summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/ABI/stable/thermal-notification4
-rw-r--r--Documentation/DocBook/80211.tmpl21
-rw-r--r--Documentation/DocBook/device-drivers.tmpl4
-rw-r--r--Documentation/DocBook/dvb/dvbapi.xml2
-rw-r--r--Documentation/DocBook/media.tmpl4
-rw-r--r--Documentation/DocBook/v4l/dev-rds.xml6
-rw-r--r--Documentation/DocBook/v4l/v4l2.xml3
-rw-r--r--Documentation/IPMI.txt27
-rw-r--r--Documentation/acpi/apei/output_format.txt122
-rw-r--r--Documentation/cgroups/memory.txt74
-rw-r--r--Documentation/feature-removal-schedule.txt19
-rw-r--r--Documentation/filesystems/Locking9
-rw-r--r--Documentation/filesystems/porting8
-rw-r--r--Documentation/filesystems/vfs.txt47
-rw-r--r--Documentation/hwmon/lm937
-rw-r--r--Documentation/kernel-parameters.txt9
-rw-r--r--Documentation/lguest/lguest.c73
-rw-r--r--Documentation/lguest/lguest.txt5
-rw-r--r--Documentation/sound/alsa/soc/codec.txt45
-rw-r--r--Documentation/sound/alsa/soc/machine.txt38
-rw-r--r--Documentation/sound/alsa/soc/platform.txt12
-rwxr-xr-xDocumentation/target/tcm_mod_builder.py1094
-rw-r--r--Documentation/target/tcm_mod_builder.txt145
-rw-r--r--Documentation/thermal/sysfs-api.txt12
-rw-r--r--Documentation/video4linux/v4l2-controls.txt12
-rw-r--r--MAINTAINERS89
-rw-r--r--Makefile4
-rw-r--r--arch/alpha/Kconfig16
-rw-r--r--arch/alpha/include/asm/io.h8
-rw-r--r--arch/alpha/kernel/Makefile4
-rw-r--r--arch/alpha/kernel/irq.c31
-rw-r--r--arch/alpha/kernel/irq_alpha.c24
-rw-r--r--arch/alpha/kernel/irq_i8259.c26
-rw-r--r--arch/alpha/kernel/irq_pyxis.c27
-rw-r--r--arch/alpha/kernel/irq_srm.c27
-rw-r--r--arch/alpha/kernel/osf_sys.c3
-rw-r--r--arch/alpha/kernel/sys_alcor.c27
-rw-r--r--arch/alpha/kernel/sys_cabriolet.c28
-rw-r--r--arch/alpha/kernel/sys_dp264.c50
-rw-r--r--arch/alpha/kernel/sys_eb64p.c27
-rw-r--r--arch/alpha/kernel/sys_eiger.c27
-rw-r--r--arch/alpha/kernel/sys_jensen.c55
-rw-r--r--arch/alpha/kernel/sys_marvel.c50
-rw-r--r--arch/alpha/kernel/sys_mikasa.c27
-rw-r--r--arch/alpha/kernel/sys_noritake.c27
-rw-r--r--arch/alpha/kernel/sys_rawhide.c27
-rw-r--r--arch/alpha/kernel/sys_rx164.c27
-rw-r--r--arch/alpha/kernel/sys_sable.c28
-rw-r--r--arch/alpha/kernel/sys_takara.c27
-rw-r--r--arch/alpha/kernel/sys_titan.c31
-rw-r--r--arch/alpha/kernel/sys_wildfire.c42
-rw-r--r--arch/alpha/lib/Makefile4
-rw-r--r--arch/alpha/math-emu/Makefile2
-rw-r--r--arch/alpha/mm/Makefile2
-rw-r--r--arch/alpha/oprofile/Makefile2
-rw-r--r--arch/arm/Kconfig23
-rw-r--r--arch/arm/common/gic.c66
-rw-r--r--arch/arm/common/it8152.c14
-rw-r--r--arch/arm/common/locomo.c24
-rw-r--r--arch/arm/common/sa1111.c96
-rw-r--r--arch/arm/common/vic.c32
-rw-r--r--arch/arm/configs/ag5evm_defconfig2
-rw-r--r--arch/arm/configs/am200epdkit_defconfig2
-rw-r--r--arch/arm/configs/at572d940hfek_defconfig2
-rw-r--r--arch/arm/configs/badge4_defconfig2
-rw-r--r--arch/arm/configs/bcmring_defconfig2
-rw-r--r--arch/arm/configs/cm_x2xx_defconfig2
-rw-r--r--arch/arm/configs/colibri_pxa270_defconfig2
-rw-r--r--arch/arm/configs/collie_defconfig2
-rw-r--r--arch/arm/configs/corgi_defconfig2
-rw-r--r--arch/arm/configs/da8xx_omapl_defconfig2
-rw-r--r--arch/arm/configs/davinci_all_defconfig2
-rw-r--r--arch/arm/configs/dove_defconfig2
-rw-r--r--arch/arm/configs/ebsa110_defconfig2
-rw-r--r--arch/arm/configs/edb7211_defconfig2
-rw-r--r--arch/arm/configs/em_x270_defconfig2
-rw-r--r--arch/arm/configs/ep93xx_defconfig2
-rw-r--r--arch/arm/configs/eseries_pxa_defconfig2
-rw-r--r--arch/arm/configs/ezx_defconfig2
-rw-r--r--arch/arm/configs/footbridge_defconfig2
-rw-r--r--arch/arm/configs/fortunet_defconfig2
-rw-r--r--arch/arm/configs/h5000_defconfig2
-rw-r--r--arch/arm/configs/imote2_defconfig2
-rw-r--r--arch/arm/configs/ixp2000_defconfig2
-rw-r--r--arch/arm/configs/ixp23xx_defconfig2
-rw-r--r--arch/arm/configs/ixp4xx_defconfig2
-rw-r--r--arch/arm/configs/loki_defconfig2
-rw-r--r--arch/arm/configs/lpd7a400_defconfig2
-rw-r--r--arch/arm/configs/lpd7a404_defconfig2
-rw-r--r--arch/arm/configs/magician_defconfig2
-rw-r--r--arch/arm/configs/mv78xx0_defconfig2
-rw-r--r--arch/arm/configs/mx1_defconfig2
-rw-r--r--arch/arm/configs/mx21_defconfig2
-rw-r--r--arch/arm/configs/mx27_defconfig2
-rw-r--r--arch/arm/configs/mx3_defconfig2
-rw-r--r--arch/arm/configs/mx51_defconfig2
-rw-r--r--arch/arm/configs/nhk8815_defconfig2
-rw-r--r--arch/arm/configs/omap1_defconfig2
-rw-r--r--arch/arm/configs/omap2plus_defconfig2
-rw-r--r--arch/arm/configs/orion5x_defconfig2
-rw-r--r--arch/arm/configs/pcm027_defconfig2
-rw-r--r--arch/arm/configs/pcontrol_g20_defconfig2
-rw-r--r--arch/arm/configs/pleb_defconfig2
-rw-r--r--arch/arm/configs/pnx4008_defconfig2
-rw-r--r--arch/arm/configs/simpad_defconfig2
-rw-r--r--arch/arm/configs/spitz_defconfig2
-rw-r--r--arch/arm/configs/stmp378x_defconfig2
-rw-r--r--arch/arm/configs/stmp37xx_defconfig2
-rw-r--r--arch/arm/configs/tct_hammer_defconfig2
-rw-r--r--arch/arm/configs/trizeps4_defconfig2
-rw-r--r--arch/arm/configs/u300_defconfig2
-rw-r--r--arch/arm/configs/viper_defconfig2
-rw-r--r--arch/arm/configs/xcep_defconfig2
-rw-r--r--arch/arm/include/asm/bitops.h2
-rw-r--r--arch/arm/include/asm/sched_clock.h2
-rw-r--r--arch/arm/kernel/ecard.c28
-rw-r--r--arch/arm/kernel/head-common.S2
-rw-r--r--arch/arm/kernel/irq.c17
-rw-r--r--arch/arm/kernel/process.c2
-rw-r--r--arch/arm/kernel/sched_clock.c9
-rw-r--r--arch/arm/kernel/setup.c22
-rw-r--r--arch/arm/kernel/smp_twd.c2
-rw-r--r--arch/arm/kernel/stacktrace.c9
-rw-r--r--arch/arm/kernel/time.c4
-rw-r--r--arch/arm/lib/delay.S4
-rw-r--r--arch/arm/mach-aaec2000/core.c18
-rw-r--r--arch/arm/mach-at91/Kconfig13
-rw-r--r--arch/arm/mach-at91/Makefile2
-rw-r--r--arch/arm/mach-at91/board-foxg20.c274
-rw-r--r--arch/arm/mach-at91/board-gsia18s.c584
-rw-r--r--arch/arm/mach-at91/board-sam9m10g45ek.c1
-rw-r--r--arch/arm/mach-at91/gpio.c34
-rw-r--r--arch/arm/mach-at91/include/mach/gsia18s.h33
-rw-r--r--arch/arm/mach-at91/irq.c36
-rw-r--r--arch/arm/mach-bcmring/irq.c42
-rw-r--r--arch/arm/mach-clps711x/irq.c40
-rw-r--r--arch/arm/mach-davinci/cp_intc.c30
-rw-r--r--arch/arm/mach-davinci/gpio.c46
-rw-r--r--arch/arm/mach-davinci/irq.c26
-rw-r--r--arch/arm/mach-dove/irq.c18
-rw-r--r--arch/arm/mach-ebsa110/core.c14
-rw-r--r--arch/arm/mach-ep93xx/gpio.c36
-rw-r--r--arch/arm/mach-footbridge/common.c14
-rw-r--r--arch/arm/mach-footbridge/isa-irq.c36
-rw-r--r--arch/arm/mach-gemini/gpio.c26
-rw-r--r--arch/arm/mach-gemini/irq.c20
-rw-r--r--arch/arm/mach-h720x/common.c38
-rw-r--r--arch/arm/mach-h720x/cpu-h7202.c14
-rw-r--r--arch/arm/mach-h720x/h7201-eval.c1
-rw-r--r--arch/arm/mach-h720x/h7202-eval.c1
-rw-r--r--arch/arm/mach-imx/Kconfig1
-rw-r--r--arch/arm/mach-imx/mach-mx27_3ds.c10
-rw-r--r--arch/arm/mach-integrator/cpu.c2
-rw-r--r--arch/arm/mach-integrator/integrator_ap.c16
-rw-r--r--arch/arm/mach-integrator/integrator_cp.c48
-rw-r--r--arch/arm/mach-iop13xx/irq.c64
-rw-r--r--arch/arm/mach-iop13xx/msi.c4
-rw-r--r--arch/arm/mach-iop32x/irq.c16
-rw-r--r--arch/arm/mach-iop33x/irq.c32
-rw-r--r--arch/arm/mach-ixp2000/core.c70
-rw-r--r--arch/arm/mach-ixp2000/ixdp2x00.c18
-rw-r--r--arch/arm/mach-ixp2000/ixdp2x01.c18
-rw-r--r--arch/arm/mach-ixp23xx/core.c55
-rw-r--r--arch/arm/mach-ixp23xx/ixdp2351.c36
-rw-r--r--arch/arm/mach-ixp4xx/common.c42
-rw-r--r--arch/arm/mach-ks8695/irq.c43
-rw-r--r--arch/arm/mach-lh7a40x/arch-kev7a400.c20
-rw-r--r--arch/arm/mach-lh7a40x/arch-lpd7a40x.c25
-rw-r--r--arch/arm/mach-lh7a40x/irq-lh7a400.c30
-rw-r--r--arch/arm/mach-lh7a40x/irq-lh7a404.c60
-rw-r--r--arch/arm/mach-lh7a40x/irq-lpd7a40x.c22
-rw-r--r--arch/arm/mach-lpc32xx/irq.c56
-rw-r--r--arch/arm/mach-mmp/include/mach/mfp-mmp2.h2
-rw-r--r--arch/arm/mach-mmp/include/mach/mfp-pxa910.h2
-rw-r--r--arch/arm/mach-mmp/irq-mmp2.c46
-rw-r--r--arch/arm/mach-mmp/irq-pxa168.c18
-rw-r--r--arch/arm/mach-msm/board-qsd8x50.c4
-rw-r--r--arch/arm/mach-msm/board-trout-gpio.c42
-rw-r--r--arch/arm/mach-msm/gpio.c48
-rw-r--r--arch/arm/mach-msm/irq-vic.c65
-rw-r--r--arch/arm/mach-msm/irq.c45
-rw-r--r--arch/arm/mach-msm/sirc.c39
-rw-r--r--arch/arm/mach-mx3/mach-mx31_3ds.c4
-rw-r--r--arch/arm/mach-mx3/mach-mx31ads.c18
-rw-r--r--arch/arm/mach-mx5/Kconfig20
-rw-r--r--arch/arm/mach-mx5/Makefile2
-rw-r--r--arch/arm/mach-mx5/board-mx51_3ds.c5
-rw-r--r--arch/arm/mach-mx5/board-mx53_evk.c74
-rw-r--r--arch/arm/mach-mx5/board-mx53_loco.c111
-rw-r--r--arch/arm/mach-mx5/board-mx53_smd.c111
-rw-r--r--arch/arm/mach-mx5/clock-mx51-mx53.c18
-rw-r--r--arch/arm/mach-mx5/devices-imx51.h8
-rw-r--r--arch/arm/mach-mx5/devices-imx53.h18
-rw-r--r--arch/arm/mach-mx5/devices.c19
-rw-r--r--arch/arm/mach-mx5/devices.h1
-rw-r--r--arch/arm/mach-mx5/eukrea_mbimx51-baseboard.c5
-rw-r--r--arch/arm/mach-mxs/Kconfig4
-rw-r--r--arch/arm/mach-mxs/clock-mx23.c13
-rw-r--r--arch/arm/mach-mxs/clock-mx28.c14
-rw-r--r--arch/arm/mach-mxs/devices-mx23.h4
-rw-r--r--arch/arm/mach-mxs/devices-mx28.h4
-rw-r--r--arch/arm/mach-mxs/devices.c17
-rw-r--r--arch/arm/mach-mxs/devices/Kconfig3
-rw-r--r--arch/arm/mach-mxs/devices/Makefile2
-rw-r--r--arch/arm/mach-mxs/devices/amba-duart.c40
-rw-r--r--arch/arm/mach-mxs/devices/platform-duart.c48
-rw-r--r--arch/arm/mach-mxs/devices/platform-fec.c2
-rw-r--r--arch/arm/mach-mxs/include/mach/devices-common.h11
-rw-r--r--arch/arm/mach-mxs/mach-mx28evk.c26
-rw-r--r--arch/arm/mach-netx/generic.c30
-rw-r--r--arch/arm/mach-ns9xxx/board-a9m9750dev.c28
-rw-r--r--arch/arm/mach-ns9xxx/irq.c28
-rw-r--r--arch/arm/mach-nuc93x/irq.c16
-rw-r--r--arch/arm/mach-omap1/Kconfig2
-rw-r--r--arch/arm/mach-omap1/Makefile3
-rw-r--r--arch/arm/mach-omap1/ams-delta-fiq.c8
-rw-r--r--arch/arm/mach-omap1/board-ams-delta.c17
-rw-r--r--arch/arm/mach-omap1/fpga.c28
-rw-r--r--arch/arm/mach-omap1/irq.c44
-rw-r--r--arch/arm/mach-omap1/time.c101
-rw-r--r--arch/arm/mach-omap1/timer32k.c13
-rw-r--r--arch/arm/mach-omap2/board-4430sdp.c10
-rw-r--r--arch/arm/mach-omap2/board-cm-t3517.c29
-rw-r--r--arch/arm/mach-omap2/board-devkit8000.c3
-rw-r--r--arch/arm/mach-omap2/board-igep0020.c33
-rw-r--r--arch/arm/mach-omap2/board-igep0030.c85
-rw-r--r--arch/arm/mach-omap2/board-omap3beagle.c60
-rw-r--r--arch/arm/mach-omap2/board-omap4panda.c10
-rw-r--r--arch/arm/mach-omap2/board-zoom-peripherals.c4
-rw-r--r--arch/arm/mach-omap2/clock3xxx_data.c2
-rw-r--r--arch/arm/mach-omap2/clock44xx_data.c1
-rw-r--r--arch/arm/mach-omap2/clockdomain.c30
-rw-r--r--arch/arm/mach-omap2/clockdomain.h2
-rw-r--r--arch/arm/mach-omap2/clockdomains44xx_data.c2
-rw-r--r--arch/arm/mach-omap2/cpuidle34xx.c2
-rw-r--r--arch/arm/mach-omap2/devices.c2
-rw-r--r--arch/arm/mach-omap2/irq.c22
-rw-r--r--arch/arm/mach-omap2/mux.c2
-rw-r--r--arch/arm/mach-omap2/mux34xx.c4
-rw-r--r--arch/arm/mach-omap2/mux44xx.c6
-rw-r--r--arch/arm/mach-omap2/omap_twl.c10
-rw-r--r--arch/arm/mach-omap2/pm_bus.c4
-rw-r--r--arch/arm/mach-omap2/powerdomain2xxx_3xxx.c1
-rw-r--r--arch/arm/mach-omap2/prm2xxx_3xxx.h63
-rw-r--r--arch/arm/mach-omap2/sr_device.c1
-rw-r--r--arch/arm/mach-omap2/timer-gp.c10
-rw-r--r--arch/arm/mach-omap2/wd_timer.c2
-rw-r--r--arch/arm/mach-pnx4008/irq.c62
-rw-r--r--arch/arm/mach-pxa/balloon3.c23
-rw-r--r--arch/arm/mach-pxa/clock-pxa3xx.c1
-rw-r--r--arch/arm/mach-pxa/cm-x2xx-pci.c2
-rw-r--r--arch/arm/mach-pxa/generic.c1
-rw-r--r--arch/arm/mach-pxa/generic.h4
-rw-r--r--arch/arm/mach-pxa/irq.c83
-rw-r--r--arch/arm/mach-pxa/lpd270.c17
-rw-r--r--arch/arm/mach-pxa/lubbock.c17
-rw-r--r--arch/arm/mach-pxa/mainstone.c17
-rw-r--r--arch/arm/mach-pxa/pcm990-baseboard.c15
-rw-r--r--arch/arm/mach-pxa/pxa25x.c7
-rw-r--r--arch/arm/mach-pxa/pxa27x.c9
-rw-r--r--arch/arm/mach-pxa/pxa3xx.c36
-rw-r--r--arch/arm/mach-pxa/spitz.c1
-rw-r--r--arch/arm/mach-pxa/viper.c22
-rw-r--r--arch/arm/mach-pxa/zeus.c26
-rw-r--r--arch/arm/mach-rpc/irq.c60
-rw-r--r--arch/arm/mach-s3c2410/bast-irq.c22
-rw-r--r--arch/arm/mach-s3c2410/include/mach/irqs.h4
-rw-r--r--arch/arm/mach-s3c2410/include/mach/map.h4
-rw-r--r--arch/arm/mach-s3c2410/include/mach/regs-s3c2443-clock.h1
-rw-r--r--arch/arm/mach-s3c2412/irq.c50
-rw-r--r--arch/arm/mach-s3c2416/Kconfig12
-rw-r--r--arch/arm/mach-s3c2416/Makefile4
-rw-r--r--arch/arm/mach-s3c2416/clock.c18
-rw-r--r--arch/arm/mach-s3c2416/irq.c76
-rw-r--r--arch/arm/mach-s3c2416/mach-smdk2416.c23
-rw-r--r--arch/arm/mach-s3c2416/s3c2416.c5
-rw-r--r--arch/arm/mach-s3c2416/setup-sdhci-gpio.c34
-rw-r--r--arch/arm/mach-s3c2416/setup-sdhci.c61
-rw-r--r--arch/arm/mach-s3c2440/irq.c18
-rw-r--r--arch/arm/mach-s3c2440/s3c244x-irq.c18
-rw-r--r--arch/arm/mach-s3c2443/Kconfig3
-rw-r--r--arch/arm/mach-s3c2443/clock.c4
-rw-r--r--arch/arm/mach-s3c2443/irq.c95
-rw-r--r--arch/arm/mach-s3c2443/mach-smdk2443.c9
-rw-r--r--arch/arm/mach-s3c2443/s3c2443.c7
-rw-r--r--arch/arm/mach-s3c64xx/clock.c19
-rw-r--r--arch/arm/mach-s3c64xx/dma.c1
-rw-r--r--arch/arm/mach-s3c64xx/irq-eint.c37
-rw-r--r--arch/arm/mach-s5p6442/clock.c16
-rw-r--r--arch/arm/mach-s5p6442/include/mach/map.h3
-rw-r--r--arch/arm/mach-s5p6442/mach-smdk6442.c11
-rw-r--r--arch/arm/mach-s5p6442/setup-i2c0.c5
-rw-r--r--arch/arm/mach-s5p64x0/Makefile4
-rw-r--r--arch/arm/mach-s5p64x0/clock-s5p6440.c22
-rw-r--r--arch/arm/mach-s5p64x0/clock-s5p6450.c34
-rw-r--r--arch/arm/mach-s5p64x0/dev-audio.c123
-rw-r--r--arch/arm/mach-s5p64x0/gpiolib.c (renamed from arch/arm/mach-s5p64x0/gpio.c)221
-rw-r--r--arch/arm/mach-s5p64x0/include/mach/map.h5
-rw-r--r--arch/arm/mach-s5p64x0/include/mach/regs-gpio.h57
-rw-r--r--arch/arm/mach-s5p64x0/mach-smdk6440.c2
-rw-r--r--arch/arm/mach-s5p64x0/mach-smdk6450.c2
-rw-r--r--arch/arm/mach-s5pc100/clock.c16
-rw-r--r--arch/arm/mach-s5pc100/include/mach/map.h2
-rw-r--r--arch/arm/mach-s5pv210/Kconfig2
-rw-r--r--arch/arm/mach-s5pv210/clock.c25
-rw-r--r--arch/arm/mach-s5pv210/cpu.c5
-rw-r--r--arch/arm/mach-s5pv210/include/mach/irqs.h3
-rw-r--r--arch/arm/mach-s5pv210/include/mach/map.h6
-rw-r--r--arch/arm/mach-s5pv210/include/mach/regs-clock.h5
-rw-r--r--arch/arm/mach-s5pv210/mach-smdkc110.c2
-rw-r--r--arch/arm/mach-s5pv210/mach-smdkv210.c140
-rw-r--r--arch/arm/mach-s5pv310/Kconfig21
-rw-r--r--arch/arm/mach-s5pv310/Makefile6
-rw-r--r--arch/arm/mach-s5pv310/clock.c77
-rw-r--r--arch/arm/mach-s5pv310/cpu.c21
-rw-r--r--arch/arm/mach-s5pv310/cpufreq.c580
-rw-r--r--arch/arm/mach-s5pv310/dev-pd.c139
-rw-r--r--arch/arm/mach-s5pv310/dev-sysmmu.c187
-rw-r--r--arch/arm/mach-s5pv310/hotplug.c4
-rw-r--r--arch/arm/mach-s5pv310/include/mach/irqs.h34
-rw-r--r--arch/arm/mach-s5pv310/include/mach/map.h29
-rw-r--r--arch/arm/mach-s5pv310/include/mach/regs-clock.h80
-rw-r--r--arch/arm/mach-s5pv310/include/mach/regs-mem.h23
-rw-r--r--arch/arm/mach-s5pv310/include/mach/regs-pmu.h30
-rw-r--r--arch/arm/mach-s5pv310/include/mach/regs-srom.h50
-rw-r--r--arch/arm/mach-s5pv310/include/mach/regs-sysmmu.h24
-rw-r--r--arch/arm/mach-s5pv310/include/mach/sysmmu.h119
-rw-r--r--arch/arm/mach-s5pv310/irq-combiner.c32
-rw-r--r--arch/arm/mach-s5pv310/irq-eint.c55
-rw-r--r--arch/arm/mach-s5pv310/mach-smdkc210.c53
-rw-r--r--arch/arm/mach-s5pv310/mach-smdkv310.c53
-rw-r--r--arch/arm/mach-s5pv310/mach-universal_c210.c80
-rw-r--r--arch/arm/mach-sa1100/generic.c1
-rw-r--r--arch/arm/mach-sa1100/irq.c84
-rw-r--r--arch/arm/mach-sa1100/neponset.c8
-rw-r--r--arch/arm/mach-shark/irq.c26
-rw-r--r--arch/arm/mach-stmp378x/stmp378x.c16
-rw-r--r--arch/arm/mach-stmp37xx/stmp37xx.c24
-rw-r--r--arch/arm/mach-tcc8k/irq.c56
-rw-r--r--arch/arm/mach-tegra/gpio.c38
-rw-r--r--arch/arm/mach-tegra/hotplug.c4
-rw-r--r--arch/arm/mach-tegra/irq.c36
-rw-r--r--arch/arm/mach-versatile/core.c18
-rw-r--r--arch/arm/mach-w90x900/irq.c20
-rw-r--r--arch/arm/mm/Kconfig2
-rw-r--r--arch/arm/mm/dma-mapping.c2
-rw-r--r--arch/arm/mm/proc-v7.S4
-rw-r--r--arch/arm/plat-mxc/3ds_debugboard.c28
-rw-r--r--arch/arm/plat-mxc/avic.c14
-rw-r--r--arch/arm/plat-mxc/devices/Kconfig2
-rw-r--r--arch/arm/plat-mxc/devices/platform-fec.c5
-rw-r--r--arch/arm/plat-mxc/devices/platform-imx-i2c.c9
-rw-r--r--arch/arm/plat-mxc/devices/platform-imx-keypad.c5
-rw-r--r--arch/arm/plat-mxc/devices/platform-mxc_pwm.c9
-rw-r--r--arch/arm/plat-mxc/devices/platform-sdhci-esdhc-imx.c12
-rw-r--r--arch/arm/plat-mxc/devices/platform-spi_imx.c12
-rw-r--r--arch/arm/plat-mxc/gpio.c30
-rw-r--r--arch/arm/plat-mxc/include/mach/iomux-mx53.h4
-rw-r--r--arch/arm/plat-mxc/include/mach/iomux-v3.h1
-rw-r--r--arch/arm/plat-mxc/include/mach/mx51.h6
-rw-r--r--arch/arm/plat-mxc/include/mach/mx53.h28
-rw-r--r--arch/arm/plat-mxc/pwm.c2
-rw-r--r--arch/arm/plat-mxc/tzic.c38
-rw-r--r--arch/arm/plat-nomadik/gpio.c56
-rw-r--r--arch/arm/plat-nomadik/include/plat/ste_dma40.h8
-rw-r--r--arch/arm/plat-omap/Kconfig8
-rw-r--r--arch/arm/plat-omap/counter_32k.c22
-rw-r--r--arch/arm/plat-omap/dma.c7
-rw-r--r--arch/arm/plat-omap/gpio.c101
-rw-r--r--arch/arm/plat-omap/include/plat/common.h3
-rw-r--r--arch/arm/plat-omap/include/plat/onenand.h1
-rw-r--r--arch/arm/plat-omap/include/plat/voltage.h17
-rw-r--r--arch/arm/plat-orion/gpio.c37
-rw-r--r--arch/arm/plat-orion/irq.c18
-rw-r--r--arch/arm/plat-pxa/gpio.c28
-rw-r--r--arch/arm/plat-pxa/include/plat/gpio.h4
-rw-r--r--arch/arm/plat-s3c24xx/devs.c1
-rw-r--r--arch/arm/plat-s3c24xx/include/plat/irq.h4
-rw-r--r--arch/arm/plat-s3c24xx/irq-pm.c9
-rw-r--r--arch/arm/plat-s3c24xx/irq.c182
-rw-r--r--arch/arm/plat-s3c24xx/s3c2443-clock.c2
-rw-r--r--arch/arm/plat-s5p/Kconfig26
-rw-r--r--arch/arm/plat-s5p/Makefile3
-rw-r--r--arch/arm/plat-s5p/cpu.c5
-rw-r--r--arch/arm/plat-s5p/dev-csis0.c34
-rw-r--r--arch/arm/plat-s5p/dev-csis1.c34
-rw-r--r--arch/arm/plat-s5p/include/plat/csis.h28
-rw-r--r--arch/arm/plat-s5p/include/plat/map-s5p.h1
-rw-r--r--arch/arm/plat-s5p/include/plat/regs-srom.h54
-rw-r--r--arch/arm/plat-s5p/include/plat/sysmmu.h23
-rw-r--r--arch/arm/plat-s5p/irq-eint.c86
-rw-r--r--arch/arm/plat-s5p/irq-gpioint.c50
-rw-r--r--arch/arm/plat-s5p/irq-pm.c6
-rw-r--r--arch/arm/plat-s5p/sysmmu.c328
-rw-r--r--arch/arm/plat-samsung/Kconfig14
-rw-r--r--arch/arm/plat-samsung/Makefile4
-rw-r--r--arch/arm/plat-samsung/clock.c92
-rw-r--r--arch/arm/plat-samsung/dev-nand.c2
-rw-r--r--arch/arm/plat-samsung/gpio-config.c42
-rw-r--r--arch/arm/plat-samsung/gpiolib.c7
-rw-r--r--arch/arm/plat-samsung/include/plat/clock.h3
-rw-r--r--arch/arm/plat-samsung/include/plat/devs.h8
-rw-r--r--arch/arm/plat-samsung/include/plat/gpio-cfg-helpers.h2
-rw-r--r--arch/arm/plat-samsung/include/plat/gpio-core.h2
-rw-r--r--arch/arm/plat-samsung/include/plat/pd.h30
-rw-r--r--arch/arm/plat-samsung/include/plat/pm.h4
-rw-r--r--arch/arm/plat-samsung/include/plat/sdhci.h35
-rw-r--r--arch/arm/plat-samsung/irq-uart.c40
-rw-r--r--arch/arm/plat-samsung/irq-vic-timer.c26
-rw-r--r--arch/arm/plat-samsung/pd.c95
-rw-r--r--arch/arm/plat-samsung/pm.c6
-rw-r--r--arch/arm/plat-spear/shirq.c22
-rw-r--r--arch/arm/plat-stmp3xxx/irq.c2
-rw-r--r--arch/arm/plat-stmp3xxx/pinmux.c32
-rw-r--r--arch/avr32/Kconfig4
-rw-r--r--arch/blackfin/Kconfig17
-rw-r--r--arch/blackfin/configs/BF518F-EZBRD_defconfig2
-rw-r--r--arch/blackfin/configs/BF526-EZBRD_defconfig2
-rw-r--r--arch/blackfin/configs/BF527-AD7160-EVAL_defconfig2
-rw-r--r--arch/blackfin/configs/BF527-EZKIT-V2_defconfig2
-rw-r--r--arch/blackfin/configs/BF527-EZKIT_defconfig2
-rw-r--r--arch/blackfin/configs/BF527-TLL6527M_defconfig2
-rw-r--r--arch/blackfin/configs/BF533-EZKIT_defconfig2
-rw-r--r--arch/blackfin/configs/BF533-STAMP_defconfig2
-rw-r--r--arch/blackfin/configs/BF537-STAMP_defconfig2
-rw-r--r--arch/blackfin/configs/BF538-EZKIT_defconfig2
-rw-r--r--arch/blackfin/configs/BF548-EZKIT_defconfig2
-rw-r--r--arch/blackfin/configs/BF561-ACVILON_defconfig2
-rw-r--r--arch/blackfin/configs/BF561-EZKIT-SMP_defconfig2
-rw-r--r--arch/blackfin/configs/BF561-EZKIT_defconfig2
-rw-r--r--arch/blackfin/configs/BlackStamp_defconfig2
-rw-r--r--arch/blackfin/configs/CM-BF527_defconfig2
-rw-r--r--arch/blackfin/configs/CM-BF533_defconfig2
-rw-r--r--arch/blackfin/configs/CM-BF537E_defconfig2
-rw-r--r--arch/blackfin/configs/CM-BF537U_defconfig2
-rw-r--r--arch/blackfin/configs/CM-BF548_defconfig2
-rw-r--r--arch/blackfin/configs/CM-BF561_defconfig2
-rw-r--r--arch/blackfin/configs/DNP5370_defconfig2
-rw-r--r--arch/blackfin/configs/H8606_defconfig2
-rw-r--r--arch/blackfin/configs/IP0X_defconfig2
-rw-r--r--arch/blackfin/configs/PNAV-10_defconfig2
-rw-r--r--arch/blackfin/configs/SRV1_defconfig2
-rw-r--r--arch/blackfin/configs/TCM-BF518_defconfig2
-rw-r--r--arch/blackfin/configs/TCM-BF537_defconfig2
-rw-r--r--arch/cris/Kconfig6
-rw-r--r--arch/cris/arch-v10/kernel/irq.c41
-rw-r--r--arch/cris/arch-v32/kernel/irq.c50
-rw-r--r--arch/cris/configs/artpec_3_defconfig2
-rw-r--r--arch/cris/configs/etrax-100lx_v2_defconfig2
-rw-r--r--arch/cris/configs/etraxfs_defconfig2
-rw-r--r--arch/cris/kernel/irq.c6
-rw-r--r--arch/frv/Kconfig9
-rw-r--r--arch/frv/defconfig2
-rw-r--r--arch/h8300/Kconfig6
-rw-r--r--arch/h8300/defconfig2
-rw-r--r--arch/h8300/kernel/irq.c50
-rw-r--r--arch/ia64/Kconfig26
-rw-r--r--arch/ia64/include/asm/io.h5
-rw-r--r--arch/ia64/include/asm/page.h1
-rw-r--r--arch/ia64/include/asm/processor.h5
-rw-r--r--arch/ia64/kernel/process.c6
-rw-r--r--arch/m32r/Kconfig11
-rw-r--r--arch/m32r/configs/m32700ut.smp_defconfig2
-rw-r--r--arch/m32r/configs/m32700ut.up_defconfig2
-rw-r--r--arch/m32r/configs/mappi.nommu_defconfig2
-rw-r--r--arch/m32r/configs/mappi.smp_defconfig2
-rw-r--r--arch/m32r/configs/mappi.up_defconfig2
-rw-r--r--arch/m32r/configs/mappi2.opsp_defconfig2
-rw-r--r--arch/m32r/configs/mappi2.vdec2_defconfig2
-rw-r--r--arch/m32r/configs/mappi3.smp_defconfig2
-rw-r--r--arch/m32r/configs/oaks32r_defconfig2
-rw-r--r--arch/m32r/configs/opsput_defconfig2
-rw-r--r--arch/m32r/configs/usrv_defconfig2
-rw-r--r--arch/m32r/kernel/irq.c10
-rw-r--r--arch/m32r/platforms/m32104ut/setup.c58
-rw-r--r--arch/m32r/platforms/m32700ut/setup.c214
-rw-r--r--arch/m32r/platforms/mappi/setup.c78
-rw-r--r--arch/m32r/platforms/mappi2/setup.c89
-rw-r--r--arch/m32r/platforms/mappi3/setup.c92
-rw-r--r--arch/m32r/platforms/oaks32r/setup.c65
-rw-r--r--arch/m32r/platforms/opsput/setup.c220
-rw-r--r--arch/m32r/platforms/usrv/setup.c115
-rw-r--r--arch/m68k/include/asm/cacheflush_no.h95
-rw-r--r--arch/m68k/include/asm/coldfire.h2
-rw-r--r--arch/m68k/include/asm/entry_no.h59
-rw-r--r--arch/m68k/include/asm/gpio.h2
-rw-r--r--arch/m68k/include/asm/io_no.h1
-rw-r--r--arch/m68k/include/asm/m5206sim.h14
-rw-r--r--arch/m68k/include/asm/m520xsim.h17
-rw-r--r--arch/m68k/include/asm/m523xsim.h11
-rw-r--r--arch/m68k/include/asm/m5249sim.h10
-rw-r--r--arch/m68k/include/asm/m5272sim.h8
-rw-r--r--arch/m68k/include/asm/m527xsim.h10
-rw-r--r--arch/m68k/include/asm/m528xsim.h11
-rw-r--r--arch/m68k/include/asm/m52xxacr.h94
-rw-r--r--arch/m68k/include/asm/m5307sim.h43
-rw-r--r--arch/m68k/include/asm/m532xsim.h33
-rw-r--r--arch/m68k/include/asm/m53xxacr.h101
-rw-r--r--arch/m68k/include/asm/m5407sim.h42
-rw-r--r--arch/m68k/include/asm/m54xxacr.h97
-rw-r--r--arch/m68k/include/asm/m54xxgpt.h (renamed from arch/m68k/include/asm/m548xgpt.h)10
-rw-r--r--arch/m68k/include/asm/m54xxsim.h (renamed from arch/m68k/include/asm/m548xsim.h)23
-rw-r--r--arch/m68k/include/asm/mcfcache.h150
-rw-r--r--arch/m68k/include/asm/mcfsim.h4
-rw-r--r--arch/m68k/include/asm/mcfuart.h45
-rw-r--r--arch/m68k/include/asm/processor.h13
-rw-r--r--arch/m68knommu/Kconfig107
-rw-r--r--arch/m68knommu/Makefile14
-rw-r--r--arch/m68knommu/configs/m5208evb_defconfig2
-rw-r--r--arch/m68knommu/configs/m5249evb_defconfig2
-rw-r--r--arch/m68knommu/configs/m5272c3_defconfig2
-rw-r--r--arch/m68knommu/configs/m5275evb_defconfig2
-rw-r--r--arch/m68knommu/configs/m5307c3_defconfig2
-rw-r--r--arch/m68knommu/configs/m5407c3_defconfig2
-rw-r--r--arch/m68knommu/defconfig2
-rw-r--r--arch/m68knommu/kernel/setup.c72
-rw-r--r--arch/m68knommu/mm/Makefile2
-rw-r--r--arch/m68knommu/mm/fault.c57
-rw-r--r--arch/m68knommu/mm/kmap.c9
-rw-r--r--arch/m68knommu/mm/memory.c33
-rw-r--r--arch/m68knommu/platform/54xx/Makefile (renamed from arch/m68knommu/platform/548x/Makefile)0
-rw-r--r--arch/m68knommu/platform/54xx/config.c (renamed from arch/m68knommu/platform/548x/config.c)32
-rw-r--r--arch/m68knommu/platform/68328/ints.c4
-rw-r--r--arch/m68knommu/platform/coldfire/Makefile4
-rw-r--r--arch/m68knommu/platform/coldfire/cache.c48
-rw-r--r--arch/m68knommu/platform/coldfire/entry.S56
-rw-r--r--arch/m68knommu/platform/coldfire/head.S26
-rw-r--r--arch/microblaze/Kconfig11
-rw-r--r--arch/microblaze/configs/mmu_defconfig2
-rw-r--r--arch/microblaze/configs/nommu_defconfig2
-rw-r--r--arch/microblaze/include/asm/pgtable.h6
-rw-r--r--arch/microblaze/include/asm/tlb.h1
-rw-r--r--arch/microblaze/kernel/prom.c4
-rw-r--r--arch/mips/Kbuild.platforms1
-rw-r--r--arch/mips/Kconfig40
-rw-r--r--arch/mips/Kconfig.debug2
-rw-r--r--arch/mips/ath79/Kconfig50
-rw-r--r--arch/mips/ath79/Makefile28
-rw-r--r--arch/mips/ath79/Platform7
-rw-r--r--arch/mips/ath79/clock.c183
-rw-r--r--arch/mips/ath79/common.c97
-rw-r--r--arch/mips/ath79/common.h31
-rw-r--r--arch/mips/ath79/dev-ar913x-wmac.c60
-rw-r--r--arch/mips/ath79/dev-ar913x-wmac.h17
-rw-r--r--arch/mips/ath79/dev-common.c77
-rw-r--r--arch/mips/ath79/dev-common.h18
-rw-r--r--arch/mips/ath79/dev-gpio-buttons.c58
-rw-r--r--arch/mips/ath79/dev-gpio-buttons.h23
-rw-r--r--arch/mips/ath79/dev-leds-gpio.c56
-rw-r--r--arch/mips/ath79/dev-leds-gpio.h21
-rw-r--r--arch/mips/ath79/dev-spi.c38
-rw-r--r--arch/mips/ath79/dev-spi.h22
-rw-r--r--arch/mips/ath79/early_printk.c36
-rw-r--r--arch/mips/ath79/gpio.c197
-rw-r--r--arch/mips/ath79/irq.c187
-rw-r--r--arch/mips/ath79/mach-ap81.c98
-rw-r--r--arch/mips/ath79/mach-pb44.c118
-rw-r--r--arch/mips/ath79/machtypes.h23
-rw-r--r--arch/mips/ath79/prom.c57
-rw-r--r--arch/mips/ath79/setup.c206
-rw-r--r--arch/mips/configs/ar7_defconfig2
-rw-r--r--arch/mips/configs/bcm47xx_defconfig2
-rw-r--r--arch/mips/configs/bcm63xx_defconfig2
-rw-r--r--arch/mips/configs/bigsur_defconfig2
-rw-r--r--arch/mips/configs/capcella_defconfig2
-rw-r--r--arch/mips/configs/cavium-octeon_defconfig2
-rw-r--r--arch/mips/configs/cobalt_defconfig2
-rw-r--r--arch/mips/configs/db1000_defconfig2
-rw-r--r--arch/mips/configs/db1100_defconfig2
-rw-r--r--arch/mips/configs/db1200_defconfig2
-rw-r--r--arch/mips/configs/db1500_defconfig2
-rw-r--r--arch/mips/configs/db1550_defconfig2
-rw-r--r--arch/mips/configs/decstation_defconfig2
-rw-r--r--arch/mips/configs/e55_defconfig2
-rw-r--r--arch/mips/configs/fuloong2e_defconfig2
-rw-r--r--arch/mips/configs/gpr_defconfig2
-rw-r--r--arch/mips/configs/ip22_defconfig2
-rw-r--r--arch/mips/configs/ip27_defconfig2
-rw-r--r--arch/mips/configs/ip28_defconfig2
-rw-r--r--arch/mips/configs/ip32_defconfig2
-rw-r--r--arch/mips/configs/jazz_defconfig2
-rw-r--r--arch/mips/configs/jmr3927_defconfig2
-rw-r--r--arch/mips/configs/lasat_defconfig2
-rw-r--r--arch/mips/configs/lemote2f_defconfig2
-rw-r--r--arch/mips/configs/malta_defconfig5
-rw-r--r--arch/mips/configs/markeins_defconfig2
-rw-r--r--arch/mips/configs/mipssim_defconfig2
-rw-r--r--arch/mips/configs/mpc30x_defconfig2
-rw-r--r--arch/mips/configs/msp71xx_defconfig2
-rw-r--r--arch/mips/configs/mtx1_defconfig2
-rw-r--r--arch/mips/configs/pb1100_defconfig2
-rw-r--r--arch/mips/configs/pb1200_defconfig2
-rw-r--r--arch/mips/configs/pb1500_defconfig2
-rw-r--r--arch/mips/configs/pb1550_defconfig2
-rw-r--r--arch/mips/configs/pnx8335-stb225_defconfig2
-rw-r--r--arch/mips/configs/pnx8550-jbs_defconfig2
-rw-r--r--arch/mips/configs/pnx8550-stb810_defconfig2
-rw-r--r--arch/mips/configs/powertv_defconfig2
-rw-r--r--arch/mips/configs/rb532_defconfig2
-rw-r--r--arch/mips/configs/rbtx49xx_defconfig2
-rw-r--r--arch/mips/configs/rm200_defconfig2
-rw-r--r--arch/mips/configs/sb1250-swarm_defconfig2
-rw-r--r--arch/mips/configs/tb0219_defconfig2
-rw-r--r--arch/mips/configs/tb0226_defconfig2
-rw-r--r--arch/mips/configs/tb0287_defconfig2
-rw-r--r--arch/mips/configs/workpad_defconfig2
-rw-r--r--arch/mips/configs/wrppmc_defconfig2
-rw-r--r--arch/mips/configs/yosemite_defconfig2
-rw-r--r--arch/mips/include/asm/cache.h2
-rw-r--r--arch/mips/include/asm/cpu-info.h1
-rw-r--r--arch/mips/include/asm/inst.h14
-rw-r--r--arch/mips/include/asm/jump_label.h48
-rw-r--r--arch/mips/include/asm/mach-ath79/ar71xx_regs.h233
-rw-r--r--arch/mips/include/asm/mach-ath79/ath79.h96
-rw-r--r--arch/mips/include/asm/mach-ath79/ath79_spi_platform.h23
-rw-r--r--arch/mips/include/asm/mach-ath79/cpu-feature-overrides.h56
-rw-r--r--arch/mips/include/asm/mach-ath79/gpio.h26
-rw-r--r--arch/mips/include/asm/mach-ath79/irq.h36
-rw-r--r--arch/mips/include/asm/mach-ath79/kernel-entry-init.h32
-rw-r--r--arch/mips/include/asm/mach-ath79/war.h25
-rw-r--r--arch/mips/include/asm/mips_machine.h54
-rw-r--r--arch/mips/include/asm/mmu_context.h8
-rw-r--r--arch/mips/include/asm/uasm.h7
-rw-r--r--arch/mips/kernel/Makefile3
-rw-r--r--arch/mips/kernel/cpu-probe.c2
-rw-r--r--arch/mips/kernel/jump_label.c54
-rw-r--r--arch/mips/kernel/mips_machine.c86
-rw-r--r--arch/mips/kernel/module.c5
-rw-r--r--arch/mips/kernel/proc.c9
-rw-r--r--arch/mips/kernel/prom.c6
-rw-r--r--arch/mips/kernel/setup.c2
-rw-r--r--arch/mips/kernel/traps.c2
-rw-r--r--arch/mips/kernel/vmlinux.lds.S7
-rw-r--r--arch/mips/mm/tlbex.c590
-rw-r--r--arch/mips/mm/uasm.c56
-rw-r--r--arch/mips/sibyte/common/sb_tbprof.c3
-rw-r--r--arch/mips/txx9/generic/pci.c7
-rw-r--r--arch/mn10300/Kconfig8
-rw-r--r--arch/mn10300/configs/asb2303_defconfig2
-rw-r--r--arch/mn10300/configs/asb2364_defconfig2
-rw-r--r--arch/parisc/Kconfig18
-rw-r--r--arch/parisc/configs/a500_defconfig2
-rw-r--r--arch/parisc/configs/c3000_defconfig2
-rw-r--r--arch/parisc/include/asm/pgtable.h4
-rw-r--r--arch/parisc/kernel/firmware.c13
-rw-r--r--arch/powerpc/Kconfig28
-rw-r--r--arch/powerpc/boot/Makefile2
-rw-r--r--arch/powerpc/boot/dts/mpc8308rdb.dts2
-rw-r--r--arch/powerpc/boot/dts/p1022ds.dts4
-rw-r--r--arch/powerpc/configs/40x/acadia_defconfig2
-rw-r--r--arch/powerpc/configs/40x/ep405_defconfig2
-rw-r--r--arch/powerpc/configs/40x/hcu4_defconfig2
-rw-r--r--arch/powerpc/configs/40x/kilauea_defconfig2
-rw-r--r--arch/powerpc/configs/40x/makalu_defconfig2
-rw-r--r--arch/powerpc/configs/40x/walnut_defconfig2
-rw-r--r--arch/powerpc/configs/44x/arches_defconfig2
-rw-r--r--arch/powerpc/configs/44x/bamboo_defconfig2
-rw-r--r--arch/powerpc/configs/44x/bluestone_defconfig2
-rw-r--r--arch/powerpc/configs/44x/canyonlands_defconfig2
-rw-r--r--arch/powerpc/configs/44x/ebony_defconfig2
-rw-r--r--arch/powerpc/configs/44x/eiger_defconfig2
-rw-r--r--arch/powerpc/configs/44x/icon_defconfig2
-rw-r--r--arch/powerpc/configs/44x/iss476-smp_defconfig2
-rw-r--r--arch/powerpc/configs/44x/katmai_defconfig2
-rw-r--r--arch/powerpc/configs/44x/rainier_defconfig2
-rw-r--r--arch/powerpc/configs/44x/redwood_defconfig2
-rw-r--r--arch/powerpc/configs/44x/sam440ep_defconfig2
-rw-r--r--arch/powerpc/configs/44x/sequoia_defconfig2
-rw-r--r--arch/powerpc/configs/44x/taishan_defconfig2
-rw-r--r--arch/powerpc/configs/44x/warp_defconfig2
-rw-r--r--arch/powerpc/configs/52xx/cm5200_defconfig2
-rw-r--r--arch/powerpc/configs/52xx/lite5200b_defconfig2
-rw-r--r--arch/powerpc/configs/52xx/motionpro_defconfig2
-rw-r--r--arch/powerpc/configs/52xx/pcm030_defconfig2
-rw-r--r--arch/powerpc/configs/52xx/tqm5200_defconfig2
-rw-r--r--arch/powerpc/configs/83xx/asp8347_defconfig2
-rw-r--r--arch/powerpc/configs/83xx/kmeter1_defconfig2
-rw-r--r--arch/powerpc/configs/83xx/mpc8313_rdb_defconfig2
-rw-r--r--arch/powerpc/configs/83xx/mpc8315_rdb_defconfig2
-rw-r--r--arch/powerpc/configs/83xx/mpc832x_mds_defconfig2
-rw-r--r--arch/powerpc/configs/83xx/mpc832x_rdb_defconfig2
-rw-r--r--arch/powerpc/configs/83xx/mpc834x_itx_defconfig2
-rw-r--r--arch/powerpc/configs/83xx/mpc834x_itxgp_defconfig2
-rw-r--r--arch/powerpc/configs/83xx/mpc834x_mds_defconfig2
-rw-r--r--arch/powerpc/configs/83xx/mpc836x_mds_defconfig2
-rw-r--r--arch/powerpc/configs/83xx/mpc836x_rdk_defconfig2
-rw-r--r--arch/powerpc/configs/83xx/mpc837x_mds_defconfig2
-rw-r--r--arch/powerpc/configs/83xx/mpc837x_rdb_defconfig2
-rw-r--r--arch/powerpc/configs/83xx/sbc834x_defconfig2
-rw-r--r--arch/powerpc/configs/85xx/ksi8560_defconfig2
-rw-r--r--arch/powerpc/configs/85xx/mpc8540_ads_defconfig2
-rw-r--r--arch/powerpc/configs/85xx/mpc8560_ads_defconfig2
-rw-r--r--arch/powerpc/configs/85xx/mpc85xx_cds_defconfig2
-rw-r--r--arch/powerpc/configs/85xx/sbc8548_defconfig2
-rw-r--r--arch/powerpc/configs/85xx/sbc8560_defconfig2
-rw-r--r--arch/powerpc/configs/85xx/socrates_defconfig2
-rw-r--r--arch/powerpc/configs/85xx/stx_gp3_defconfig2
-rw-r--r--arch/powerpc/configs/85xx/tqm8540_defconfig2
-rw-r--r--arch/powerpc/configs/85xx/tqm8541_defconfig2
-rw-r--r--arch/powerpc/configs/85xx/tqm8548_defconfig2
-rw-r--r--arch/powerpc/configs/85xx/tqm8555_defconfig2
-rw-r--r--arch/powerpc/configs/85xx/tqm8560_defconfig2
-rw-r--r--arch/powerpc/configs/85xx/xes_mpc85xx_defconfig2
-rw-r--r--arch/powerpc/configs/86xx/gef_ppc9a_defconfig2
-rw-r--r--arch/powerpc/configs/86xx/gef_sbc310_defconfig2
-rw-r--r--arch/powerpc/configs/86xx/gef_sbc610_defconfig2
-rw-r--r--arch/powerpc/configs/86xx/mpc8610_hpcd_defconfig2
-rw-r--r--arch/powerpc/configs/86xx/mpc8641_hpcn_defconfig2
-rw-r--r--arch/powerpc/configs/86xx/sbc8641d_defconfig2
-rw-r--r--arch/powerpc/configs/adder875_defconfig2
-rw-r--r--arch/powerpc/configs/e55xx_smp_defconfig2
-rw-r--r--arch/powerpc/configs/ep8248e_defconfig2
-rw-r--r--arch/powerpc/configs/ep88xc_defconfig2
-rw-r--r--arch/powerpc/configs/gamecube_defconfig2
-rw-r--r--arch/powerpc/configs/holly_defconfig2
-rw-r--r--arch/powerpc/configs/mgcoge_defconfig2
-rw-r--r--arch/powerpc/configs/mgsuvd_defconfig2
-rw-r--r--arch/powerpc/configs/mpc7448_hpc2_defconfig2
-rw-r--r--arch/powerpc/configs/mpc8272_ads_defconfig2
-rw-r--r--arch/powerpc/configs/mpc83xx_defconfig2
-rw-r--r--arch/powerpc/configs/mpc85xx_defconfig2
-rw-r--r--arch/powerpc/configs/mpc85xx_smp_defconfig2
-rw-r--r--arch/powerpc/configs/mpc866_ads_defconfig2
-rw-r--r--arch/powerpc/configs/mpc86xx_defconfig2
-rw-r--r--arch/powerpc/configs/mpc885_ads_defconfig2
-rw-r--r--arch/powerpc/configs/ppc40x_defconfig2
-rw-r--r--arch/powerpc/configs/ppc44x_defconfig2
-rw-r--r--arch/powerpc/configs/pq2fads_defconfig2
-rw-r--r--arch/powerpc/configs/ps3_defconfig2
-rw-r--r--arch/powerpc/configs/pseries_defconfig7
-rw-r--r--arch/powerpc/configs/storcenter_defconfig2
-rw-r--r--arch/powerpc/configs/tqm8xx_defconfig2
-rw-r--r--arch/powerpc/configs/wii_defconfig2
-rw-r--r--arch/powerpc/include/asm/feature-fixups.h27
-rw-r--r--arch/powerpc/include/asm/immap_qe.h21
-rw-r--r--arch/powerpc/include/asm/irqflags.h40
-rw-r--r--arch/powerpc/include/asm/machdep.h18
-rw-r--r--arch/powerpc/include/asm/reg.h2
-rw-r--r--arch/powerpc/include/asm/reg_booke.h14
-rw-r--r--arch/powerpc/include/asm/spu.h8
-rw-r--r--arch/powerpc/kernel/cpu_setup_fsl_booke.S6
-rw-r--r--arch/powerpc/kernel/cputable.c23
-rw-r--r--arch/powerpc/kernel/crash.c72
-rw-r--r--arch/powerpc/kernel/entry_32.S11
-rw-r--r--arch/powerpc/kernel/machine_kexec.c19
-rw-r--r--arch/powerpc/kernel/perf_event.c1
-rw-r--r--arch/powerpc/kernel/perf_event_fsl_emb.c1
-rw-r--r--arch/powerpc/kernel/process.c2
-rw-r--r--arch/powerpc/kernel/prom.c4
-rw-r--r--arch/powerpc/kernel/rtas_flash.c53
-rw-r--r--arch/powerpc/kernel/rtasd.c2
-rw-r--r--arch/powerpc/kernel/time.c25
-rw-r--r--arch/powerpc/kernel/traps.c12
-rw-r--r--arch/powerpc/lib/feature-fixups-test.S19
-rw-r--r--arch/powerpc/platforms/83xx/mpc830x_rdb.c4
-rw-r--r--arch/powerpc/platforms/83xx/mpc831x_rdb.c4
-rw-r--r--arch/powerpc/platforms/83xx/mpc83xx.h2
-rw-r--r--arch/powerpc/platforms/83xx/usb.c21
-rw-r--r--arch/powerpc/platforms/cell/cpufreq_spudemand.c20
-rw-r--r--arch/powerpc/platforms/cell/qpace_setup.c5
-rw-r--r--arch/powerpc/platforms/cell/spu_base.c70
-rw-r--r--arch/powerpc/platforms/cell/spufs/file.c27
-rw-r--r--arch/powerpc/platforms/embedded6xx/gamecube.c11
-rw-r--r--arch/powerpc/platforms/embedded6xx/wii.c11
-rw-r--r--arch/powerpc/platforms/iseries/Kconfig2
-rw-r--r--arch/powerpc/platforms/pseries/Kconfig6
-rw-r--r--arch/powerpc/platforms/pseries/kexec.c10
-rw-r--r--arch/powerpc/platforms/pseries/ras.c102
-rw-r--r--arch/powerpc/sysdev/fsl_rio.c2
-rw-r--r--arch/powerpc/sysdev/mpic.c6
-rw-r--r--arch/s390/defconfig16
-rw-r--r--arch/s390/include/asm/compat.h2
-rw-r--r--arch/s390/include/asm/elf.h9
-rw-r--r--arch/s390/include/asm/system.h2
-rw-r--r--arch/s390/include/asm/thread_info.h6
-rw-r--r--arch/s390/kernel/process.c38
-rw-r--r--arch/s390/kernel/vdso.c4
-rw-r--r--arch/s390/mm/mmap.c49
-rw-r--r--arch/score/Kconfig10
-rw-r--r--arch/score/configs/spct6600_defconfig2
-rw-r--r--arch/sh/Kconfig2
-rw-r--r--arch/sh/kernel/cpu/shmobile/cpuidle.c1
-rw-r--r--arch/sparc/Kconfig9
-rw-r--r--arch/tile/Kconfig55
-rw-r--r--arch/tile/Kconfig.debug2
-rw-r--r--arch/tile/configs/tile_defconfig2
-rw-r--r--arch/um/Kconfig.common6
-rw-r--r--arch/um/Kconfig.um3
-rw-r--r--arch/um/defconfig2
-rw-r--r--arch/x86/Kconfig31
-rw-r--r--arch/x86/Kconfig.cpu2
-rw-r--r--arch/x86/Kconfig.debug4
-rw-r--r--arch/x86/include/asm/cacheflush.h42
-rw-r--r--arch/x86/include/asm/cpu.h1
-rw-r--r--arch/x86/include/asm/jump_label.h2
-rw-r--r--arch/x86/include/asm/numa_32.h2
-rw-r--r--arch/x86/include/asm/numa_64.h1
-rw-r--r--arch/x86/include/asm/percpu.h8
-rw-r--r--arch/x86/include/asm/processor.h5
-rw-r--r--arch/x86/kernel/acpi/boot.c1
-rw-r--r--arch/x86/kernel/apb_timer.c14
-rw-r--r--arch/x86/kernel/cpu/intel_cacheinfo.c3
-rw-r--r--arch/x86/kernel/cpu/mcheck/therm_throt.c1
-rw-r--r--arch/x86/kernel/dumpstack.c1
-rw-r--r--arch/x86/kernel/e820.c1
-rw-r--r--arch/x86/kernel/irq_32.c7
-rw-r--r--arch/x86/kernel/process.c33
-rw-r--r--arch/x86/kernel/process_32.c4
-rw-r--r--arch/x86/kernel/process_64.c6
-rw-r--r--arch/x86/kernel/smpboot.c3
-rw-r--r--arch/x86/kernel/tsc.c4
-rw-r--r--arch/x86/lguest/Kconfig1
-rw-r--r--arch/x86/lguest/boot.c2
-rw-r--r--arch/x86/mm/numa.c22
-rw-r--r--arch/x86/mm/numa_64.c24
-rw-r--r--arch/x86/mm/srat_32.c1
-rw-r--r--arch/x86/pci/broadcom_bus.c11
-rw-r--r--arch/x86/pci/common.c41
-rw-r--r--arch/x86/pci/irq.c3
-rw-r--r--arch/x86/platform/olpc/olpc-xo1.c101
-rw-r--r--arch/x86/xen/enlighten.c2
-rw-r--r--arch/x86/xen/irq.c2
-rw-r--r--arch/x86/xen/mmu.c1
-rw-r--r--arch/x86/xen/p2m.c20
-rw-r--r--arch/xtensa/configs/common_defconfig2
-rw-r--r--arch/xtensa/configs/iss_defconfig2
-rw-r--r--arch/xtensa/configs/s6105_defconfig2
-rw-r--r--block/Kconfig2
-rw-r--r--block/cfq-iosched.c28
-rw-r--r--drivers/Kconfig2
-rw-r--r--drivers/Makefile4
-rw-r--r--drivers/acpi/Kconfig20
-rw-r--r--drivers/acpi/Makefile3
-rw-r--r--drivers/acpi/ac.c3
-rw-r--r--drivers/acpi/acpi_ipmi.c525
-rw-r--r--drivers/acpi/acpica/Makefile2
-rw-r--r--drivers/acpi/acpica/accommon.h2
-rw-r--r--drivers/acpi/acpica/acconfig.h2
-rw-r--r--drivers/acpi/acpica/acdebug.h2
-rw-r--r--drivers/acpi/acpica/acdispat.h2
-rw-r--r--drivers/acpi/acpica/acevents.h23
-rw-r--r--drivers/acpi/acpica/acglobal.h11
-rw-r--r--drivers/acpi/acpica/achware.h4
-rw-r--r--drivers/acpi/acpica/acinterp.h2
-rw-r--r--drivers/acpi/acpica/aclocal.h15
-rw-r--r--drivers/acpi/acpica/acmacros.h2
-rw-r--r--drivers/acpi/acpica/acnamesp.h2
-rw-r--r--drivers/acpi/acpica/acobject.h16
-rw-r--r--drivers/acpi/acpica/acopcode.h2
-rw-r--r--drivers/acpi/acpica/acparser.h2
-rw-r--r--drivers/acpi/acpica/acpredef.h2
-rw-r--r--drivers/acpi/acpica/acresrc.h2
-rw-r--r--drivers/acpi/acpica/acstruct.h2
-rw-r--r--drivers/acpi/acpica/actables.h2
-rw-r--r--drivers/acpi/acpica/acutils.h2
-rw-r--r--drivers/acpi/acpica/amlcode.h10
-rw-r--r--drivers/acpi/acpica/amlresrc.h2
-rw-r--r--drivers/acpi/acpica/dsfield.c2
-rw-r--r--drivers/acpi/acpica/dsinit.c2
-rw-r--r--drivers/acpi/acpica/dsmethod.c64
-rw-r--r--drivers/acpi/acpica/dsmthdat.c2
-rw-r--r--drivers/acpi/acpica/dsobject.c2
-rw-r--r--drivers/acpi/acpica/dsopcode.c2
-rw-r--r--drivers/acpi/acpica/dsutils.c2
-rw-r--r--drivers/acpi/acpica/dswexec.c2
-rw-r--r--drivers/acpi/acpica/dswload.c2
-rw-r--r--drivers/acpi/acpica/dswscope.c2
-rw-r--r--drivers/acpi/acpica/dswstate.c2
-rw-r--r--drivers/acpi/acpica/evevent.c14
-rw-r--r--drivers/acpi/acpica/evgpe.c269
-rw-r--r--drivers/acpi/acpica/evgpeblk.c35
-rw-r--r--drivers/acpi/acpica/evgpeinit.c27
-rw-r--r--drivers/acpi/acpica/evgpeutil.c41
-rw-r--r--drivers/acpi/acpica/evmisc.c94
-rw-r--r--drivers/acpi/acpica/evregion.c2
-rw-r--r--drivers/acpi/acpica/evrgnini.c6
-rw-r--r--drivers/acpi/acpica/evsci.c2
-rw-r--r--drivers/acpi/acpica/evxface.c79
-rw-r--r--drivers/acpi/acpica/evxfevnt.c602
-rw-r--r--drivers/acpi/acpica/evxfgpe.c669
-rw-r--r--drivers/acpi/acpica/evxfregn.c2
-rw-r--r--drivers/acpi/acpica/exconfig.c2
-rw-r--r--drivers/acpi/acpica/exconvrt.c2
-rw-r--r--drivers/acpi/acpica/excreate.c10
-rw-r--r--drivers/acpi/acpica/exdebug.c2
-rw-r--r--drivers/acpi/acpica/exdump.c4
-rw-r--r--drivers/acpi/acpica/exfield.c2
-rw-r--r--drivers/acpi/acpica/exfldio.c2
-rw-r--r--drivers/acpi/acpica/exmisc.c2
-rw-r--r--drivers/acpi/acpica/exmutex.c2
-rw-r--r--drivers/acpi/acpica/exnames.c2
-rw-r--r--drivers/acpi/acpica/exoparg1.c2
-rw-r--r--drivers/acpi/acpica/exoparg2.c2
-rw-r--r--drivers/acpi/acpica/exoparg3.c2
-rw-r--r--drivers/acpi/acpica/exoparg6.c2
-rw-r--r--drivers/acpi/acpica/exprep.c2
-rw-r--r--drivers/acpi/acpica/exregion.c2
-rw-r--r--drivers/acpi/acpica/exresnte.c2
-rw-r--r--drivers/acpi/acpica/exresolv.c2
-rw-r--r--drivers/acpi/acpica/exresop.c2
-rw-r--r--drivers/acpi/acpica/exstore.c2
-rw-r--r--drivers/acpi/acpica/exstoren.c2
-rw-r--r--drivers/acpi/acpica/exstorob.c2
-rw-r--r--drivers/acpi/acpica/exsystem.c2
-rw-r--r--drivers/acpi/acpica/exutils.c2
-rw-r--r--drivers/acpi/acpica/hwacpi.c2
-rw-r--r--drivers/acpi/acpica/hwgpe.c34
-rw-r--r--drivers/acpi/acpica/hwpci.c2
-rw-r--r--drivers/acpi/acpica/hwregs.c2
-rw-r--r--drivers/acpi/acpica/hwsleep.c2
-rw-r--r--drivers/acpi/acpica/hwtimer.c2
-rw-r--r--drivers/acpi/acpica/hwvalid.c2
-rw-r--r--drivers/acpi/acpica/hwxface.c2
-rw-r--r--drivers/acpi/acpica/nsaccess.c8
-rw-r--r--drivers/acpi/acpica/nsalloc.c15
-rw-r--r--drivers/acpi/acpica/nsdump.c17
-rw-r--r--drivers/acpi/acpica/nsdumpdv.c2
-rw-r--r--drivers/acpi/acpica/nseval.c4
-rw-r--r--drivers/acpi/acpica/nsinit.c2
-rw-r--r--drivers/acpi/acpica/nsload.c2
-rw-r--r--drivers/acpi/acpica/nsnames.c2
-rw-r--r--drivers/acpi/acpica/nsobject.c2
-rw-r--r--drivers/acpi/acpica/nsparse.c2
-rw-r--r--drivers/acpi/acpica/nspredef.c2
-rw-r--r--drivers/acpi/acpica/nsrepair.c2
-rw-r--r--drivers/acpi/acpica/nsrepair2.c2
-rw-r--r--drivers/acpi/acpica/nssearch.c2
-rw-r--r--drivers/acpi/acpica/nsutils.c2
-rw-r--r--drivers/acpi/acpica/nswalk.c2
-rw-r--r--drivers/acpi/acpica/nsxfeval.c2
-rw-r--r--drivers/acpi/acpica/nsxfname.c7
-rw-r--r--drivers/acpi/acpica/nsxfobj.c2
-rw-r--r--drivers/acpi/acpica/psargs.c2
-rw-r--r--drivers/acpi/acpica/psloop.c4
-rw-r--r--drivers/acpi/acpica/psopcode.c2
-rw-r--r--drivers/acpi/acpica/psparse.c27
-rw-r--r--drivers/acpi/acpica/psscope.c2
-rw-r--r--drivers/acpi/acpica/pstree.c2
-rw-r--r--drivers/acpi/acpica/psutils.c2
-rw-r--r--drivers/acpi/acpica/pswalk.c2
-rw-r--r--drivers/acpi/acpica/psxface.c9
-rw-r--r--drivers/acpi/acpica/rsaddr.c2
-rw-r--r--drivers/acpi/acpica/rscalc.c2
-rw-r--r--drivers/acpi/acpica/rscreate.c2
-rw-r--r--drivers/acpi/acpica/rsdump.c2
-rw-r--r--drivers/acpi/acpica/rsinfo.c2
-rw-r--r--drivers/acpi/acpica/rsio.c2
-rw-r--r--drivers/acpi/acpica/rsirq.c2
-rw-r--r--drivers/acpi/acpica/rslist.c2
-rw-r--r--drivers/acpi/acpica/rsmemory.c2
-rw-r--r--drivers/acpi/acpica/rsmisc.c2
-rw-r--r--drivers/acpi/acpica/rsutils.c2
-rw-r--r--drivers/acpi/acpica/rsxface.c2
-rw-r--r--drivers/acpi/acpica/tbfadt.c2
-rw-r--r--drivers/acpi/acpica/tbfind.c2
-rw-r--r--drivers/acpi/acpica/tbinstal.c2
-rw-r--r--drivers/acpi/acpica/tbutils.c2
-rw-r--r--drivers/acpi/acpica/tbxface.c2
-rw-r--r--drivers/acpi/acpica/tbxfroot.c2
-rw-r--r--drivers/acpi/acpica/utalloc.c2
-rw-r--r--drivers/acpi/acpica/utcopy.c2
-rw-r--r--drivers/acpi/acpica/utdebug.c2
-rw-r--r--drivers/acpi/acpica/utdelete.c2
-rw-r--r--drivers/acpi/acpica/uteval.c2
-rw-r--r--drivers/acpi/acpica/utglobal.c5
-rw-r--r--drivers/acpi/acpica/utids.c2
-rw-r--r--drivers/acpi/acpica/utinit.c2
-rw-r--r--drivers/acpi/acpica/utlock.c2
-rw-r--r--drivers/acpi/acpica/utmath.c2
-rw-r--r--drivers/acpi/acpica/utmisc.c2
-rw-r--r--drivers/acpi/acpica/utmutex.c3
-rw-r--r--drivers/acpi/acpica/utobject.c2
-rw-r--r--drivers/acpi/acpica/utosi.c2
-rw-r--r--drivers/acpi/acpica/utresrc.c2
-rw-r--r--drivers/acpi/acpica/utstate.c2
-rw-r--r--drivers/acpi/acpica/utxface.c2
-rw-r--r--drivers/acpi/acpica/utxferror.c2
-rw-r--r--drivers/acpi/apei/apei-internal.h2
-rw-r--r--drivers/acpi/apei/cper.c311
-rw-r--r--drivers/acpi/apei/ghes.c431
-rw-r--r--drivers/acpi/apei/hest.c26
-rw-r--r--drivers/acpi/battery.c15
-rw-r--r--drivers/acpi/bus.c153
-rw-r--r--drivers/acpi/button.c9
-rw-r--r--drivers/acpi/dock.c2
-rw-r--r--drivers/acpi/ec.c5
-rw-r--r--drivers/acpi/fan.c27
-rw-r--r--drivers/acpi/glue.c5
-rw-r--r--drivers/acpi/internal.h13
-rw-r--r--drivers/acpi/numa.c8
-rw-r--r--drivers/acpi/nvs.c (renamed from kernel/power/nvs.c)19
-rw-r--r--drivers/acpi/osl.c23
-rw-r--r--drivers/acpi/pci_root.c35
-rw-r--r--drivers/acpi/power.c128
-rw-r--r--drivers/acpi/proc.c41
-rw-r--r--drivers/acpi/processor_core.c4
-rw-r--r--drivers/acpi/processor_driver.c80
-rw-r--r--drivers/acpi/processor_idle.c28
-rw-r--r--drivers/acpi/processor_throttling.c190
-rw-r--r--drivers/acpi/sbs.c2
-rw-r--r--drivers/acpi/scan.c70
-rw-r--r--drivers/acpi/sleep.c15
-rw-r--r--drivers/acpi/sysfs.c19
-rw-r--r--drivers/acpi/thermal.c5
-rw-r--r--drivers/acpi/video.c104
-rw-r--r--drivers/acpi/video_detect.c57
-rw-r--r--drivers/acpi/wakeup.c22
-rw-r--r--drivers/ata/Kconfig2
-rw-r--r--drivers/base/Kconfig2
-rw-r--r--drivers/char/Kconfig12
-rw-r--r--drivers/char/Makefile13
-rw-r--r--drivers/char/agp/intel-agp.c4
-rw-r--r--drivers/char/agp/intel-gtt.c21
-rw-r--r--drivers/char/ipmi/ipmi_msghandler.c27
-rw-r--r--drivers/char/ipmi/ipmi_si_intf.c23
-rw-r--r--drivers/char/tpm/tpm.c10
-rw-r--r--drivers/char/tpm/tpm_tis.c6
-rw-r--r--drivers/clocksource/acpi_pm.c6
-rw-r--r--drivers/cpufreq/Kconfig2
-rw-r--r--drivers/cpuidle/cpuidle.c92
-rw-r--r--drivers/dma/Kconfig9
-rw-r--r--drivers/dma/amba-pl08x.c1168
-rw-r--r--drivers/dma/at_hdmac.c19
-rw-r--r--drivers/dma/fsldma.c4
-rw-r--r--drivers/dma/intel_mid_dma.c33
-rw-r--r--drivers/dma/iop-adma.c4
-rw-r--r--drivers/dma/pch_dma.c19
-rw-r--r--drivers/dma/ste_dma40.c191
-rw-r--r--drivers/dma/ste_dma40_ll.c246
-rw-r--r--drivers/dma/ste_dma40_ll.h36
-rw-r--r--drivers/firewire/Kconfig6
-rw-r--r--drivers/firewire/core-card.c11
-rw-r--r--drivers/firewire/net.c9
-rw-r--r--drivers/firmware/Kconfig2
-rw-r--r--drivers/gpio/cs5535-gpio.c93
-rw-r--r--drivers/gpio/timbgpio.c6
-rw-r--r--drivers/gpu/drm/Kconfig6
-rw-r--r--drivers/gpu/drm/drm_fb_helper.c45
-rw-r--r--drivers/gpu/drm/i915/i915_debugfs.c2
-rw-r--r--drivers/gpu/drm/i915/i915_dma.c35
-rw-r--r--drivers/gpu/drm/i915/i915_drv.c8
-rw-r--r--drivers/gpu/drm/i915/i915_drv.h6
-rw-r--r--drivers/gpu/drm/i915/i915_gem.c12
-rw-r--r--drivers/gpu/drm/i915/i915_gem_execbuffer.c27
-rw-r--r--drivers/gpu/drm/i915/i915_gem_gtt.c4
-rw-r--r--drivers/gpu/drm/i915/i915_irq.c39
-rw-r--r--drivers/gpu/drm/i915/i915_reg.h6
-rw-r--r--drivers/gpu/drm/i915/intel_bios.c17
-rw-r--r--drivers/gpu/drm/i915/intel_display.c42
-rw-r--r--drivers/gpu/drm/i915/intel_fb.c1
-rw-r--r--drivers/gpu/drm/i915/intel_lvds.c8
-rw-r--r--drivers/gpu/drm/i915/intel_opregion.c3
-rw-r--r--drivers/gpu/drm/i915/intel_panel.c2
-rw-r--r--drivers/gpu/drm/i915/intel_ringbuffer.c82
-rw-r--r--drivers/gpu/drm/i915/intel_ringbuffer.h4
-rw-r--r--drivers/gpu/drm/nouveau/Kconfig2
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_drv.h15
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_fbcon.c5
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_mem.c26
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_mm.c182
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_mm.h4
-rw-r--r--drivers/gpu/drm/nouveau/nv40_graph.c3
-rw-r--r--drivers/gpu/drm/nouveau/nv40_grctx.c21
-rw-r--r--drivers/gpu/drm/nouveau/nv40_mc.c14
-rw-r--r--drivers/gpu/drm/nouveau/nv50_instmem.c7
-rw-r--r--drivers/gpu/drm/nouveau/nvc0_graph.c3
-rw-r--r--drivers/gpu/drm/nouveau/nvc0_vm.c4
-rw-r--r--drivers/gpu/drm/radeon/atombios_crtc.c22
-rw-r--r--drivers/gpu/drm/radeon/evergreen.c33
-rw-r--r--drivers/gpu/drm/radeon/r100.c13
-rw-r--r--drivers/gpu/drm/radeon/r300.c11
-rw-r--r--drivers/gpu/drm/radeon/r600.c26
-rw-r--r--drivers/gpu/drm/radeon/radeon.h1
-rw-r--r--drivers/gpu/drm/radeon/radeon_atombios.c14
-rw-r--r--drivers/gpu/drm/radeon/radeon_drv.c6
-rw-r--r--drivers/gpu/drm/radeon/radeon_fb.c2
-rw-r--r--drivers/gpu/drm/radeon/radeon_irq_kms.c3
-rw-r--r--drivers/gpu/drm/radeon/radeon_kms.c4
-rw-r--r--drivers/gpu/drm/radeon/reg_srcs/evergreen2
-rw-r--r--drivers/gpu/drm/radeon/rs600.c16
-rw-r--r--drivers/gpu/drm/radeon/rv770.c5
-rw-r--r--drivers/gpu/stub/Kconfig1
-rw-r--r--drivers/gpu/vga/Kconfig2
-rw-r--r--drivers/gpu/vga/vgaarb.c2
-rw-r--r--drivers/hid/Kconfig64
-rw-r--r--drivers/hid/usbhid/Kconfig2
-rw-r--r--drivers/hwmon/Kconfig4
-rw-r--r--drivers/hwmon/lm93.c21
-rw-r--r--drivers/i2c/busses/scx200_acb.c200
-rw-r--r--drivers/i2c/i2c-core.c90
-rw-r--r--drivers/ide/Kconfig2
-rw-r--r--drivers/idle/intel_idle.c65
-rw-r--r--drivers/infiniband/core/cache.c4
-rw-r--r--drivers/infiniband/core/device.c11
-rw-r--r--drivers/infiniband/core/sa_query.c2
-rw-r--r--drivers/infiniband/core/umem.c2
-rw-r--r--drivers/infiniband/hw/amso1100/c2_rnic.c5
-rw-r--r--drivers/infiniband/hw/ehca/ipz_pt_fn.c5
-rw-r--r--drivers/infiniband/hw/ipath/ipath_driver.c5
-rw-r--r--drivers/infiniband/hw/ipath/ipath_file_ops.c11
-rw-r--r--drivers/infiniband/hw/ipath/ipath_init_chip.c5
-rw-r--r--drivers/infiniband/hw/ipath/ipath_user_pages.c2
-rw-r--r--drivers/infiniband/hw/mlx4/main.c12
-rw-r--r--drivers/infiniband/hw/mthca/Kconfig2
-rw-r--r--drivers/infiniband/hw/mthca/mthca_catas.c5
-rw-r--r--drivers/infiniband/hw/mthca/mthca_cmd.c2
-rw-r--r--drivers/infiniband/hw/mthca/mthca_eq.c2
-rw-r--r--drivers/infiniband/hw/mthca/mthca_main.c2
-rw-r--r--drivers/infiniband/hw/mthca/mthca_mr.c2
-rw-r--r--drivers/infiniband/hw/nes/nes.c35
-rw-r--r--drivers/infiniband/hw/nes/nes.h4
-rw-r--r--drivers/infiniband/hw/nes/nes_cm.c8
-rw-r--r--drivers/infiniband/hw/nes/nes_hw.c95
-rw-r--r--drivers/infiniband/hw/nes/nes_hw.h10
-rw-r--r--drivers/infiniband/hw/nes/nes_nic.c78
-rw-r--r--drivers/infiniband/hw/nes/nes_verbs.c37
-rw-r--r--drivers/infiniband/hw/qib/qib_iba7220.c7
-rw-r--r--drivers/infiniband/hw/qib/qib_iba7322.c14
-rw-r--r--drivers/infiniband/hw/qib/qib_init.c33
-rw-r--r--drivers/infiniband/hw/qib/qib_qsfp.c9
-rw-r--r--drivers/infiniband/hw/qib/qib_verbs.h3
-rw-r--r--drivers/infiniband/ulp/ipoib/Kconfig2
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_cm.c10
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_main.c3
-rw-r--r--drivers/infiniband/ulp/srp/ib_srp.c19
-rw-r--r--drivers/input/Kconfig6
-rw-r--r--drivers/input/keyboard/Kconfig4
-rw-r--r--drivers/input/mouse/Kconfig10
-rw-r--r--drivers/input/serio/Kconfig6
-rw-r--r--drivers/input/touchscreen/Kconfig30
-rw-r--r--drivers/leds/ledtrig-gpio.c15
-rw-r--r--drivers/lguest/page_tables.c2
-rw-r--r--drivers/lguest/x86/core.c4
-rw-r--r--drivers/macintosh/therm_pm72.c4
-rw-r--r--drivers/md/dm-table.c1
-rw-r--r--drivers/md/md.c1
-rw-r--r--drivers/media/common/saa7146_core.c2
-rw-r--r--drivers/media/common/saa7146_fops.c8
-rw-r--r--drivers/media/common/saa7146_vbi.c2
-rw-r--r--drivers/media/common/saa7146_video.c20
-rw-r--r--drivers/media/common/tuners/Kconfig2
-rw-r--r--drivers/media/common/tuners/tda8290.c130
-rw-r--r--drivers/media/dvb/dvb-usb/dib0700_core.c6
-rw-r--r--drivers/media/dvb/firewire/firedtv-rc.c9
-rw-r--r--drivers/media/dvb/frontends/Kconfig2
-rw-r--r--drivers/media/dvb/frontends/af9013.c4
-rw-r--r--drivers/media/dvb/frontends/ix2505v.c2
-rw-r--r--drivers/media/dvb/frontends/mb86a20s.c36
-rw-r--r--drivers/media/dvb/ttpci/av7110_ca.c2
-rw-r--r--drivers/media/radio/Kconfig14
-rw-r--r--drivers/media/radio/Makefile1
-rw-r--r--drivers/media/radio/radio-aimslab.c1
-rw-r--r--drivers/media/radio/radio-gemtek-pci.c478
-rw-r--r--drivers/media/radio/radio-maxiradio.c4
-rw-r--r--drivers/media/radio/radio-wl1273.c2
-rw-r--r--drivers/media/radio/si470x/radio-si470x-common.c9
-rw-r--r--drivers/media/rc/ene_ir.c23
-rw-r--r--drivers/media/rc/ene_ir.h2
-rw-r--r--drivers/media/rc/imon.c60
-rw-r--r--drivers/media/rc/ir-raw.c2
-rw-r--r--drivers/media/rc/keymaps/rc-dib0700-nec.c52
-rw-r--r--drivers/media/rc/mceusb.c3
-rw-r--r--drivers/media/video/Kconfig11
-rw-r--r--drivers/media/video/Makefile1
-rw-r--r--drivers/media/video/adv7175.c11
-rw-r--r--drivers/media/video/bt8xx/bttv-cards.c39
-rw-r--r--drivers/media/video/bt8xx/bttv.h1
-rw-r--r--drivers/media/video/cafe_ccic.c15
-rw-r--r--drivers/media/video/cpia2/cpia2.h2
-rw-r--r--drivers/media/video/cpia2/cpia2_core.c65
-rw-r--r--drivers/media/video/cpia2/cpia2_v4l.c104
-rw-r--r--drivers/media/video/cx18/cx18-driver.c24
-rw-r--r--drivers/media/video/cx18/cx18-driver.h3
-rw-r--r--drivers/media/video/cx18/cx18-streams.h3
-rw-r--r--drivers/media/video/cx231xx/cx231xx-dvb.c5
-rw-r--r--drivers/media/video/cx25840/cx25840-core.c22
-rw-r--r--drivers/media/video/davinci/vpif.c177
-rw-r--r--drivers/media/video/davinci/vpif.h18
-rw-r--r--drivers/media/video/davinci/vpif_capture.c451
-rw-r--r--drivers/media/video/davinci/vpif_capture.h2
-rw-r--r--drivers/media/video/davinci/vpif_display.c474
-rw-r--r--drivers/media/video/davinci/vpif_display.h2
-rw-r--r--drivers/media/video/em28xx/em28xx-cards.c19
-rw-r--r--drivers/media/video/et61x251/et61x251.h24
-rw-r--r--drivers/media/video/gspca/benq.c2
-rw-r--r--drivers/media/video/gspca/conex.c4
-rw-r--r--drivers/media/video/gspca/cpia1.c2
-rw-r--r--drivers/media/video/gspca/etoms.c4
-rw-r--r--drivers/media/video/gspca/finepix.c2
-rw-r--r--drivers/media/video/gspca/gl860/gl860.c2
-rw-r--r--drivers/media/video/gspca/gspca.c210
-rw-r--r--drivers/media/video/gspca/gspca.h2
-rw-r--r--drivers/media/video/gspca/jeilinj.c2
-rw-r--r--drivers/media/video/gspca/jpeg.h4
-rw-r--r--drivers/media/video/gspca/konica.c2
-rw-r--r--drivers/media/video/gspca/m5602/m5602_core.c2
-rw-r--r--drivers/media/video/gspca/mars.c2
-rw-r--r--drivers/media/video/gspca/mr97310a.c2
-rw-r--r--drivers/media/video/gspca/ov519.c8
-rw-r--r--drivers/media/video/gspca/ov534.c29
-rw-r--r--drivers/media/video/gspca/ov534_9.c2
-rw-r--r--drivers/media/video/gspca/pac207.c2
-rw-r--r--drivers/media/video/gspca/pac7302.c4
-rw-r--r--drivers/media/video/gspca/pac7311.c4
-rw-r--r--drivers/media/video/gspca/sn9c2028.c2
-rw-r--r--drivers/media/video/gspca/sn9c20x.c2
-rw-r--r--drivers/media/video/gspca/sonixb.c270
-rw-r--r--drivers/media/video/gspca/sonixj.c155
-rw-r--r--drivers/media/video/gspca/spca1528.c2
-rw-r--r--drivers/media/video/gspca/spca500.c2
-rw-r--r--drivers/media/video/gspca/spca501.c2
-rw-r--r--drivers/media/video/gspca/spca505.c2
-rw-r--r--drivers/media/video/gspca/spca508.c2
-rw-r--r--drivers/media/video/gspca/spca561.c2
-rw-r--r--drivers/media/video/gspca/sq905.c2
-rw-r--r--drivers/media/video/gspca/sq905c.c2
-rw-r--r--drivers/media/video/gspca/sq930x.c2
-rw-r--r--drivers/media/video/gspca/stk014.c2
-rw-r--r--drivers/media/video/gspca/stv0680.c2
-rw-r--r--drivers/media/video/gspca/stv06xx/stv06xx.c2
-rw-r--r--drivers/media/video/gspca/sunplus.c2
-rw-r--r--drivers/media/video/gspca/t613.c2
-rw-r--r--drivers/media/video/gspca/tv8532.c2
-rw-r--r--drivers/media/video/gspca/vc032x.c2
-rw-r--r--drivers/media/video/gspca/xirlink_cit.c2
-rw-r--r--drivers/media/video/gspca/zc3xx.c2
-rw-r--r--drivers/media/video/hdpvr/Makefile4
-rw-r--r--drivers/media/video/hdpvr/hdpvr-core.c10
-rw-r--r--drivers/media/video/hdpvr/hdpvr-i2c.c143
-rw-r--r--drivers/media/video/hdpvr/hdpvr-video.c7
-rw-r--r--drivers/media/video/hdpvr/hdpvr.h5
-rw-r--r--drivers/media/video/ir-kbd-i2c.c12
-rw-r--r--drivers/media/video/ivtv/ivtv-i2c.c9
-rw-r--r--drivers/media/video/mt9v011.c54
-rw-r--r--drivers/media/video/mt9v011.h36
-rw-r--r--drivers/media/video/ov7670.c74
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h2
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-i2c-core.c62
-rw-r--r--drivers/media/video/saa7134/saa7134-cards.c51
-rw-r--r--drivers/media/video/saa7134/saa7134-dvb.c80
-rw-r--r--drivers/media/video/sn9c102/sn9c102_devtable.h74
-rw-r--r--drivers/media/video/sr030pc30.c10
-rw-r--r--drivers/media/video/tda9875.c411
-rw-r--r--drivers/media/video/tlg2300/pd-video.c13
-rw-r--r--drivers/media/video/v4l2-common.c19
-rw-r--r--drivers/media/video/v4l2-ctrls.c34
-rw-r--r--drivers/media/video/v4l2-dev.c9
-rw-r--r--drivers/media/video/v4l2-device.c16
-rw-r--r--drivers/media/video/v4l2-ioctl.c20
-rw-r--r--drivers/media/video/w9966.c1
-rw-r--r--drivers/media/video/zoran/zoran_card.c2
-rw-r--r--drivers/mfd/88pm860x-core.c36
-rw-r--r--drivers/mfd/Kconfig16
-rw-r--r--drivers/mfd/Makefile3
-rw-r--r--drivers/mfd/ab3550-core.c28
-rw-r--r--drivers/mfd/ab8500-core.c306
-rw-r--r--drivers/mfd/ab8500-debugfs.c1016
-rw-r--r--drivers/mfd/ab8500-spi.c143
-rw-r--r--drivers/mfd/asic3.c62
-rw-r--r--drivers/mfd/cs5535-mfd.c151
-rw-r--r--drivers/mfd/ezx-pcap.c25
-rw-r--r--drivers/mfd/htc-egpio.c27
-rw-r--r--drivers/mfd/htc-i2cpld.c40
-rw-r--r--drivers/mfd/jz4740-adc.c25
-rw-r--r--drivers/mfd/max8925-core.c30
-rw-r--r--drivers/mfd/max8998-irq.c37
-rw-r--r--drivers/mfd/max8998.c134
-rw-r--r--drivers/mfd/mc13xxx-core.c2
-rw-r--r--drivers/mfd/mfd-core.c4
-rw-r--r--drivers/mfd/sm501.c9
-rw-r--r--drivers/mfd/stmpe.c28
-rw-r--r--drivers/mfd/t7l66xb.c20
-rw-r--r--drivers/mfd/tc6393xb.c22
-rw-r--r--drivers/mfd/tps65010.c2
-rw-r--r--drivers/mfd/tps6586x.c36
-rw-r--r--drivers/mfd/twl-core.c2
-rw-r--r--drivers/mfd/twl4030-irq.c28
-rw-r--r--drivers/mfd/twl6030-irq.c2
-rw-r--r--drivers/mfd/vx855.c2
-rw-r--r--drivers/mfd/wm831x-core.c17
-rw-r--r--drivers/mfd/wm831x-i2c.c14
-rw-r--r--drivers/mfd/wm831x-irq.c53
-rw-r--r--drivers/mfd/wm831x-spi.c18
-rw-r--r--drivers/mfd/wm8350-irq.c32
-rw-r--r--drivers/mfd/wm8994-core.c46
-rw-r--r--drivers/mfd/wm8994-irq.c32
-rw-r--r--drivers/misc/Kconfig2
-rw-r--r--drivers/misc/cs5535-mfgpt.c73
-rw-r--r--drivers/mmc/host/msm_sdcc.c52
-rw-r--r--drivers/mmc/host/sdhci-of-core.c9
-rw-r--r--drivers/mtd/Kconfig19
-rw-r--r--drivers/mtd/Makefile2
-rw-r--r--drivers/mtd/chips/cfi_cmdset_0001.c55
-rw-r--r--drivers/mtd/chips/cfi_cmdset_0002.c116
-rw-r--r--drivers/mtd/chips/cfi_cmdset_0020.c1
-rw-r--r--drivers/mtd/chips/cfi_util.c2
-rw-r--r--drivers/mtd/chips/fwh_lock.h2
-rw-r--r--drivers/mtd/devices/m25p80.c39
-rw-r--r--drivers/mtd/devices/sst25l.c4
-rw-r--r--drivers/mtd/maps/amd76xrom.c7
-rw-r--r--drivers/mtd/maps/bcm963xx-flash.c5
-rw-r--r--drivers/mtd/maps/ck804xrom.c7
-rw-r--r--drivers/mtd/maps/esb2rom.c9
-rw-r--r--drivers/mtd/maps/ichxrom.c9
-rw-r--r--drivers/mtd/maps/physmap_of.c4
-rw-r--r--drivers/mtd/maps/scx200_docflash.c5
-rw-r--r--drivers/mtd/maps/tqm8xxl.c2
-rw-r--r--drivers/mtd/mtdchar.c12
-rw-r--r--drivers/mtd/mtdconcat.c1
-rw-r--r--drivers/mtd/mtdoops.c3
-rw-r--r--drivers/mtd/mtdpart.c30
-rw-r--r--drivers/mtd/nand/Kconfig1
-rw-r--r--drivers/mtd/nand/ams-delta.c80
-rw-r--r--drivers/mtd/nand/fsl_elbc_nand.c2
-rw-r--r--drivers/mtd/nand/fsmc_nand.c89
-rw-r--r--drivers/mtd/nand/jz4740_nand.c57
-rw-r--r--drivers/mtd/nand/mxc_nand.c2
-rw-r--r--drivers/mtd/nand/nand_base.c25
-rw-r--r--drivers/mtd/nand/nand_bbt.c3
-rw-r--r--drivers/mtd/nand/nandsim.c39
-rw-r--r--drivers/mtd/nand/pasemi_nand.c2
-rw-r--r--drivers/mtd/nand/pxa3xx_nand.c2
-rw-r--r--drivers/mtd/nand/txx9ndfmc.c5
-rw-r--r--drivers/mtd/onenand/omap2.c80
-rw-r--r--drivers/mtd/onenand/onenand_base.c81
-rw-r--r--drivers/mtd/onenand/onenand_bbt.c10
-rw-r--r--drivers/mtd/onenand/samsung.c7
-rw-r--r--drivers/mtd/ubi/build.c28
-rw-r--r--drivers/mtd/ubi/vtbl.c6
-rw-r--r--drivers/net/Kconfig5
-rw-r--r--drivers/net/arm/ks8695net.c290
-rw-r--r--drivers/net/bfin_mac.c9
-rw-r--r--drivers/net/bna/bnad_ethtool.c1
-rw-r--r--drivers/net/bnx2x/bnx2x.h4
-rw-r--r--drivers/net/bnx2x/bnx2x_hsi.h4
-rw-r--r--drivers/net/bnx2x/bnx2x_link.c173
-rw-r--r--drivers/net/bnx2x/bnx2x_reg.h4
-rw-r--r--drivers/net/cassini.c6
-rw-r--r--drivers/net/e1000/e1000_main.c10
-rw-r--r--drivers/net/e1000e/82571.c4
-rw-r--r--drivers/net/e1000e/Makefile2
-rw-r--r--drivers/net/e1000e/defines.h2
-rw-r--r--drivers/net/e1000e/e1000.h2
-rw-r--r--drivers/net/e1000e/es2lan.c2
-rw-r--r--drivers/net/e1000e/ethtool.c2
-rw-r--r--drivers/net/e1000e/hw.h4
-rw-r--r--drivers/net/e1000e/ich8lan.c2
-rw-r--r--drivers/net/e1000e/lib.c20
-rw-r--r--drivers/net/e1000e/netdev.c223
-rw-r--r--drivers/net/e1000e/param.c6
-rw-r--r--drivers/net/e1000e/phy.c4
-rw-r--r--drivers/net/gianfar.c12
-rw-r--r--drivers/net/gianfar.h10
-rw-r--r--drivers/net/greth.c221
-rw-r--r--drivers/net/greth.h2
-rw-r--r--drivers/net/irda/sh_irda.c14
-rw-r--r--drivers/net/ixgbe/ixgbe_main.c23
-rw-r--r--drivers/net/macvtap.c2
-rw-r--r--drivers/net/mlx4/catas.c6
-rw-r--r--drivers/net/mlx4/en_main.c3
-rw-r--r--drivers/net/mlx4/main.c2
-rw-r--r--drivers/net/mlx4/mcg.c23
-rw-r--r--drivers/net/myri10ge/myri10ge.c4
-rw-r--r--drivers/net/ns83820.c5
-rw-r--r--drivers/net/r8169.c43
-rw-r--r--drivers/net/sfc/efx.c18
-rw-r--r--drivers/net/sfc/falcon.c25
-rw-r--r--drivers/net/sfc/net_driver.h10
-rw-r--r--drivers/net/tile/tilepro.c10
-rw-r--r--drivers/net/ucc_geth.c2
-rw-r--r--drivers/net/usb/cdc_ncm.c21
-rw-r--r--drivers/net/vmxnet3/vmxnet3_drv.c93
-rw-r--r--drivers/net/vmxnet3/vmxnet3_ethtool.c274
-rw-r--r--drivers/net/vmxnet3/vmxnet3_int.h7
-rw-r--r--drivers/net/vxge/vxge-main.c1
-rw-r--r--drivers/net/wireless/ath/ath5k/base.c4
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9002_calib.c13
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h2
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_hw.c4
-rw-r--r--drivers/net/wireless/ath/ath9k/eeprom_def.c4
-rw-r--r--drivers/net/wireless/ath/ath9k/htc.h3
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_drv_main.c37
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_drv_txrx.c8
-rw-r--r--drivers/net/wireless/ath/ath9k/hw.c5
-rw-r--r--drivers/net/wireless/hostap/hostap_cs.c15
-rw-r--r--drivers/net/wireless/ipw2x00/ipw2200.c7
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-eeprom.c2
-rw-r--r--drivers/net/wireless/iwmc3200wifi/netdev.c2
-rw-r--r--drivers/net/wireless/p54/txrx.c2
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00firmware.c1
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00pci.c4
-rw-r--r--drivers/nfc/pn544.c2
-rw-r--r--drivers/of/fdt.c8
-rw-r--r--drivers/pci/msi.c5
-rw-r--r--drivers/pci/msi.h6
-rw-r--r--drivers/pci/pci-acpi.c3
-rw-r--r--drivers/pci/pci-driver.c5
-rw-r--r--drivers/pci/pci-stub.c7
-rw-r--r--drivers/pci/pci-sysfs.c2
-rw-r--r--drivers/pci/pci.c25
-rw-r--r--drivers/pci/pci.h14
-rw-r--r--drivers/pci/pcie/Kconfig2
-rw-r--r--drivers/pci/pcie/aer/aerdrv.c1
-rw-r--r--drivers/pci/pcie/aer/aerdrv.h3
-rw-r--r--drivers/pci/pcie/aspm.c21
-rw-r--r--drivers/pci/pcie/pme.c31
-rw-r--r--drivers/pci/pcie/portdrv.h5
-rw-r--r--drivers/pci/pcie/portdrv_acpi.c23
-rw-r--r--drivers/pci/pcie/portdrv_core.c25
-rw-r--r--drivers/pci/pcie/portdrv_pci.c37
-rw-r--r--drivers/pcmcia/Kconfig12
-rw-r--r--drivers/platform/x86/fujitsu-laptop.c4
-rw-r--r--drivers/platform/x86/intel_scu_ipc.c7
-rw-r--r--drivers/platform/x86/intel_scu_ipcutil.c2
-rw-r--r--drivers/pnp/Makefile6
-rw-r--r--drivers/pnp/core.c7
-rw-r--r--drivers/pnp/driver.c7
-rw-r--r--drivers/pnp/isapnp/Makefile6
-rw-r--r--drivers/pnp/pnpacpi/Makefile3
-rw-r--r--drivers/pnp/pnpacpi/core.c93
-rw-r--r--drivers/pnp/pnpbios/Makefile5
-rw-r--r--drivers/power/Kconfig20
-rw-r--r--drivers/power/Makefile2
-rw-r--r--drivers/power/collie_battery.c13
-rw-r--r--drivers/power/ds2760_battery.c2
-rw-r--r--drivers/power/gpio-charger.c188
-rw-r--r--drivers/power/intel_mid_battery.c2
-rw-r--r--drivers/power/isp1704_charger.c201
-rw-r--r--drivers/power/jz4740-battery.c13
-rw-r--r--drivers/power/max17042_battery.c239
-rw-r--r--drivers/power/olpc_battery.c114
-rw-r--r--drivers/power/power_supply_core.c6
-rw-r--r--drivers/power/s3c_adc_battery.c12
-rw-r--r--drivers/power/tosa_battery.c13
-rw-r--r--drivers/power/wm97xx_battery.c4
-rw-r--r--drivers/power/z2_battery.c6
-rw-r--r--drivers/rapidio/rio-scan.c2
-rw-r--r--drivers/regulator/max8998.c94
-rw-r--r--drivers/rtc/Kconfig12
-rw-r--r--drivers/rtc/interface.c61
-rw-r--r--drivers/rtc/rtc-max8998.c54
-rw-r--r--drivers/s390/cio/device.c1
-rw-r--r--drivers/s390/net/qeth_l2_main.c18
-rw-r--r--drivers/s390/net/qeth_l3_main.c22
-rw-r--r--drivers/scsi/ipr.c8
-rw-r--r--drivers/scsi/pmcraid.c7
-rw-r--r--drivers/scsi/sd.c103
-rw-r--r--drivers/scsi/sd.h1
-rw-r--r--drivers/scsi/sr.c4
-rw-r--r--drivers/sfi/sfi_core.c2
-rw-r--r--drivers/spi/Kconfig16
-rw-r--r--drivers/spi/Makefile1
-rw-r--r--drivers/spi/amba-pl022.c2
-rw-r--r--drivers/spi/ath79_spi.c292
-rw-r--r--drivers/spi/dw_spi_mmio.c5
-rw-r--r--drivers/spi/spi_imx.c6
-rw-r--r--drivers/spi/spi_sh_msiof.c2
-rw-r--r--drivers/spi/spi_tegra.c2
-rw-r--r--drivers/ssb/Kconfig2
-rw-r--r--drivers/ssb/scan.c10
-rw-r--r--drivers/staging/autofs/dirhash.c5
-rw-r--r--drivers/staging/bcm/Qos.c7
-rw-r--r--drivers/staging/bcm/Transmit.c6
-rw-r--r--drivers/staging/lirc/TODO.lirc_zilog36
-rw-r--r--drivers/staging/lirc/lirc_imon.c1
-rw-r--r--drivers/staging/lirc/lirc_it87.c1
-rw-r--r--drivers/staging/lirc/lirc_parallel.c19
-rw-r--r--drivers/staging/lirc/lirc_sasem.c1
-rw-r--r--drivers/staging/lirc/lirc_serial.c3
-rw-r--r--drivers/staging/lirc/lirc_sir.c1
-rw-r--r--drivers/staging/lirc/lirc_zilog.c650
-rw-r--r--drivers/staging/sm7xx/smtcfb.c2
-rw-r--r--drivers/staging/smbfs/dir.c4
-rw-r--r--drivers/staging/tm6000/tm6000-video.c46
-rw-r--r--drivers/target/Kconfig32
-rw-r--r--drivers/target/Makefile24
-rw-r--r--drivers/target/target_core_alua.c1991
-rw-r--r--drivers/target/target_core_alua.h126
-rw-r--r--drivers/target/target_core_cdb.c1131
-rw-r--r--drivers/target/target_core_configfs.c3225
-rw-r--r--drivers/target/target_core_device.c1694
-rw-r--r--drivers/target/target_core_fabric_configfs.c996
-rw-r--r--drivers/target/target_core_fabric_lib.c451
-rw-r--r--drivers/target/target_core_file.c688
-rw-r--r--drivers/target/target_core_file.h50
-rw-r--r--drivers/target/target_core_hba.c185
-rw-r--r--drivers/target/target_core_hba.h7
-rw-r--r--drivers/target/target_core_iblock.c808
-rw-r--r--drivers/target/target_core_iblock.h40
-rw-r--r--drivers/target/target_core_mib.c1078
-rw-r--r--drivers/target/target_core_mib.h28
-rw-r--r--drivers/target/target_core_pr.c4252
-rw-r--r--drivers/target/target_core_pr.h67
-rw-r--r--drivers/target/target_core_pscsi.c1470
-rw-r--r--drivers/target/target_core_pscsi.h65
-rw-r--r--drivers/target/target_core_rd.c1091
-rw-r--r--drivers/target/target_core_rd.h73
-rw-r--r--drivers/target/target_core_scdb.c105
-rw-r--r--drivers/target/target_core_scdb.h10
-rw-r--r--drivers/target/target_core_tmr.c404
-rw-r--r--drivers/target/target_core_tpg.c826
-rw-r--r--drivers/target/target_core_transport.c6134
-rw-r--r--drivers/target/target_core_ua.c332
-rw-r--r--drivers/target/target_core_ua.h36
-rw-r--r--drivers/thermal/Kconfig1
-rw-r--r--drivers/thermal/thermal_sys.c120
-rw-r--r--drivers/tty/Makefile2
-rw-r--r--drivers/tty/hvc/Makefile13
-rw-r--r--drivers/tty/hvc/hvc_beat.c (renamed from drivers/char/hvc_beat.c)0
-rw-r--r--drivers/tty/hvc/hvc_console.c (renamed from drivers/char/hvc_console.c)0
-rw-r--r--drivers/tty/hvc/hvc_console.h (renamed from drivers/char/hvc_console.h)0
-rw-r--r--drivers/tty/hvc/hvc_dcc.c (renamed from drivers/char/hvc_dcc.c)0
-rw-r--r--drivers/tty/hvc/hvc_irq.c (renamed from drivers/char/hvc_irq.c)0
-rw-r--r--drivers/tty/hvc/hvc_iseries.c (renamed from drivers/char/hvc_iseries.c)0
-rw-r--r--drivers/tty/hvc/hvc_iucv.c (renamed from drivers/char/hvc_iucv.c)0
-rw-r--r--drivers/tty/hvc/hvc_rtas.c (renamed from drivers/char/hvc_rtas.c)0
-rw-r--r--drivers/tty/hvc/hvc_tile.c (renamed from drivers/char/hvc_tile.c)0
-rw-r--r--drivers/tty/hvc/hvc_udbg.c (renamed from drivers/char/hvc_udbg.c)0
-rw-r--r--drivers/tty/hvc/hvc_vio.c (renamed from drivers/char/hvc_vio.c)0
-rw-r--r--drivers/tty/hvc/hvc_xen.c (renamed from drivers/char/hvc_xen.c)0
-rw-r--r--drivers/tty/hvc/hvcs.c (renamed from drivers/char/hvcs.c)0
-rw-r--r--drivers/tty/hvc/hvsi.c (renamed from drivers/char/hvsi.c)0
-rw-r--r--drivers/tty/hvc/virtio_console.c (renamed from drivers/char/virtio_console.c)0
-rw-r--r--drivers/tty/serial/21285.c (renamed from drivers/serial/21285.c)0
-rw-r--r--drivers/tty/serial/68328serial.c (renamed from drivers/serial/68328serial.c)0
-rw-r--r--drivers/tty/serial/68328serial.h (renamed from drivers/serial/68328serial.h)0
-rw-r--r--drivers/tty/serial/68360serial.c (renamed from drivers/serial/68360serial.c)0
-rw-r--r--drivers/tty/serial/8250.c (renamed from drivers/serial/8250.c)0
-rw-r--r--drivers/tty/serial/8250.h (renamed from drivers/serial/8250.h)0
-rw-r--r--drivers/tty/serial/8250_accent.c (renamed from drivers/serial/8250_accent.c)0
-rw-r--r--drivers/tty/serial/8250_acorn.c (renamed from drivers/serial/8250_acorn.c)0
-rw-r--r--drivers/tty/serial/8250_boca.c (renamed from drivers/serial/8250_boca.c)0
-rw-r--r--drivers/tty/serial/8250_early.c (renamed from drivers/serial/8250_early.c)0
-rw-r--r--drivers/tty/serial/8250_exar_st16c554.c (renamed from drivers/serial/8250_exar_st16c554.c)0
-rw-r--r--drivers/tty/serial/8250_fourport.c (renamed from drivers/serial/8250_fourport.c)0
-rw-r--r--drivers/tty/serial/8250_gsc.c (renamed from drivers/serial/8250_gsc.c)0
-rw-r--r--drivers/tty/serial/8250_hp300.c (renamed from drivers/serial/8250_hp300.c)0
-rw-r--r--drivers/tty/serial/8250_hub6.c (renamed from drivers/serial/8250_hub6.c)0
-rw-r--r--drivers/tty/serial/8250_mca.c (renamed from drivers/serial/8250_mca.c)0
-rw-r--r--drivers/tty/serial/8250_pci.c (renamed from drivers/serial/8250_pci.c)0
-rw-r--r--drivers/tty/serial/8250_pnp.c (renamed from drivers/serial/8250_pnp.c)0
-rw-r--r--drivers/tty/serial/Kconfig (renamed from drivers/serial/Kconfig)4
-rw-r--r--drivers/tty/serial/Makefile (renamed from drivers/serial/Makefile)0
-rw-r--r--drivers/tty/serial/altera_jtaguart.c (renamed from drivers/serial/altera_jtaguart.c)0
-rw-r--r--drivers/tty/serial/altera_uart.c (renamed from drivers/serial/altera_uart.c)0
-rw-r--r--drivers/tty/serial/amba-pl010.c (renamed from drivers/serial/amba-pl010.c)0
-rw-r--r--drivers/tty/serial/amba-pl011.c (renamed from drivers/serial/amba-pl011.c)0
-rw-r--r--drivers/tty/serial/apbuart.c (renamed from drivers/serial/apbuart.c)0
-rw-r--r--drivers/tty/serial/apbuart.h (renamed from drivers/serial/apbuart.h)0
-rw-r--r--drivers/tty/serial/atmel_serial.c (renamed from drivers/serial/atmel_serial.c)0
-rw-r--r--drivers/tty/serial/bcm63xx_uart.c (renamed from drivers/serial/bcm63xx_uart.c)0
-rw-r--r--drivers/tty/serial/bfin_5xx.c (renamed from drivers/serial/bfin_5xx.c)0
-rw-r--r--drivers/tty/serial/bfin_sport_uart.c (renamed from drivers/serial/bfin_sport_uart.c)0
-rw-r--r--drivers/tty/serial/bfin_sport_uart.h (renamed from drivers/serial/bfin_sport_uart.h)0
-rw-r--r--drivers/tty/serial/clps711x.c (renamed from drivers/serial/clps711x.c)0
-rw-r--r--drivers/tty/serial/cpm_uart/Makefile (renamed from drivers/serial/cpm_uart/Makefile)0
-rw-r--r--drivers/tty/serial/cpm_uart/cpm_uart.h (renamed from drivers/serial/cpm_uart/cpm_uart.h)0
-rw-r--r--drivers/tty/serial/cpm_uart/cpm_uart_core.c (renamed from drivers/serial/cpm_uart/cpm_uart_core.c)0
-rw-r--r--drivers/tty/serial/cpm_uart/cpm_uart_cpm1.c (renamed from drivers/serial/cpm_uart/cpm_uart_cpm1.c)0
-rw-r--r--drivers/tty/serial/cpm_uart/cpm_uart_cpm1.h (renamed from drivers/serial/cpm_uart/cpm_uart_cpm1.h)0
-rw-r--r--drivers/tty/serial/cpm_uart/cpm_uart_cpm2.c (renamed from drivers/serial/cpm_uart/cpm_uart_cpm2.c)0
-rw-r--r--drivers/tty/serial/cpm_uart/cpm_uart_cpm2.h (renamed from drivers/serial/cpm_uart/cpm_uart_cpm2.h)0
-rw-r--r--drivers/tty/serial/crisv10.c (renamed from drivers/serial/crisv10.c)0
-rw-r--r--drivers/tty/serial/crisv10.h (renamed from drivers/serial/crisv10.h)0
-rw-r--r--drivers/tty/serial/dz.c (renamed from drivers/serial/dz.c)0
-rw-r--r--drivers/tty/serial/dz.h (renamed from drivers/serial/dz.h)0
-rw-r--r--drivers/tty/serial/icom.c (renamed from drivers/serial/icom.c)0
-rw-r--r--drivers/tty/serial/icom.h (renamed from drivers/serial/icom.h)0
-rw-r--r--drivers/tty/serial/ifx6x60.c (renamed from drivers/serial/ifx6x60.c)0
-rw-r--r--drivers/tty/serial/ifx6x60.h (renamed from drivers/serial/ifx6x60.h)0
-rw-r--r--drivers/tty/serial/imx.c (renamed from drivers/serial/imx.c)0
-rw-r--r--drivers/tty/serial/ioc3_serial.c (renamed from drivers/serial/ioc3_serial.c)0
-rw-r--r--drivers/tty/serial/ioc4_serial.c (renamed from drivers/serial/ioc4_serial.c)0
-rw-r--r--drivers/tty/serial/ip22zilog.c (renamed from drivers/serial/ip22zilog.c)0
-rw-r--r--drivers/tty/serial/ip22zilog.h (renamed from drivers/serial/ip22zilog.h)0
-rw-r--r--drivers/tty/serial/jsm/Makefile (renamed from drivers/serial/jsm/Makefile)0
-rw-r--r--drivers/tty/serial/jsm/jsm.h (renamed from drivers/serial/jsm/jsm.h)0
-rw-r--r--drivers/tty/serial/jsm/jsm_driver.c (renamed from drivers/serial/jsm/jsm_driver.c)0
-rw-r--r--drivers/tty/serial/jsm/jsm_neo.c (renamed from drivers/serial/jsm/jsm_neo.c)0
-rw-r--r--drivers/tty/serial/jsm/jsm_tty.c (renamed from drivers/serial/jsm/jsm_tty.c)0
-rw-r--r--drivers/tty/serial/kgdboc.c (renamed from drivers/serial/kgdboc.c)0
-rw-r--r--drivers/tty/serial/m32r_sio.c (renamed from drivers/serial/m32r_sio.c)0
-rw-r--r--drivers/tty/serial/m32r_sio.h (renamed from drivers/serial/m32r_sio.h)0
-rw-r--r--drivers/tty/serial/m32r_sio_reg.h (renamed from drivers/serial/m32r_sio_reg.h)0
-rw-r--r--drivers/tty/serial/max3100.c (renamed from drivers/serial/max3100.c)0
-rw-r--r--drivers/tty/serial/max3107-aava.c (renamed from drivers/serial/max3107-aava.c)0
-rw-r--r--drivers/tty/serial/max3107.c (renamed from drivers/serial/max3107.c)0
-rw-r--r--drivers/tty/serial/max3107.h (renamed from drivers/serial/max3107.h)0
-rw-r--r--drivers/tty/serial/mcf.c (renamed from drivers/serial/mcf.c)0
-rw-r--r--drivers/tty/serial/mfd.c (renamed from drivers/serial/mfd.c)0
-rw-r--r--drivers/tty/serial/mpc52xx_uart.c (renamed from drivers/serial/mpc52xx_uart.c)0
-rw-r--r--drivers/tty/serial/mpsc.c (renamed from drivers/serial/mpsc.c)0
-rw-r--r--drivers/tty/serial/mrst_max3110.c (renamed from drivers/serial/mrst_max3110.c)0
-rw-r--r--drivers/tty/serial/mrst_max3110.h (renamed from drivers/serial/mrst_max3110.h)0
-rw-r--r--drivers/tty/serial/msm_serial.c (renamed from drivers/serial/msm_serial.c)0
-rw-r--r--drivers/tty/serial/msm_serial.h (renamed from drivers/serial/msm_serial.h)0
-rw-r--r--drivers/tty/serial/mux.c (renamed from drivers/serial/mux.c)0
-rw-r--r--drivers/tty/serial/netx-serial.c (renamed from drivers/serial/netx-serial.c)0
-rw-r--r--drivers/tty/serial/nwpserial.c (renamed from drivers/serial/nwpserial.c)0
-rw-r--r--drivers/tty/serial/of_serial.c (renamed from drivers/serial/of_serial.c)0
-rw-r--r--drivers/tty/serial/omap-serial.c (renamed from drivers/serial/omap-serial.c)0
-rw-r--r--drivers/tty/serial/pch_uart.c (renamed from drivers/serial/pch_uart.c)0
-rw-r--r--drivers/tty/serial/pmac_zilog.c (renamed from drivers/serial/pmac_zilog.c)0
-rw-r--r--drivers/tty/serial/pmac_zilog.h (renamed from drivers/serial/pmac_zilog.h)0
-rw-r--r--drivers/tty/serial/pnx8xxx_uart.c (renamed from drivers/serial/pnx8xxx_uart.c)0
-rw-r--r--drivers/tty/serial/pxa.c (renamed from drivers/serial/pxa.c)0
-rw-r--r--drivers/tty/serial/s3c2400.c (renamed from drivers/serial/s3c2400.c)0
-rw-r--r--drivers/tty/serial/s3c2410.c (renamed from drivers/serial/s3c2410.c)0
-rw-r--r--drivers/tty/serial/s3c2412.c (renamed from drivers/serial/s3c2412.c)0
-rw-r--r--drivers/tty/serial/s3c2440.c (renamed from drivers/serial/s3c2440.c)0
-rw-r--r--drivers/tty/serial/s3c24a0.c (renamed from drivers/serial/s3c24a0.c)0
-rw-r--r--drivers/tty/serial/s3c6400.c (renamed from drivers/serial/s3c6400.c)0
-rw-r--r--drivers/tty/serial/s5pv210.c (renamed from drivers/serial/s5pv210.c)0
-rw-r--r--drivers/tty/serial/sa1100.c (renamed from drivers/serial/sa1100.c)0
-rw-r--r--drivers/tty/serial/samsung.c (renamed from drivers/serial/samsung.c)4
-rw-r--r--drivers/tty/serial/samsung.h (renamed from drivers/serial/samsung.h)0
-rw-r--r--drivers/tty/serial/sb1250-duart.c (renamed from drivers/serial/sb1250-duart.c)0
-rw-r--r--drivers/tty/serial/sc26xx.c (renamed from drivers/serial/sc26xx.c)0
-rw-r--r--drivers/tty/serial/serial_core.c (renamed from drivers/serial/serial_core.c)0
-rw-r--r--drivers/tty/serial/serial_cs.c (renamed from drivers/serial/serial_cs.c)0
-rw-r--r--drivers/tty/serial/serial_ks8695.c (renamed from drivers/serial/serial_ks8695.c)0
-rw-r--r--drivers/tty/serial/serial_lh7a40x.c (renamed from drivers/serial/serial_lh7a40x.c)0
-rw-r--r--drivers/tty/serial/serial_txx9.c (renamed from drivers/serial/serial_txx9.c)0
-rw-r--r--drivers/tty/serial/sh-sci.c (renamed from drivers/serial/sh-sci.c)0
-rw-r--r--drivers/tty/serial/sh-sci.h (renamed from drivers/serial/sh-sci.h)0
-rw-r--r--drivers/tty/serial/sn_console.c (renamed from drivers/serial/sn_console.c)0
-rw-r--r--drivers/tty/serial/suncore.c (renamed from drivers/serial/suncore.c)0
-rw-r--r--drivers/tty/serial/suncore.h (renamed from drivers/serial/suncore.h)0
-rw-r--r--drivers/tty/serial/sunhv.c (renamed from drivers/serial/sunhv.c)0
-rw-r--r--drivers/tty/serial/sunsab.c (renamed from drivers/serial/sunsab.c)0
-rw-r--r--drivers/tty/serial/sunsab.h (renamed from drivers/serial/sunsab.h)0
-rw-r--r--drivers/tty/serial/sunsu.c (renamed from drivers/serial/sunsu.c)0
-rw-r--r--drivers/tty/serial/sunzilog.c (renamed from drivers/serial/sunzilog.c)0
-rw-r--r--drivers/tty/serial/sunzilog.h (renamed from drivers/serial/sunzilog.h)0
-rw-r--r--drivers/tty/serial/timbuart.c (renamed from drivers/serial/timbuart.c)0
-rw-r--r--drivers/tty/serial/timbuart.h (renamed from drivers/serial/timbuart.h)0
-rw-r--r--drivers/tty/serial/uartlite.c (renamed from drivers/serial/uartlite.c)0
-rw-r--r--drivers/tty/serial/ucc_uart.c (renamed from drivers/serial/ucc_uart.c)0
-rw-r--r--drivers/tty/serial/vr41xx_siu.c (renamed from drivers/serial/vr41xx_siu.c)0
-rw-r--r--drivers/tty/serial/vt8500_serial.c (renamed from drivers/serial/vt8500_serial.c)0
-rw-r--r--drivers/tty/serial/zs.c (renamed from drivers/serial/zs.c)0
-rw-r--r--drivers/tty/serial/zs.h (renamed from drivers/serial/zs.h)0
-rw-r--r--drivers/usb/core/Kconfig6
-rw-r--r--drivers/vhost/vhost.c18
-rw-r--r--drivers/video/Kconfig2
-rw-r--r--drivers/video/backlight/88pm860x_bl.c4
-rw-r--r--drivers/video/console/Kconfig2
-rw-r--r--drivers/video/ep93xx-fb.c6
-rw-r--r--drivers/virtio/virtio_pci.c20
-rw-r--r--drivers/xen/xenfs/xenbus.c31
-rw-r--r--fs/Kconfig19
-rw-r--r--fs/afs/cmservice.c12
-rw-r--r--fs/afs/dir.c1
-rw-r--r--fs/afs/inode.c3
-rw-r--r--fs/afs/internal.h2
-rw-r--r--fs/afs/main.c13
-rw-r--r--fs/afs/mntpt.c63
-rw-r--r--fs/afs/rxrpc.c2
-rw-r--r--fs/afs/server.c13
-rw-r--r--fs/afs/vlocation.c14
-rw-r--r--fs/aio.c2
-rw-r--r--fs/anon_inodes.c2
-rw-r--r--fs/autofs4/autofs_i.h113
-rw-r--r--fs/autofs4/dev-ioctl.c2
-rw-r--r--fs/autofs4/expire.c55
-rw-r--r--fs/autofs4/inode.c114
-rw-r--r--fs/autofs4/root.c743
-rw-r--r--fs/autofs4/symlink.c3
-rw-r--r--fs/autofs4/waitq.c17
-rw-r--r--fs/block_dev.c93
-rw-r--r--fs/btrfs/Kconfig2
-rw-r--r--fs/btrfs/Makefile2
-rw-r--r--fs/btrfs/acl.c4
-rw-r--r--fs/btrfs/btrfs_inode.h2
-rw-r--r--fs/btrfs/compression.c329
-rw-r--r--fs/btrfs/compression.h72
-rw-r--r--fs/btrfs/ctree.c8
-rw-r--r--fs/btrfs/ctree.h49
-rw-r--r--fs/btrfs/disk-io.c412
-rw-r--r--fs/btrfs/disk-io.h1
-rw-r--r--fs/btrfs/extent-tree.c90
-rw-r--r--fs/btrfs/extent_io.c7
-rw-r--r--fs/btrfs/extent_io.h17
-rw-r--r--fs/btrfs/extent_map.c2
-rw-r--r--fs/btrfs/extent_map.h3
-rw-r--r--fs/btrfs/file.c126
-rw-r--r--fs/btrfs/inode.c201
-rw-r--r--fs/btrfs/ioctl.c220
-rw-r--r--fs/btrfs/ioctl.h12
-rw-r--r--fs/btrfs/lzo.c420
-rw-r--r--fs/btrfs/ordered-data.c18
-rw-r--r--fs/btrfs/ordered-data.h8
-rw-r--r--fs/btrfs/super.c281
-rw-r--r--fs/btrfs/transaction.c11
-rw-r--r--fs/btrfs/transaction.h1
-rw-r--r--fs/btrfs/volumes.c626
-rw-r--r--fs/btrfs/volumes.h27
-rw-r--r--fs/btrfs/xattr.c18
-rw-r--r--fs/btrfs/zlib.c369
-rw-r--r--fs/cifs/cifs_debug.c10
-rw-r--r--fs/cifs/cifs_dfs_ref.c119
-rw-r--r--fs/cifs/cifs_fs_sb.h1
-rw-r--r--fs/cifs/cifs_unicode.c127
-rw-r--r--fs/cifs/cifsacl.c13
-rw-r--r--fs/cifs/cifsfs.c44
-rw-r--r--fs/cifs/cifsfs.h21
-rw-r--r--fs/cifs/cifsglob.h97
-rw-r--r--fs/cifs/cifspdu.h62
-rw-r--r--fs/cifs/cifsproto.h9
-rw-r--r--fs/cifs/cifssmb.c113
-rw-r--r--fs/cifs/connect.c204
-rw-r--r--fs/cifs/dir.c2
-rw-r--r--fs/cifs/file.c289
-rw-r--r--fs/cifs/inode.c16
-rw-r--r--fs/cifs/misc.c73
-rw-r--r--fs/cifs/netmisc.c8
-rw-r--r--fs/cifs/sess.c15
-rw-r--r--fs/cifs/transport.c434
-rw-r--r--fs/compat.c10
-rw-r--r--fs/configfs/Kconfig4
-rw-r--r--fs/dcache.c13
-rw-r--r--fs/direct-io.c10
-rw-r--r--fs/dlm/Kconfig3
-rw-r--r--fs/ecryptfs/crypto.c30
-rw-r--r--fs/ecryptfs/ecryptfs_kernel.h2
-rw-r--r--fs/ecryptfs/file.c28
-rw-r--r--fs/ecryptfs/inode.c32
-rw-r--r--fs/ecryptfs/keystore.c26
-rw-r--r--fs/ecryptfs/main.c9
-rw-r--r--fs/ecryptfs/mmap.c35
-rw-r--r--fs/ext3/super.c25
-rw-r--r--fs/ext4/ext4.h2
-rw-r--r--fs/ext4/extents.c11
-rw-r--r--fs/ext4/file.c2
-rw-r--r--fs/ext4/super.c25
-rw-r--r--fs/file_table.c2
-rw-r--r--fs/fs_struct.c35
-rw-r--r--fs/fscache/operation.c2
-rw-r--r--fs/gfs2/file.c258
-rw-r--r--fs/gfs2/inode.c72
-rw-r--r--fs/gfs2/inode.h1
-rw-r--r--fs/gfs2/ops_inode.c258
-rw-r--r--fs/gfs2/super.c1
-rw-r--r--fs/hpfs/inode.c2
-rw-r--r--fs/internal.h4
-rw-r--r--fs/ioctl.c10
-rw-r--r--fs/jffs2/build.c5
-rw-r--r--fs/jffs2/jffs2_fs_sb.h2
-rw-r--r--fs/jffs2/xattr.c12
-rw-r--r--fs/locks.c8
-rw-r--r--fs/namei.c417
-rw-r--r--fs/namespace.c223
-rw-r--r--fs/nfs/dir.c10
-rw-r--r--fs/nfs/inode.c4
-rw-r--r--fs/nfs/internal.h1
-rw-r--r--fs/nfs/namespace.c77
-rw-r--r--fs/nfsd/acl.h (renamed from include/linux/nfs4_acl.h)2
-rw-r--r--fs/nfsd/export.c4
-rw-r--r--fs/nfsd/idmap.h (renamed from include/linux/nfsd_idmap.h)6
-rw-r--r--fs/nfsd/nfs3proc.c8
-rw-r--r--fs/nfsd/nfs4acl.c2
-rw-r--r--fs/nfsd/nfs4callback.c151
-rw-r--r--fs/nfsd/nfs4idmap.c15
-rw-r--r--fs/nfsd/nfs4proc.c59
-rw-r--r--fs/nfsd/nfs4recover.c1
-rw-r--r--fs/nfsd/nfs4state.c243
-rw-r--r--fs/nfsd/nfs4xdr.c115
-rw-r--r--fs/nfsd/nfsctl.c4
-rw-r--r--fs/nfsd/nfsd.h1
-rw-r--r--fs/nfsd/nfsproc.c6
-rw-r--r--fs/nfsd/nfssvc.c2
-rw-r--r--fs/nfsd/state.h16
-rw-r--r--fs/nfsd/vfs.c90
-rw-r--r--fs/nfsd/xdr4.h9
-rw-r--r--fs/ocfs2/Kconfig3
-rw-r--r--fs/ocfs2/file.c10
-rw-r--r--fs/ocfs2/super.c5
-rw-r--r--fs/open.c4
-rw-r--r--fs/pipe.c12
-rw-r--r--fs/proc/Kconfig6
-rw-r--r--fs/quota/dquot.c18
-rw-r--r--fs/quota/quota.c41
-rw-r--r--fs/reiserfs/super.c17
-rw-r--r--fs/squashfs/Kconfig18
-rw-r--r--fs/squashfs/Makefile1
-rw-r--r--fs/squashfs/block.c1
-rw-r--r--fs/squashfs/cache.c1
-rw-r--r--fs/squashfs/decompressor.c16
-rw-r--r--fs/squashfs/decompressor.h9
-rw-r--r--fs/squashfs/fragment.c1
-rw-r--r--fs/squashfs/id.c1
-rw-r--r--fs/squashfs/lzo_wrapper.c1
-rw-r--r--fs/squashfs/squashfs.h8
-rw-r--r--fs/squashfs/squashfs_fs.h1
-rw-r--r--fs/squashfs/squashfs_fs_i.h6
-rw-r--r--fs/squashfs/xattr_id.c1
-rw-r--r--fs/squashfs/xz_wrapper.c153
-rw-r--r--fs/squashfs/zlib_wrapper.c15
-rw-r--r--fs/stat.c4
-rw-r--r--fs/super.c2
-rw-r--r--fs/sysfs/Kconfig2
-rw-r--r--fs/xfs/Makefile1
-rw-r--r--fs/xfs/linux-2.6/xfs_buf.c7
-rw-r--r--fs/xfs/linux-2.6/xfs_buf.h7
-rw-r--r--fs/xfs/linux-2.6/xfs_discard.c191
-rw-r--r--fs/xfs/linux-2.6/xfs_discard.h8
-rw-r--r--fs/xfs/linux-2.6/xfs_file.c587
-rw-r--r--fs/xfs/linux-2.6/xfs_ioctl.c3
-rw-r--r--fs/xfs/linux-2.6/xfs_iops.c57
-rw-r--r--fs/xfs/linux-2.6/xfs_super.c2
-rw-r--r--fs/xfs/linux-2.6/xfs_sync.c11
-rw-r--r--fs/xfs/linux-2.6/xfs_sysctl.c23
-rw-r--r--fs/xfs/linux-2.6/xfs_trace.h33
-rw-r--r--fs/xfs/support/debug.c112
-rw-r--r--fs/xfs/support/debug.h25
-rw-r--r--fs/xfs/xfs_alloc.c10
-rw-r--r--fs/xfs/xfs_alloc.h25
-rw-r--r--fs/xfs/xfs_buf_item.c151
-rw-r--r--fs/xfs/xfs_error.c31
-rw-r--r--fs/xfs/xfs_error.h18
-rw-r--r--fs/xfs/xfs_fsops.c10
-rw-r--r--fs/xfs/xfs_fsops.h2
-rw-r--r--fs/xfs/xfs_log.c2
-rw-r--r--fs/xfs/xfs_log_recover.c2
-rw-r--r--fs/xfs/xfs_trans.c2
-rw-r--r--include/acpi/acexcep.h2
-rw-r--r--include/acpi/acnames.h2
-rw-r--r--include/acpi/acoutput.h2
-rw-r--r--include/acpi/acpi.h2
-rw-r--r--include/acpi/acpi_bus.h12
-rw-r--r--include/acpi/acpiosxf.h2
-rw-r--r--include/acpi/acpixf.h22
-rw-r--r--include/acpi/acrestyp.h2
-rw-r--r--include/acpi/actbl.h2
-rw-r--r--include/acpi/actbl1.h2
-rw-r--r--include/acpi/actbl2.h2
-rw-r--r--include/acpi/actypes.h54
-rw-r--r--include/acpi/apei.h6
-rw-r--r--include/acpi/platform/acenv.h2
-rw-r--r--include/acpi/platform/acgcc.h2
-rw-r--r--include/acpi/platform/aclinux.h2
-rw-r--r--include/acpi/processor.h6
-rw-r--r--include/asm-generic/pgtable.h14
-rw-r--r--include/asm-generic/vmlinux.lds.h7
-rw-r--r--include/drm/drm_fb_helper.h3
-rw-r--r--include/drm/radeon_drm.h1
-rw-r--r--include/linux/acpi.h13
-rw-r--r--include/linux/acpi_io.h16
-rw-r--r--include/linux/amba/pl08x.h99
-rw-r--r--include/linux/auto_fs4.h2
-rw-r--r--include/linux/cper.h86
-rw-r--r--include/linux/cpuidle.h6
-rw-r--r--include/linux/dcache.h16
-rw-r--r--include/linux/dmaengine.h2
-rw-r--r--include/linux/etherdevice.h11
-rw-r--r--include/linux/fcntl.h1
-rw-r--r--include/linux/file.h2
-rw-r--r--include/linux/fs.h19
-rw-r--r--include/linux/gfp.h2
-rw-r--r--include/linux/gpio.h4
-rw-r--r--include/linux/ieee80211.h2
-rw-r--r--include/linux/ipmi.h38
-rw-r--r--include/linux/ipmi_smi.h8
-rw-r--r--include/linux/irqdesc.h14
-rw-r--r--include/linux/kernel.h34
-rw-r--r--include/linux/kmemcheck.h2
-rw-r--r--include/linux/list_bl.h3
-rw-r--r--include/linux/lockdep.h11
-rw-r--r--include/linux/magic.h1
-rw-r--r--include/linux/memcontrol.h9
-rw-r--r--include/linux/memory_hotplug.h6
-rw-r--r--include/linux/mfd/ab8500.h53
-rw-r--r--include/linux/mfd/core.h6
-rw-r--r--include/linux/mfd/max8998-private.h2
-rw-r--r--include/linux/mfd/max8998.h31
-rw-r--r--include/linux/mfd/wm831x/core.h1
-rw-r--r--include/linux/mlx4/device.h10
-rw-r--r--include/linux/mlx4/driver.h6
-rw-r--r--include/linux/mm.h2
-rw-r--r--include/linux/module.h27
-rw-r--r--include/linux/moduleparam.h6
-rw-r--r--include/linux/mount.h11
-rw-r--r--include/linux/mtd/cfi.h3
-rw-r--r--include/linux/mtd/fsmc.h26
-rw-r--r--include/linux/mtd/mtd.h11
-rw-r--r--include/linux/mtd/nand.h2
-rw-r--r--include/linux/mtd/onenand.h14
-rw-r--r--include/linux/mtd/partitions.h2
-rw-r--r--include/linux/namei.h5
-rw-r--r--include/linux/netdevice.h5
-rw-r--r--include/linux/nfs4.h6
-rw-r--r--include/linux/nfs_fs.h1
-rw-r--r--include/linux/nfsd/export.h2
-rw-r--r--include/linux/nl80211.h20
-rw-r--r--include/linux/of_fdt.h2
-rw-r--r--include/linux/page_cgroup.h23
-rw-r--r--include/linux/path.h2
-rw-r--r--include/linux/pci-acpi.h7
-rw-r--r--include/linux/pci-aspm.h5
-rw-r--r--include/linux/pci.h25
-rw-r--r--include/linux/pci_ids.h3
-rw-r--r--include/linux/pci_regs.h10
-rw-r--r--include/linux/power/gpio-charger.h41
-rw-r--r--include/linux/power/max17042_battery.h30
-rw-r--r--include/linux/quota.h5
-rw-r--r--include/linux/quotaops.h4
-rw-r--r--include/linux/rculist_bl.h3
-rw-r--r--include/linux/rtc.h4
-rw-r--r--include/linux/s3c_adc_battery.h1
-rw-r--r--include/linux/skbuff.h15
-rw-r--r--include/linux/sunrpc/cache.h3
-rw-r--r--include/linux/sunrpc/svc.h1
-rw-r--r--include/linux/sunrpc/svc_xprt.h2
-rw-r--r--include/linux/sunrpc/svcsock.h1
-rw-r--r--include/linux/sunrpc/xprt.h1
-rw-r--r--include/linux/suspend.h17
-rw-r--r--include/linux/thermal.h47
-rw-r--r--include/linux/virtio_config.h5
-rw-r--r--include/media/mt9v011.h17
-rw-r--r--include/media/rc-core.h3
-rw-r--r--include/media/saa7146.h2
-rw-r--r--include/media/v4l2-common.h13
-rw-r--r--include/media/v4l2-ctrls.h7
-rw-r--r--include/media/v4l2-subdev.h23
-rw-r--r--include/net/ah.h2
-rw-r--r--include/net/cfg80211.h2
-rw-r--r--include/net/mac80211.h14
-rw-r--r--include/net/netfilter/ipv6/nf_conntrack_ipv6.h10
-rw-r--r--include/net/netfilter/ipv6/nf_defrag_ipv6.h10
-rw-r--r--include/net/red.h1
-rw-r--r--include/net/sctp/user.h1
-rw-r--r--include/rdma/ib_verbs.h3
-rw-r--r--include/sound/ac97_codec.h2
-rw-r--r--include/target/configfs_macros.h147
-rw-r--r--include/target/target_core_base.h937
-rw-r--r--include/target/target_core_configfs.h52
-rw-r--r--include/target/target_core_device.h61
-rw-r--r--include/target/target_core_fabric_configfs.h106
-rw-r--r--include/target/target_core_fabric_lib.h28
-rw-r--r--include/target/target_core_fabric_ops.h100
-rw-r--r--include/target/target_core_tmr.h43
-rw-r--r--include/target/target_core_tpg.h35
-rw-r--r--include/target/target_core_transport.h351
-rw-r--r--include/trace/events/module.h10
-rw-r--r--init/Kconfig75
-rw-r--r--init/main.c13
-rw-r--r--kernel/cgroup.c19
-rw-r--r--kernel/futex.c7
-rw-r--r--kernel/irq/Kconfig3
-rw-r--r--kernel/irq/handle.c111
-rw-r--r--kernel/lockdep.c18
-rw-r--r--kernel/panic.c1
-rw-r--r--kernel/params.c65
-rw-r--r--kernel/perf_event.c69
-rw-r--r--kernel/power/Kconfig5
-rw-r--r--kernel/power/Makefile1
-rw-r--r--kernel/rcutiny.c3
-rw-r--r--kernel/sched.c26
-rw-r--r--kernel/sched_autogroup.c32
-rw-r--r--kernel/sched_autogroup.h4
-rw-r--r--kernel/sched_debug.c42
-rw-r--r--kernel/sched_fair.c113
-rw-r--r--kernel/smp.c62
-rw-r--r--kernel/srcu.c15
-rw-r--r--kernel/time/clocksource.c8
-rw-r--r--kernel/time/tick-sched.c7
-rw-r--r--kernel/time/timekeeping.c4
-rw-r--r--kernel/trace/trace_irqsoff.c8
-rw-r--r--kernel/trace/trace_syscalls.c33
-rw-r--r--kernel/workqueue.c20
-rw-r--r--lib/Kconfig.debug6
-rw-r--r--lib/ioremap.c2
-rw-r--r--lib/xz/Kconfig12
-rw-r--r--mm/compaction.c11
-rw-r--r--mm/huge_memory.c5
-rw-r--r--mm/internal.h9
-rw-r--r--mm/memblock.c8
-rw-r--r--mm/memcontrol.c190
-rw-r--r--mm/memory_hotplug.c4
-rw-r--r--mm/pgtable-generic.c11
-rw-r--r--mm/slab.c6
-rw-r--r--mm/slub.c4
-rw-r--r--mm/swap.c191
-rw-r--r--mm/truncate.c11
-rw-r--r--mm/vmalloc.c1
-rw-r--r--mm/vmscan.c7
-rw-r--r--net/ax25/af_ax25.c2
-rw-r--r--net/batman-adv/main.h6
-rw-r--r--net/batman-adv/packet.h14
-rw-r--r--net/batman-adv/types.h4
-rw-r--r--net/batman-adv/unicast.c6
-rw-r--r--net/caif/cfcnfg.c9
-rw-r--r--net/can/bcm.c3
-rw-r--r--net/can/raw.c3
-rw-r--r--net/core/dev.c35
-rw-r--r--net/core/rtnetlink.c2
-rw-r--r--net/core/skbuff.c2
-rw-r--r--net/dsa/dsa.c2
-rw-r--r--net/ethernet/eth.c2
-rw-r--r--net/ipv4/inet_diag.c2
-rw-r--r--net/ipv6/addrconf.c3
-rw-r--r--net/ipv6/ip6_output.c3
-rw-r--r--net/ipv6/netfilter/nf_defrag_ipv6_hooks.c8
-rw-r--r--net/mac80211/Kconfig6
-rw-r--r--net/mac80211/agg-rx.c11
-rw-r--r--net/mac80211/main.c12
-rw-r--r--net/netfilter/nf_conntrack_netlink.c7
-rw-r--r--net/netlink/genetlink.c2
-rw-r--r--net/rfkill/Kconfig4
-rw-r--r--net/rxrpc/af_rxrpc.c2
-rw-r--r--net/sched/sch_teql.c26
-rw-r--r--net/sctp/socket.c4
-rw-r--r--net/sunrpc/auth_gss/gss_krb5_crypto.c2
-rw-r--r--net/sunrpc/auth_gss/svcauth_gss.c2
-rw-r--r--net/sunrpc/cache.c54
-rw-r--r--net/sunrpc/svc.c3
-rw-r--r--net/sunrpc/svc_xprt.c97
-rw-r--r--net/sunrpc/svcauth.c1
-rw-r--r--net/sunrpc/svcauth_unix.c17
-rw-r--r--net/sunrpc/svcsock.c20
-rw-r--r--net/sunrpc/xprt.c5
-rw-r--r--net/sunrpc/xprtsock.c34
-rw-r--r--net/wireless/Kconfig2
-rw-r--r--net/xfrm/xfrm_user.c2
-rw-r--r--security/keys/Makefile4
-rw-r--r--security/keys/compat.c17
-rw-r--r--security/keys/encrypted.c (renamed from security/keys/encrypted_defined.c)2
-rw-r--r--security/keys/encrypted.h (renamed from security/keys/encrypted_defined.h)0
-rw-r--r--security/keys/gc.c14
-rw-r--r--security/keys/internal.h32
-rw-r--r--security/keys/key.c328
-rw-r--r--security/keys/keyctl.c355
-rw-r--r--security/keys/keyring.c326
-rw-r--r--security/keys/permission.c33
-rw-r--r--security/keys/proc.c17
-rw-r--r--security/keys/process_keys.c135
-rw-r--r--security/keys/request_key.c166
-rw-r--r--security/keys/request_key_auth.c62
-rw-r--r--security/keys/trusted.c (renamed from security/keys/trusted_defined.c)54
-rw-r--r--security/keys/trusted.h (renamed from security/keys/trusted_defined.h)0
-rw-r--r--security/keys/user_defined.c32
-rw-r--r--security/selinux/ss/conditional.c2
-rw-r--r--security/selinux/ss/policydb.c4
-rw-r--r--sound/pci/ac97/ac97_codec.c2
-rw-r--r--sound/pci/ac97/ac97_patch.c62
-rw-r--r--sound/pci/au88x0/au88x0_pcm.c24
-rw-r--r--sound/pci/cs5535audio/cs5535audio_pm.c7
-rw-r--r--sound/pci/hda/hda_codec.c10
-rw-r--r--sound/pci/hda/hda_generic.c7
-rw-r--r--sound/pci/hda/hda_intel.c2
-rw-r--r--sound/pci/hda/hda_local.h6
-rw-r--r--sound/pci/hda/hda_proc.c2
-rw-r--r--sound/pci/hda/patch_analog.c208
-rw-r--r--sound/pci/hda/patch_cirrus.c4
-rw-r--r--sound/pci/hda/patch_cmedia.c2
-rw-r--r--sound/pci/hda/patch_conexant.c14
-rw-r--r--sound/pci/hda/patch_hdmi.c12
-rw-r--r--sound/pci/hda/patch_realtek.c391
-rw-r--r--sound/pci/hda/patch_sigmatel.c89
-rw-r--r--sound/pci/hda/patch_via.c28
-rw-r--r--sound/pci/ice1712/delta.c7
-rw-r--r--sound/pci/oxygen/xonar_dg.c2
-rw-r--r--sound/soc/blackfin/Kconfig11
-rw-r--r--sound/soc/blackfin/bf5xx-ac97.c4
-rw-r--r--sound/soc/blackfin/bf5xx-tdm.c10
-rw-r--r--sound/soc/codecs/Kconfig2
-rw-r--r--sound/soc/codecs/wl1273.c29
-rw-r--r--sound/soc/codecs/wl1273.h71
-rw-r--r--sound/soc/codecs/wm8990.c10
-rw-r--r--sound/soc/ep93xx/ep93xx-i2s.c18
-rw-r--r--sound/soc/pxa/z2.c3
-rw-r--r--tools/perf/Documentation/perf-record.txt3
-rw-r--r--tools/perf/Makefile9
-rw-r--r--tools/perf/builtin-annotate.c6
-rw-r--r--tools/perf/builtin-kmem.c4
-rw-r--r--tools/perf/builtin-lock.c6
-rw-r--r--tools/perf/builtin-record.c16
-rw-r--r--tools/perf/builtin-report.c2
-rw-r--r--tools/perf/builtin-sched.c38
-rw-r--r--tools/perf/builtin-script.c6
-rw-r--r--tools/perf/builtin-stat.c5
-rw-r--r--tools/perf/builtin-test.c54
-rw-r--r--tools/perf/builtin-top.c14
-rw-r--r--tools/perf/perf.c2
-rw-r--r--tools/perf/util/event.c5
-rw-r--r--tools/perf/util/header.c4
-rw-r--r--tools/perf/util/hist.c17
-rw-r--r--tools/perf/util/include/linux/bitops.h1
-rw-r--r--tools/perf/util/map.c3
-rw-r--r--tools/perf/util/parse-events.c33
-rw-r--r--tools/perf/util/parse-events.h2
-rw-r--r--tools/perf/util/probe-event.c2
-rw-r--r--tools/perf/util/session.c28
-rw-r--r--tools/perf/util/svghelper.c9
-rw-r--r--tools/perf/util/symbol.c16
-rw-r--r--tools/perf/util/types.h10
-rw-r--r--tools/perf/util/ui/browsers/hists.c2
-rw-r--r--tools/perf/util/ui/browsers/map.c5
-rw-r--r--tools/perf/util/values.c10
-rw-r--r--usr/Kconfig18
2100 files changed, 65691 insertions, 20634 deletions
diff --git a/Documentation/ABI/stable/thermal-notification b/Documentation/ABI/stable/thermal-notification
new file mode 100644
index 0000000..9723e8b
--- /dev/null
+++ b/Documentation/ABI/stable/thermal-notification
@@ -0,0 +1,4 @@
+What: A notification mechanism for thermal related events
+Description:
+ This interface enables notification for thermal related events.
+ The notification is in the form of a netlink event.
diff --git a/Documentation/DocBook/80211.tmpl b/Documentation/DocBook/80211.tmpl
index 03641a0..8906648 100644
--- a/Documentation/DocBook/80211.tmpl
+++ b/Documentation/DocBook/80211.tmpl
@@ -268,10 +268,6 @@
!Finclude/net/mac80211.h ieee80211_ops
!Finclude/net/mac80211.h ieee80211_alloc_hw
!Finclude/net/mac80211.h ieee80211_register_hw
-!Finclude/net/mac80211.h ieee80211_get_tx_led_name
-!Finclude/net/mac80211.h ieee80211_get_rx_led_name
-!Finclude/net/mac80211.h ieee80211_get_assoc_led_name
-!Finclude/net/mac80211.h ieee80211_get_radio_led_name
!Finclude/net/mac80211.h ieee80211_unregister_hw
!Finclude/net/mac80211.h ieee80211_free_hw
</chapter>
@@ -382,6 +378,23 @@
</para>
</partintro>
+ <chapter id="led-support">
+ <title>LED support</title>
+ <para>
+ Mac80211 supports various ways of blinking LEDs. Wherever possible,
+ device LEDs should be exposed as LED class devices and hooked up to
+ the appropriate trigger, which will then be triggered appropriately
+ by mac80211.
+ </para>
+!Finclude/net/mac80211.h ieee80211_get_tx_led_name
+!Finclude/net/mac80211.h ieee80211_get_rx_led_name
+!Finclude/net/mac80211.h ieee80211_get_assoc_led_name
+!Finclude/net/mac80211.h ieee80211_get_radio_led_name
+!Finclude/net/mac80211.h ieee80211_tpt_blink
+!Finclude/net/mac80211.h ieee80211_tpt_led_trigger_flags
+!Finclude/net/mac80211.h ieee80211_create_tpt_led_trigger
+ </chapter>
+
<chapter id="hardware-crypto-offload">
<title>Hardware crypto acceleration</title>
!Pinclude/net/mac80211.h Hardware crypto acceleration
diff --git a/Documentation/DocBook/device-drivers.tmpl b/Documentation/DocBook/device-drivers.tmpl
index 35447e0..36f63d4 100644
--- a/Documentation/DocBook/device-drivers.tmpl
+++ b/Documentation/DocBook/device-drivers.tmpl
@@ -217,8 +217,8 @@ X!Isound/sound_firmware.c
<chapter id="uart16x50">
<title>16x50 UART Driver</title>
!Iinclude/linux/serial_core.h
-!Edrivers/serial/serial_core.c
-!Edrivers/serial/8250.c
+!Edrivers/tty/serial/serial_core.c
+!Edrivers/tty/serial/8250.c
</chapter>
<chapter id="fbdev">
diff --git a/Documentation/DocBook/dvb/dvbapi.xml b/Documentation/DocBook/dvb/dvbapi.xml
index e3a97fd..ad8678d 100644
--- a/Documentation/DocBook/dvb/dvbapi.xml
+++ b/Documentation/DocBook/dvb/dvbapi.xml
@@ -28,7 +28,7 @@
<holder>Convergence GmbH</holder>
</copyright>
<copyright>
- <year>2009-2010</year>
+ <year>2009-2011</year>
<holder>Mauro Carvalho Chehab</holder>
</copyright>
diff --git a/Documentation/DocBook/media.tmpl b/Documentation/DocBook/media.tmpl
index f11048d..a99088a 100644
--- a/Documentation/DocBook/media.tmpl
+++ b/Documentation/DocBook/media.tmpl
@@ -28,7 +28,7 @@
<title>LINUX MEDIA INFRASTRUCTURE API</title>
<copyright>
- <year>2009-2010</year>
+ <year>2009-2011</year>
<holder>LinuxTV Developers</holder>
</copyright>
@@ -86,7 +86,7 @@ Foundation. A copy of the license is included in the chapter entitled
</author>
</authorgroup>
<copyright>
- <year>2009-2010</year>
+ <year>2009-2011</year>
<holder>Mauro Carvalho Chehab</holder>
</copyright>
diff --git a/Documentation/DocBook/v4l/dev-rds.xml b/Documentation/DocBook/v4l/dev-rds.xml
index 360d273..2427f54 100644
--- a/Documentation/DocBook/v4l/dev-rds.xml
+++ b/Documentation/DocBook/v4l/dev-rds.xml
@@ -75,6 +75,7 @@ as follows:</para>
</section>
<section>
+ <title>RDS datastructures</title>
<table frame="none" pgwide="1" id="v4l2-rds-data">
<title>struct
<structname>v4l2_rds_data</structname></title>
@@ -129,10 +130,11 @@ as follows:</para>
<table frame="none" pgwide="1" id="v4l2-rds-block-codes">
<title>Block defines</title>
- <tgroup cols="3">
+ <tgroup cols="4">
<colspec colname="c1" colwidth="1*" />
<colspec colname="c2" colwidth="1*" />
- <colspec colname="c3" colwidth="5*" />
+ <colspec colname="c3" colwidth="1*" />
+ <colspec colname="c4" colwidth="5*" />
<tbody valign="top">
<row>
<entry>V4L2_RDS_BLOCK_MSK</entry>
diff --git a/Documentation/DocBook/v4l/v4l2.xml b/Documentation/DocBook/v4l/v4l2.xml
index 839e93e..9288af9 100644
--- a/Documentation/DocBook/v4l/v4l2.xml
+++ b/Documentation/DocBook/v4l/v4l2.xml
@@ -100,6 +100,7 @@ Remote Controller chapter.</contrib>
<year>2008</year>
<year>2009</year>
<year>2010</year>
+ <year>2011</year>
<holder>Bill Dirks, Michael H. Schimek, Hans Verkuil, Martin
Rubli, Andy Walls, Muralidharan Karicheri, Mauro Carvalho Chehab</holder>
</copyright>
@@ -381,7 +382,7 @@ and discussions on the V4L mailing list.</revremark>
</partinfo>
<title>Video for Linux Two API Specification</title>
- <subtitle>Revision 2.6.33</subtitle>
+ <subtitle>Revision 2.6.38</subtitle>
<chapter id="common">
&sub-common;
diff --git a/Documentation/IPMI.txt b/Documentation/IPMI.txt
index 69dd29e..b2bea15 100644
--- a/Documentation/IPMI.txt
+++ b/Documentation/IPMI.txt
@@ -533,6 +533,33 @@ completion during sending a panic event.
Other Pieces
------------
+Get the detailed info related with the IPMI device
+--------------------------------------------------
+
+Some users need more detailed information about a device, like where
+the address came from or the raw base device for the IPMI interface.
+You can use the IPMI smi_watcher to catch the IPMI interfaces as they
+come or go, and to grab the information, you can use the function
+ipmi_get_smi_info(), which returns the following structure:
+
+struct ipmi_smi_info {
+ enum ipmi_addr_src addr_src;
+ struct device *dev;
+ union {
+ struct {
+ void *acpi_handle;
+ } acpi_info;
+ } addr_info;
+};
+
+Currently special info for only for SI_ACPI address sources is
+returned. Others may be added as necessary.
+
+Note that the dev pointer is included in the above structure, and
+assuming ipmi_smi_get_info returns success, you must call put_device
+on the dev pointer.
+
+
Watchdog
--------
diff --git a/Documentation/acpi/apei/output_format.txt b/Documentation/acpi/apei/output_format.txt
new file mode 100644
index 0000000..9146952
--- /dev/null
+++ b/Documentation/acpi/apei/output_format.txt
@@ -0,0 +1,122 @@
+ APEI output format
+ ~~~~~~~~~~~~~~~~~~
+
+APEI uses printk as hardware error reporting interface, the output
+format is as follow.
+
+<error record> :=
+APEI generic hardware error status
+severity: <integer>, <severity string>
+section: <integer>, severity: <integer>, <severity string>
+flags: <integer>
+<section flags strings>
+fru_id: <uuid string>
+fru_text: <string>
+section_type: <section type string>
+<section data>
+
+<severity string>* := recoverable | fatal | corrected | info
+
+<section flags strings># :=
+[primary][, containment warning][, reset][, threshold exceeded]\
+[, resource not accessible][, latent error]
+
+<section type string> := generic processor error | memory error | \
+PCIe error | unknown, <uuid string>
+
+<section data> :=
+<generic processor section data> | <memory section data> | \
+<pcie section data> | <null>
+
+<generic processor section data> :=
+[processor_type: <integer>, <proc type string>]
+[processor_isa: <integer>, <proc isa string>]
+[error_type: <integer>
+<proc error type strings>]
+[operation: <integer>, <proc operation string>]
+[flags: <integer>
+<proc flags strings>]
+[level: <integer>]
+[version_info: <integer>]
+[processor_id: <integer>]
+[target_address: <integer>]
+[requestor_id: <integer>]
+[responder_id: <integer>]
+[IP: <integer>]
+
+<proc type string>* := IA32/X64 | IA64
+
+<proc isa string>* := IA32 | IA64 | X64
+
+<processor error type strings># :=
+[cache error][, TLB error][, bus error][, micro-architectural error]
+
+<proc operation string>* := unknown or generic | data read | data write | \
+instruction execution
+
+<proc flags strings># :=
+[restartable][, precise IP][, overflow][, corrected]
+
+<memory section data> :=
+[error_status: <integer>]
+[physical_address: <integer>]
+[physical_address_mask: <integer>]
+[node: <integer>]
+[card: <integer>]
+[module: <integer>]
+[bank: <integer>]
+[device: <integer>]
+[row: <integer>]
+[column: <integer>]
+[bit_position: <integer>]
+[requestor_id: <integer>]
+[responder_id: <integer>]
+[target_id: <integer>]
+[error_type: <integer>, <mem error type string>]
+
+<mem error type string>* :=
+unknown | no error | single-bit ECC | multi-bit ECC | \
+single-symbol chipkill ECC | multi-symbol chipkill ECC | master abort | \
+target abort | parity error | watchdog timeout | invalid address | \
+mirror Broken | memory sparing | scrub corrected error | \
+scrub uncorrected error
+
+<pcie section data> :=
+[port_type: <integer>, <pcie port type string>]
+[version: <integer>.<integer>]
+[command: <integer>, status: <integer>]
+[device_id: <integer>:<integer>:<integer>.<integer>
+slot: <integer>
+secondary_bus: <integer>
+vendor_id: <integer>, device_id: <integer>
+class_code: <integer>]
+[serial number: <integer>, <integer>]
+[bridge: secondary_status: <integer>, control: <integer>]
+
+<pcie port type string>* := PCIe end point | legacy PCI end point | \
+unknown | unknown | root port | upstream switch port | \
+downstream switch port | PCIe to PCI/PCI-X bridge | \
+PCI/PCI-X to PCIe bridge | root complex integrated endpoint device | \
+root complex event collector
+
+Where, [] designate corresponding content is optional
+
+All <field string> description with * has the following format:
+
+field: <integer>, <field string>
+
+Where value of <integer> should be the position of "string" in <field
+string> description. Otherwise, <field string> will be "unknown".
+
+All <field strings> description with # has the following format:
+
+field: <integer>
+<field strings>
+
+Where each string in <fields strings> corresponding to one set bit of
+<integer>. The bit position is the position of "string" in <field
+strings> description.
+
+For more detailed explanation of every field, please refer to UEFI
+specification version 2.3 or later, section Appendix N: Common
+Platform Error Record.
diff --git a/Documentation/cgroups/memory.txt b/Documentation/cgroups/memory.txt
index bac328c..7781857 100644
--- a/Documentation/cgroups/memory.txt
+++ b/Documentation/cgroups/memory.txt
@@ -385,10 +385,6 @@ mapped_file - # of bytes of mapped file (includes tmpfs/shmem)
pgpgin - # of pages paged in (equivalent to # of charging events).
pgpgout - # of pages paged out (equivalent to # of uncharging events).
swap - # of bytes of swap usage
-dirty - # of bytes that are waiting to get written back to the disk.
-writeback - # of bytes that are actively being written back to the disk.
-nfs_unstable - # of bytes sent to the NFS server, but not yet committed to
- the actual storage.
inactive_anon - # of bytes of anonymous memory and swap cache memory on
LRU list.
active_anon - # of bytes of anonymous and swap cache memory on active
@@ -410,9 +406,6 @@ total_mapped_file - sum of all children's "cache"
total_pgpgin - sum of all children's "pgpgin"
total_pgpgout - sum of all children's "pgpgout"
total_swap - sum of all children's "swap"
-total_dirty - sum of all children's "dirty"
-total_writeback - sum of all children's "writeback"
-total_nfs_unstable - sum of all children's "nfs_unstable"
total_inactive_anon - sum of all children's "inactive_anon"
total_active_anon - sum of all children's "active_anon"
total_inactive_file - sum of all children's "inactive_file"
@@ -460,73 +453,6 @@ memory under it will be reclaimed.
You can reset failcnt by writing 0 to failcnt file.
# echo 0 > .../memory.failcnt
-5.5 dirty memory
-
-Control the maximum amount of dirty pages a cgroup can have at any given time.
-
-Limiting dirty memory is like fixing the max amount of dirty (hard to reclaim)
-page cache used by a cgroup. So, in case of multiple cgroup writers, they will
-not be able to consume more than their designated share of dirty pages and will
-be forced to perform write-out if they cross that limit.
-
-The interface is equivalent to the procfs interface: /proc/sys/vm/dirty_*. It
-is possible to configure a limit to trigger both a direct writeback or a
-background writeback performed by per-bdi flusher threads. The root cgroup
-memory.dirty_* control files are read-only and match the contents of
-the /proc/sys/vm/dirty_* files.
-
-Per-cgroup dirty limits can be set using the following files in the cgroupfs:
-
-- memory.dirty_ratio: the amount of dirty memory (expressed as a percentage of
- cgroup memory) at which a process generating dirty pages will itself start
- writing out dirty data.
-
-- memory.dirty_limit_in_bytes: the amount of dirty memory (expressed in bytes)
- in the cgroup at which a process generating dirty pages will start itself
- writing out dirty data. Suffix (k, K, m, M, g, or G) can be used to indicate
- that value is kilo, mega or gigabytes.
-
- Note: memory.dirty_limit_in_bytes is the counterpart of memory.dirty_ratio.
- Only one of them may be specified at a time. When one is written it is
- immediately taken into account to evaluate the dirty memory limits and the
- other appears as 0 when read.
-
-- memory.dirty_background_ratio: the amount of dirty memory of the cgroup
- (expressed as a percentage of cgroup memory) at which background writeback
- kernel threads will start writing out dirty data.
-
-- memory.dirty_background_limit_in_bytes: the amount of dirty memory (expressed
- in bytes) in the cgroup at which background writeback kernel threads will
- start writing out dirty data. Suffix (k, K, m, M, g, or G) can be used to
- indicate that value is kilo, mega or gigabytes.
-
- Note: memory.dirty_background_limit_in_bytes is the counterpart of
- memory.dirty_background_ratio. Only one of them may be specified at a time.
- When one is written it is immediately taken into account to evaluate the dirty
- memory limits and the other appears as 0 when read.
-
-A cgroup may contain more dirty memory than its dirty limit. This is possible
-because of the principle that the first cgroup to touch a page is charged for
-it. Subsequent page counting events (dirty, writeback, nfs_unstable) are also
-counted to the originally charged cgroup.
-
-Example: If page is allocated by a cgroup A task, then the page is charged to
-cgroup A. If the page is later dirtied by a task in cgroup B, then the cgroup A
-dirty count will be incremented. If cgroup A is over its dirty limit but cgroup
-B is not, then dirtying a cgroup A page from a cgroup B task may push cgroup A
-over its dirty limit without throttling the dirtying cgroup B task.
-
-When use_hierarchy=0, each cgroup has dirty memory usage and limits.
-System-wide dirty limits are also consulted. Dirty memory consumption is
-checked against both system-wide and per-cgroup dirty limits.
-
-The current implementation does not enforce per-cgroup dirty limits when
-use_hierarchy=1. System-wide dirty limits are used for processes in such
-cgroups. Attempts to read memory.dirty_* files return the system-wide
-values. Writes to the memory.dirty_* files return error. An enhanced
-implementation is needed to check the chain of parents to ensure that no
-dirty limit is exceeded.
-
6. Hierarchy support
The memory controller supports a deep hierarchy and hierarchical accounting.
diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt
index 6cbbd20..b959659 100644
--- a/Documentation/feature-removal-schedule.txt
+++ b/Documentation/feature-removal-schedule.txt
@@ -248,6 +248,17 @@ Who: Zhang Rui <rui.zhang@intel.com>
---------------------------
+What: CONFIG_ACPI_PROCFS_POWER
+When: 2.6.39
+Why: sysfs I/F for ACPI power devices, including AC and Battery,
+ has been working in upstream kenrel since 2.6.24, Sep 2007.
+ In 2.6.37, we make the sysfs I/F always built in and this option
+ disabled by default.
+ Remove this option and the ACPI power procfs interface in 2.6.39.
+Who: Zhang Rui <rui.zhang@intel.com>
+
+---------------------------
+
What: /proc/acpi/button
When: August 2007
Why: /proc/acpi/button has been replaced by events to the input layer
@@ -346,14 +357,6 @@ Who: Dave Jones <davej@redhat.com>, Matthew Garrett <mjg@redhat.com>
-----------------------------
-What: __do_IRQ all in one fits nothing interrupt handler
-When: 2.6.32
-Why: __do_IRQ was kept for easy migration to the type flow handlers.
- More than two years of migration time is enough.
-Who: Thomas Gleixner <tglx@linutronix.de>
-
------------------------------
-
What: fakephp and associated sysfs files in /sys/bus/pci/slots/
When: 2011
Why: In 2.6.27, the semantics of /sys/bus/pci/slots was redefined to
diff --git a/Documentation/filesystems/Locking b/Documentation/filesystems/Locking
index 977d891..4471a41 100644
--- a/Documentation/filesystems/Locking
+++ b/Documentation/filesystems/Locking
@@ -19,6 +19,8 @@ prototypes:
void (*d_release)(struct dentry *);
void (*d_iput)(struct dentry *, struct inode *);
char *(*d_dname)((struct dentry *dentry, char *buffer, int buflen);
+ struct vfsmount *(*d_automount)(struct path *path);
+ int (*d_manage)(struct dentry *, bool);
locking rules:
rename_lock ->d_lock may block rcu-walk
@@ -29,6 +31,8 @@ d_delete: no yes no no
d_release: no no yes no
d_iput: no no yes no
d_dname: no no no no
+d_automount: no no yes no
+d_manage: no no yes (ref-walk) maybe
--------------------------- inode_operations ---------------------------
prototypes:
@@ -56,7 +60,6 @@ ata *);
ssize_t (*listxattr) (struct dentry *, char *, size_t);
int (*removexattr) (struct dentry *, const char *);
void (*truncate_range)(struct inode *, loff_t, loff_t);
- long (*fallocate)(struct inode *inode, int mode, loff_t offset, loff_t len);
int (*fiemap)(struct inode *, struct fiemap_extent_info *, u64 start, u64 len);
locking rules:
@@ -84,7 +87,6 @@ getxattr: no
listxattr: no
removexattr: yes
truncate_range: yes
-fallocate: no
fiemap: no
Additionally, ->rmdir(), ->unlink() and ->rename() have ->i_mutex on
victim.
@@ -343,7 +345,6 @@ prototypes:
int (*fl_grant)(struct file_lock *, struct file_lock *, int);
void (*fl_release_private)(struct file_lock *);
void (*fl_break)(struct file_lock *); /* break_lease callback */
- int (*fl_mylease)(struct file_lock *, struct file_lock *);
int (*fl_change)(struct file_lock **, int);
locking rules:
@@ -353,7 +354,6 @@ fl_notify: yes no
fl_grant: no no
fl_release_private: maybe no
fl_break: yes no
-fl_mylease: yes no
fl_change yes no
--------------------------- buffer_head -----------------------------------
@@ -435,6 +435,7 @@ prototypes:
ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *,
size_t, unsigned int);
int (*setlease)(struct file *, long, struct file_lock **);
+ long (*fallocate)(struct file *, int, loff_t, loff_t);
};
locking rules:
diff --git a/Documentation/filesystems/porting b/Documentation/filesystems/porting
index 266d205..dfbcd1b 100644
--- a/Documentation/filesystems/porting
+++ b/Documentation/filesystems/porting
@@ -365,8 +365,8 @@ must be done in the RCU callback.
[recommended]
vfs now tries to do path walking in "rcu-walk mode", which avoids
atomic operations and scalability hazards on dentries and inodes (see
-Documentation/filesystems/path-walk.txt). d_hash and d_compare changes (above)
-are examples of the changes required to support this. For more complex
+Documentation/filesystems/path-lookup.txt). d_hash and d_compare changes
+(above) are examples of the changes required to support this. For more complex
filesystem callbacks, the vfs drops out of rcu-walk mode before the fs call, so
no changes are required to the filesystem. However, this is costly and loses
the benefits of rcu-walk mode. We will begin to add filesystem callbacks that
@@ -383,8 +383,8 @@ Documentation/filesystems/vfs.txt for more details.
permission and check_acl are inode permission checks that are called
on many or all directory inodes on the way down a path walk (to check for
-exec permission). These must now be rcu-walk aware (flags & IPERM_RCU). See
-Documentation/filesystems/vfs.txt for more details.
+exec permission). These must now be rcu-walk aware (flags & IPERM_FLAG_RCU).
+See Documentation/filesystems/vfs.txt for more details.
--
[mandatory]
diff --git a/Documentation/filesystems/vfs.txt b/Documentation/filesystems/vfs.txt
index fbb324e..94cf97b 100644
--- a/Documentation/filesystems/vfs.txt
+++ b/Documentation/filesystems/vfs.txt
@@ -415,8 +415,8 @@ otherwise noted.
permission: called by the VFS to check for access rights on a POSIX-like
filesystem.
- May be called in rcu-walk mode (flags & IPERM_RCU). If in rcu-walk
- mode, the filesystem must check the permission without blocking or
+ May be called in rcu-walk mode (flags & IPERM_FLAG_RCU). If in rcu-walk
+ mode, the filesystem must check the permission without blocking or
storing to the inode.
If a situation is encountered that rcu-walk cannot handle, return
@@ -864,6 +864,8 @@ struct dentry_operations {
void (*d_release)(struct dentry *);
void (*d_iput)(struct dentry *, struct inode *);
char *(*d_dname)(struct dentry *, char *, int);
+ struct vfsmount *(*d_automount)(struct path *);
+ int (*d_manage)(struct dentry *, bool, bool);
};
d_revalidate: called when the VFS needs to revalidate a dentry. This
@@ -930,6 +932,47 @@ struct dentry_operations {
at the end of the buffer, and returns a pointer to the first char.
dynamic_dname() helper function is provided to take care of this.
+ d_automount: called when an automount dentry is to be traversed (optional).
+ This should create a new VFS mount record and return the record to the
+ caller. The caller is supplied with a path parameter giving the
+ automount directory to describe the automount target and the parent
+ VFS mount record to provide inheritable mount parameters. NULL should
+ be returned if someone else managed to make the automount first. If
+ the vfsmount creation failed, then an error code should be returned.
+ If -EISDIR is returned, then the directory will be treated as an
+ ordinary directory and returned to pathwalk to continue walking.
+
+ If a vfsmount is returned, the caller will attempt to mount it on the
+ mountpoint and will remove the vfsmount from its expiration list in
+ the case of failure. The vfsmount should be returned with 2 refs on
+ it to prevent automatic expiration - the caller will clean up the
+ additional ref.
+
+ This function is only used if DCACHE_NEED_AUTOMOUNT is set on the
+ dentry. This is set by __d_instantiate() if S_AUTOMOUNT is set on the
+ inode being added.
+
+ d_manage: called to allow the filesystem to manage the transition from a
+ dentry (optional). This allows autofs, for example, to hold up clients
+ waiting to explore behind a 'mountpoint' whilst letting the daemon go
+ past and construct the subtree there. 0 should be returned to let the
+ calling process continue. -EISDIR can be returned to tell pathwalk to
+ use this directory as an ordinary directory and to ignore anything
+ mounted on it and not to check the automount flag. Any other error
+ code will abort pathwalk completely.
+
+ If the 'mounting_here' parameter is true, then namespace_sem is being
+ held by the caller and the function should not initiate any mounts or
+ unmounts that it will then wait for.
+
+ If the 'rcu_walk' parameter is true, then the caller is doing a
+ pathwalk in RCU-walk mode. Sleeping is not permitted in this mode,
+ and the caller can be asked to leave it and call again by returing
+ -ECHILD.
+
+ This function is only used if DCACHE_MANAGE_TRANSIT is set on the
+ dentry being transited from.
+
Example :
static char *pipefs_dname(struct dentry *dent, char *buffer, int buflen)
diff --git a/Documentation/hwmon/lm93 b/Documentation/hwmon/lm93
index 7a10616..f3b2ad2 100644
--- a/Documentation/hwmon/lm93
+++ b/Documentation/hwmon/lm93
@@ -6,6 +6,10 @@ Supported chips:
Prefix 'lm93'
Addresses scanned: I2C 0x2c-0x2e
Datasheet: http://www.national.com/ds.cgi/LM/LM93.pdf
+ * National Semiconductor LM94
+ Prefix 'lm94'
+ Addresses scanned: I2C 0x2c-0x2e
+ Datasheet: http://www.national.com/ds.cgi/LM/LM94.pdf
Authors:
Mark M. Hoffman <mhoffman@lightlink.com>
@@ -56,6 +60,9 @@ previous motherboard management ASICs and uses some of the LM85's features
for dynamic Vccp monitoring and PROCHOT. It is designed to monitor a dual
processor Xeon class motherboard with a minimum of external components.
+LM94 is also supported in LM93 compatible mode. Extra sensors and features of
+LM94 are not supported.
+
User Interface
--------------
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index 55fe759..89835a4 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -43,11 +43,11 @@ parameter is applicable:
AVR32 AVR32 architecture is enabled.
AX25 Appropriate AX.25 support is enabled.
BLACKFIN Blackfin architecture is enabled.
+ DRM Direct Rendering Management support is enabled.
+ DYNAMIC_DEBUG Build in debug messages and enable them at runtime
EDD BIOS Enhanced Disk Drive Services (EDD) is enabled
EFI EFI Partitioning (GPT) is enabled
EIDE EIDE/ATAPI support is enabled.
- DRM Direct Rendering Management support is enabled.
- DYNAMIC_DEBUG Build in debug messages and enable them at runtime
FB The frame buffer device is enabled.
GCOV GCOV profiling is enabled.
HW Appropriate hardware is enabled.
@@ -199,11 +199,6 @@ and is between 256 and 4096 characters. It is defined in the file
unusable. The "log_buf_len" parameter may be useful
if you need to capture more output.
- acpi_display_output= [HW,ACPI]
- acpi_display_output=vendor
- acpi_display_output=video
- See above.
-
acpi_irq_balance [HW,ACPI]
ACPI will balance active IRQs
default in APIC mode
diff --git a/Documentation/lguest/lguest.c b/Documentation/lguest/lguest.c
index dc73bc54..d9da7e1 100644
--- a/Documentation/lguest/lguest.c
+++ b/Documentation/lguest/lguest.c
@@ -39,6 +39,9 @@
#include <limits.h>
#include <stddef.h>
#include <signal.h>
+#include <pwd.h>
+#include <grp.h>
+
#include <linux/virtio_config.h>
#include <linux/virtio_net.h>
#include <linux/virtio_blk.h>
@@ -298,20 +301,27 @@ static void *map_zeroed_pages(unsigned int num)
/*
* We use a private mapping (ie. if we write to the page, it will be
- * copied).
+ * copied). We allocate an extra two pages PROT_NONE to act as guard
+ * pages against read/write attempts that exceed allocated space.
*/
- addr = mmap(NULL, getpagesize() * num,
- PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE, fd, 0);
+ addr = mmap(NULL, getpagesize() * (num+2),
+ PROT_NONE, MAP_PRIVATE, fd, 0);
+
if (addr == MAP_FAILED)
err(1, "Mmapping %u pages of /dev/zero", num);
+ if (mprotect(addr + getpagesize(), getpagesize() * num,
+ PROT_READ|PROT_WRITE) == -1)
+ err(1, "mprotect rw %u pages failed", num);
+
/*
* One neat mmap feature is that you can close the fd, and it
* stays mapped.
*/
close(fd);
- return addr;
+ /* Return address after PROT_NONE page */
+ return addr + getpagesize();
}
/* Get some more pages for a device. */
@@ -343,7 +353,7 @@ static void map_at(int fd, void *addr, unsigned long offset, unsigned long len)
* done to it. This allows us to share untouched memory between
* Guests.
*/
- if (mmap(addr, len, PROT_READ|PROT_WRITE|PROT_EXEC,
+ if (mmap(addr, len, PROT_READ|PROT_WRITE,
MAP_FIXED|MAP_PRIVATE, fd, offset) != MAP_FAILED)
return;
@@ -573,10 +583,10 @@ static void *_check_pointer(unsigned long addr, unsigned int size,
unsigned int line)
{
/*
- * We have to separately check addr and addr+size, because size could
- * be huge and addr + size might wrap around.
+ * Check if the requested address and size exceeds the allocated memory,
+ * or addr + size wraps around.
*/
- if (addr >= guest_limit || addr + size >= guest_limit)
+ if ((addr + size) > guest_limit || (addr + size) < addr)
errx(1, "%s:%i: Invalid address %#lx", __FILE__, line, addr);
/*
* We return a pointer for the caller's convenience, now we know it's
@@ -1872,6 +1882,8 @@ static struct option opts[] = {
{ "block", 1, NULL, 'b' },
{ "rng", 0, NULL, 'r' },
{ "initrd", 1, NULL, 'i' },
+ { "username", 1, NULL, 'u' },
+ { "chroot", 1, NULL, 'c' },
{ NULL },
};
static void usage(void)
@@ -1894,6 +1906,12 @@ int main(int argc, char *argv[])
/* If they specify an initrd file to load. */
const char *initrd_name = NULL;
+ /* Password structure for initgroups/setres[gu]id */
+ struct passwd *user_details = NULL;
+
+ /* Directory to chroot to */
+ char *chroot_path = NULL;
+
/* Save the args: we "reboot" by execing ourselves again. */
main_args = argv;
@@ -1950,6 +1968,14 @@ int main(int argc, char *argv[])
case 'i':
initrd_name = optarg;
break;
+ case 'u':
+ user_details = getpwnam(optarg);
+ if (!user_details)
+ err(1, "getpwnam failed, incorrect username?");
+ break;
+ case 'c':
+ chroot_path = optarg;
+ break;
default:
warnx("Unknown argument %s", argv[optind]);
usage();
@@ -2021,6 +2047,37 @@ int main(int argc, char *argv[])
/* If we exit via err(), this kills all the threads, restores tty. */
atexit(cleanup_devices);
+ /* If requested, chroot to a directory */
+ if (chroot_path) {
+ if (chroot(chroot_path) != 0)
+ err(1, "chroot(\"%s\") failed", chroot_path);
+
+ if (chdir("/") != 0)
+ err(1, "chdir(\"/\") failed");
+
+ verbose("chroot done\n");
+ }
+
+ /* If requested, drop privileges */
+ if (user_details) {
+ uid_t u;
+ gid_t g;
+
+ u = user_details->pw_uid;
+ g = user_details->pw_gid;
+
+ if (initgroups(user_details->pw_name, g) != 0)
+ err(1, "initgroups failed");
+
+ if (setresgid(g, g, g) != 0)
+ err(1, "setresgid failed");
+
+ if (setresuid(u, u, u) != 0)
+ err(1, "setresuid failed");
+
+ verbose("Dropping privileges completed\n");
+ }
+
/* Finally, run the Guest. This doesn't return. */
run_guest();
}
diff --git a/Documentation/lguest/lguest.txt b/Documentation/lguest/lguest.txt
index 6ccaf8e..dad9997 100644
--- a/Documentation/lguest/lguest.txt
+++ b/Documentation/lguest/lguest.txt
@@ -117,6 +117,11 @@ Running Lguest:
for general information on how to get bridging to work.
+- Random number generation. Using the --rng option will provide a
+ /dev/hwrng in the guest that will read from the host's /dev/random.
+ Use this option in conjunction with rng-tools (see ../hw_random.txt)
+ to provide entropy to the guest kernel's /dev/random.
+
There is a helpful mailing list at http://ozlabs.org/mailman/listinfo/lguest
Good luck!
diff --git a/Documentation/sound/alsa/soc/codec.txt b/Documentation/sound/alsa/soc/codec.txt
index 37ba3a7..bce23a4 100644
--- a/Documentation/sound/alsa/soc/codec.txt
+++ b/Documentation/sound/alsa/soc/codec.txt
@@ -27,42 +27,38 @@ ASoC Codec driver breakdown
1 - Codec DAI and PCM configuration
-----------------------------------
-Each codec driver must have a struct snd_soc_codec_dai to define its DAI and
+Each codec driver must have a struct snd_soc_dai_driver to define its DAI and
PCM capabilities and operations. This struct is exported so that it can be
registered with the core by your machine driver.
e.g.
-struct snd_soc_codec_dai wm8731_dai = {
- .name = "WM8731",
- /* playback capabilities */
+static struct snd_soc_dai_ops wm8731_dai_ops = {
+ .prepare = wm8731_pcm_prepare,
+ .hw_params = wm8731_hw_params,
+ .shutdown = wm8731_shutdown,
+ .digital_mute = wm8731_mute,
+ .set_sysclk = wm8731_set_dai_sysclk,
+ .set_fmt = wm8731_set_dai_fmt,
+};
+
+struct snd_soc_dai_driver wm8731_dai = {
+ .name = "wm8731-hifi",
.playback = {
.stream_name = "Playback",
.channels_min = 1,
.channels_max = 2,
.rates = WM8731_RATES,
.formats = WM8731_FORMATS,},
- /* capture capabilities */
.capture = {
.stream_name = "Capture",
.channels_min = 1,
.channels_max = 2,
.rates = WM8731_RATES,
.formats = WM8731_FORMATS,},
- /* pcm operations - see section 4 below */
- .ops = {
- .prepare = wm8731_pcm_prepare,
- .hw_params = wm8731_hw_params,
- .shutdown = wm8731_shutdown,
- },
- /* DAI operations - see DAI.txt */
- .dai_ops = {
- .digital_mute = wm8731_mute,
- .set_sysclk = wm8731_set_dai_sysclk,
- .set_fmt = wm8731_set_dai_fmt,
- }
+ .ops = &wm8731_dai_ops,
+ .symmetric_rates = 1,
};
-EXPORT_SYMBOL_GPL(wm8731_dai);
2 - Codec control IO
@@ -186,13 +182,14 @@ when the mute is applied or freed.
i.e.
-static int wm8974_mute(struct snd_soc_codec *codec,
- struct snd_soc_codec_dai *dai, int mute)
+static int wm8974_mute(struct snd_soc_dai *dai, int mute)
{
- u16 mute_reg = wm8974_read_reg_cache(codec, WM8974_DAC) & 0xffbf;
- if(mute)
- wm8974_write(codec, WM8974_DAC, mute_reg | 0x40);
+ struct snd_soc_codec *codec = dai->codec;
+ u16 mute_reg = snd_soc_read(codec, WM8974_DAC) & 0xffbf;
+
+ if (mute)
+ snd_soc_write(codec, WM8974_DAC, mute_reg | 0x40);
else
- wm8974_write(codec, WM8974_DAC, mute_reg);
+ snd_soc_write(codec, WM8974_DAC, mute_reg);
return 0;
}
diff --git a/Documentation/sound/alsa/soc/machine.txt b/Documentation/sound/alsa/soc/machine.txt
index 2524c75..3e2ec9c 100644
--- a/Documentation/sound/alsa/soc/machine.txt
+++ b/Documentation/sound/alsa/soc/machine.txt
@@ -12,6 +12,8 @@ the following struct:-
struct snd_soc_card {
char *name;
+ ...
+
int (*probe)(struct platform_device *pdev);
int (*remove)(struct platform_device *pdev);
@@ -22,12 +24,13 @@ struct snd_soc_card {
int (*resume_pre)(struct platform_device *pdev);
int (*resume_post)(struct platform_device *pdev);
- /* machine stream operations */
- struct snd_soc_ops *ops;
+ ...
/* CPU <--> Codec DAI links */
struct snd_soc_dai_link *dai_link;
int num_links;
+
+ ...
};
probe()/remove()
@@ -42,11 +45,6 @@ of any machine audio tasks that have to be done before or after the codec, DAIs
and DMA is suspended and resumed. Optional.
-Machine operations
-------------------
-The machine specific audio operations can be set here. Again this is optional.
-
-
Machine DAI Configuration
-------------------------
The machine DAI configuration glues all the codec and CPU DAIs together. It can
@@ -61,8 +59,10 @@ struct snd_soc_dai_link is used to set up each DAI in your machine. e.g.
static struct snd_soc_dai_link corgi_dai = {
.name = "WM8731",
.stream_name = "WM8731",
- .cpu_dai = &pxa_i2s_dai,
- .codec_dai = &wm8731_dai,
+ .cpu_dai_name = "pxa-is2-dai",
+ .codec_dai_name = "wm8731-hifi",
+ .platform_name = "pxa-pcm-audio",
+ .codec_name = "wm8713-codec.0-001a",
.init = corgi_wm8731_init,
.ops = &corgi_ops,
};
@@ -77,26 +77,6 @@ static struct snd_soc_card snd_soc_corgi = {
};
-Machine Audio Subsystem
------------------------
-
-The machine soc device glues the platform, machine and codec driver together.
-Private data can also be set here. e.g.
-
-/* corgi audio private data */
-static struct wm8731_setup_data corgi_wm8731_setup = {
- .i2c_address = 0x1b,
-};
-
-/* corgi audio subsystem */
-static struct snd_soc_device corgi_snd_devdata = {
- .machine = &snd_soc_corgi,
- .platform = &pxa2xx_soc_platform,
- .codec_dev = &soc_codec_dev_wm8731,
- .codec_data = &corgi_wm8731_setup,
-};
-
-
Machine Power Map
-----------------
diff --git a/Documentation/sound/alsa/soc/platform.txt b/Documentation/sound/alsa/soc/platform.txt
index 06d8359..d57efad 100644
--- a/Documentation/sound/alsa/soc/platform.txt
+++ b/Documentation/sound/alsa/soc/platform.txt
@@ -20,9 +20,10 @@ struct snd_soc_ops {
int (*trigger)(struct snd_pcm_substream *, int);
};
-The platform driver exports its DMA functionality via struct snd_soc_platform:-
+The platform driver exports its DMA functionality via struct
+snd_soc_platform_driver:-
-struct snd_soc_platform {
+struct snd_soc_platform_driver {
char *name;
int (*probe)(struct platform_device *pdev);
@@ -34,6 +35,13 @@ struct snd_soc_platform {
int (*pcm_new)(struct snd_card *, struct snd_soc_codec_dai *, struct snd_pcm *);
void (*pcm_free)(struct snd_pcm *);
+ /*
+ * For platform caused delay reporting.
+ * Optional.
+ */
+ snd_pcm_sframes_t (*delay)(struct snd_pcm_substream *,
+ struct snd_soc_dai *);
+
/* platform stream ops */
struct snd_pcm_ops *pcm_ops;
};
diff --git a/Documentation/target/tcm_mod_builder.py b/Documentation/target/tcm_mod_builder.py
new file mode 100755
index 0000000..dbeb8a0
--- /dev/null
+++ b/Documentation/target/tcm_mod_builder.py
@@ -0,0 +1,1094 @@
+#!/usr/bin/python
+# The TCM v4 multi-protocol fabric module generation script for drivers/target/$NEW_MOD
+#
+# Copyright (c) 2010 Rising Tide Systems
+# Copyright (c) 2010 Linux-iSCSI.org
+#
+# Author: nab@kernel.org
+#
+import os, sys
+import subprocess as sub
+import string
+import re
+import optparse
+
+tcm_dir = ""
+
+fabric_ops = []
+fabric_mod_dir = ""
+fabric_mod_port = ""
+fabric_mod_init_port = ""
+
+def tcm_mod_err(msg):
+ print msg
+ sys.exit(1)
+
+def tcm_mod_create_module_subdir(fabric_mod_dir_var):
+
+ if os.path.isdir(fabric_mod_dir_var) == True:
+ return 1
+
+ print "Creating fabric_mod_dir: " + fabric_mod_dir_var
+ ret = os.mkdir(fabric_mod_dir_var)
+ if ret:
+ tcm_mod_err("Unable to mkdir " + fabric_mod_dir_var)
+
+ return
+
+def tcm_mod_build_FC_include(fabric_mod_dir_var, fabric_mod_name):
+ global fabric_mod_port
+ global fabric_mod_init_port
+ buf = ""
+
+ f = fabric_mod_dir_var + "/" + fabric_mod_name + "_base.h"
+ print "Writing file: " + f
+
+ p = open(f, 'w');
+ if not p:
+ tcm_mod_err("Unable to open file: " + f)
+
+ buf = "#define " + fabric_mod_name.upper() + "_VERSION \"v0.1\"\n"
+ buf += "#define " + fabric_mod_name.upper() + "_NAMELEN 32\n"
+ buf += "\n"
+ buf += "struct " + fabric_mod_name + "_nacl {\n"
+ buf += " /* Binary World Wide unique Port Name for FC Initiator Nport */\n"
+ buf += " u64 nport_wwpn;\n"
+ buf += " /* ASCII formatted WWPN for FC Initiator Nport */\n"
+ buf += " char nport_name[" + fabric_mod_name.upper() + "_NAMELEN];\n"
+ buf += " /* Returned by " + fabric_mod_name + "_make_nodeacl() */\n"
+ buf += " struct se_node_acl se_node_acl;\n"
+ buf += "};\n"
+ buf += "\n"
+ buf += "struct " + fabric_mod_name + "_tpg {\n"
+ buf += " /* FC lport target portal group tag for TCM */\n"
+ buf += " u16 lport_tpgt;\n"
+ buf += " /* Pointer back to " + fabric_mod_name + "_lport */\n"
+ buf += " struct " + fabric_mod_name + "_lport *lport;\n"
+ buf += " /* Returned by " + fabric_mod_name + "_make_tpg() */\n"
+ buf += " struct se_portal_group se_tpg;\n"
+ buf += "};\n"
+ buf += "\n"
+ buf += "struct " + fabric_mod_name + "_lport {\n"
+ buf += " /* SCSI protocol the lport is providing */\n"
+ buf += " u8 lport_proto_id;\n"
+ buf += " /* Binary World Wide unique Port Name for FC Target Lport */\n"
+ buf += " u64 lport_wwpn;\n"
+ buf += " /* ASCII formatted WWPN for FC Target Lport */\n"
+ buf += " char lport_name[" + fabric_mod_name.upper() + "_NAMELEN];\n"
+ buf += " /* Returned by " + fabric_mod_name + "_make_lport() */\n"
+ buf += " struct se_wwn lport_wwn;\n"
+ buf += "};\n"
+
+ ret = p.write(buf)
+ if ret:
+ tcm_mod_err("Unable to write f: " + f)
+
+ p.close()
+
+ fabric_mod_port = "lport"
+ fabric_mod_init_port = "nport"
+
+ return
+
+def tcm_mod_build_SAS_include(fabric_mod_dir_var, fabric_mod_name):
+ global fabric_mod_port
+ global fabric_mod_init_port
+ buf = ""
+
+ f = fabric_mod_dir_var + "/" + fabric_mod_name + "_base.h"
+ print "Writing file: " + f
+
+ p = open(f, 'w');
+ if not p:
+ tcm_mod_err("Unable to open file: " + f)
+
+ buf = "#define " + fabric_mod_name.upper() + "_VERSION \"v0.1\"\n"
+ buf += "#define " + fabric_mod_name.upper() + "_NAMELEN 32\n"
+ buf += "\n"
+ buf += "struct " + fabric_mod_name + "_nacl {\n"
+ buf += " /* Binary World Wide unique Port Name for SAS Initiator port */\n"
+ buf += " u64 iport_wwpn;\n"
+ buf += " /* ASCII formatted WWPN for Sas Initiator port */\n"
+ buf += " char iport_name[" + fabric_mod_name.upper() + "_NAMELEN];\n"
+ buf += " /* Returned by " + fabric_mod_name + "_make_nodeacl() */\n"
+ buf += " struct se_node_acl se_node_acl;\n"
+ buf += "};\n\n"
+ buf += "struct " + fabric_mod_name + "_tpg {\n"
+ buf += " /* SAS port target portal group tag for TCM */\n"
+ buf += " u16 tport_tpgt;\n"
+ buf += " /* Pointer back to " + fabric_mod_name + "_tport */\n"
+ buf += " struct " + fabric_mod_name + "_tport *tport;\n"
+ buf += " /* Returned by " + fabric_mod_name + "_make_tpg() */\n"
+ buf += " struct se_portal_group se_tpg;\n"
+ buf += "};\n\n"
+ buf += "struct " + fabric_mod_name + "_tport {\n"
+ buf += " /* SCSI protocol the tport is providing */\n"
+ buf += " u8 tport_proto_id;\n"
+ buf += " /* Binary World Wide unique Port Name for SAS Target port */\n"
+ buf += " u64 tport_wwpn;\n"
+ buf += " /* ASCII formatted WWPN for SAS Target port */\n"
+ buf += " char tport_name[" + fabric_mod_name.upper() + "_NAMELEN];\n"
+ buf += " /* Returned by " + fabric_mod_name + "_make_tport() */\n"
+ buf += " struct se_wwn tport_wwn;\n"
+ buf += "};\n"
+
+ ret = p.write(buf)
+ if ret:
+ tcm_mod_err("Unable to write f: " + f)
+
+ p.close()
+
+ fabric_mod_port = "tport"
+ fabric_mod_init_port = "iport"
+
+ return
+
+def tcm_mod_build_iSCSI_include(fabric_mod_dir_var, fabric_mod_name):
+ global fabric_mod_port
+ global fabric_mod_init_port
+ buf = ""
+
+ f = fabric_mod_dir_var + "/" + fabric_mod_name + "_base.h"
+ print "Writing file: " + f
+
+ p = open(f, 'w');
+ if not p:
+ tcm_mod_err("Unable to open file: " + f)
+
+ buf = "#define " + fabric_mod_name.upper() + "_VERSION \"v0.1\"\n"
+ buf += "#define " + fabric_mod_name.upper() + "_NAMELEN 32\n"
+ buf += "\n"
+ buf += "struct " + fabric_mod_name + "_nacl {\n"
+ buf += " /* ASCII formatted InitiatorName */\n"
+ buf += " char iport_name[" + fabric_mod_name.upper() + "_NAMELEN];\n"
+ buf += " /* Returned by " + fabric_mod_name + "_make_nodeacl() */\n"
+ buf += " struct se_node_acl se_node_acl;\n"
+ buf += "};\n\n"
+ buf += "struct " + fabric_mod_name + "_tpg {\n"
+ buf += " /* iSCSI target portal group tag for TCM */\n"
+ buf += " u16 tport_tpgt;\n"
+ buf += " /* Pointer back to " + fabric_mod_name + "_tport */\n"
+ buf += " struct " + fabric_mod_name + "_tport *tport;\n"
+ buf += " /* Returned by " + fabric_mod_name + "_make_tpg() */\n"
+ buf += " struct se_portal_group se_tpg;\n"
+ buf += "};\n\n"
+ buf += "struct " + fabric_mod_name + "_tport {\n"
+ buf += " /* SCSI protocol the tport is providing */\n"
+ buf += " u8 tport_proto_id;\n"
+ buf += " /* ASCII formatted TargetName for IQN */\n"
+ buf += " char tport_name[" + fabric_mod_name.upper() + "_NAMELEN];\n"
+ buf += " /* Returned by " + fabric_mod_name + "_make_tport() */\n"
+ buf += " struct se_wwn tport_wwn;\n"
+ buf += "};\n"
+
+ ret = p.write(buf)
+ if ret:
+ tcm_mod_err("Unable to write f: " + f)
+
+ p.close()
+
+ fabric_mod_port = "tport"
+ fabric_mod_init_port = "iport"
+
+ return
+
+def tcm_mod_build_base_includes(proto_ident, fabric_mod_dir_val, fabric_mod_name):
+
+ if proto_ident == "FC":
+ tcm_mod_build_FC_include(fabric_mod_dir_val, fabric_mod_name)
+ elif proto_ident == "SAS":
+ tcm_mod_build_SAS_include(fabric_mod_dir_val, fabric_mod_name)
+ elif proto_ident == "iSCSI":
+ tcm_mod_build_iSCSI_include(fabric_mod_dir_val, fabric_mod_name)
+ else:
+ print "Unsupported proto_ident: " + proto_ident
+ sys.exit(1)
+
+ return
+
+def tcm_mod_build_configfs(proto_ident, fabric_mod_dir_var, fabric_mod_name):
+ buf = ""
+
+ f = fabric_mod_dir_var + "/" + fabric_mod_name + "_configfs.c"
+ print "Writing file: " + f
+
+ p = open(f, 'w');
+ if not p:
+ tcm_mod_err("Unable to open file: " + f)
+
+ buf = "#include <linux/module.h>\n"
+ buf += "#include <linux/moduleparam.h>\n"
+ buf += "#include <linux/version.h>\n"
+ buf += "#include <generated/utsrelease.h>\n"
+ buf += "#include <linux/utsname.h>\n"
+ buf += "#include <linux/init.h>\n"
+ buf += "#include <linux/slab.h>\n"
+ buf += "#include <linux/kthread.h>\n"
+ buf += "#include <linux/types.h>\n"
+ buf += "#include <linux/string.h>\n"
+ buf += "#include <linux/configfs.h>\n"
+ buf += "#include <linux/ctype.h>\n"
+ buf += "#include <asm/unaligned.h>\n\n"
+ buf += "#include <target/target_core_base.h>\n"
+ buf += "#include <target/target_core_transport.h>\n"
+ buf += "#include <target/target_core_fabric_ops.h>\n"
+ buf += "#include <target/target_core_fabric_configfs.h>\n"
+ buf += "#include <target/target_core_fabric_lib.h>\n"
+ buf += "#include <target/target_core_device.h>\n"
+ buf += "#include <target/target_core_tpg.h>\n"
+ buf += "#include <target/target_core_configfs.h>\n"
+ buf += "#include <target/target_core_base.h>\n"
+ buf += "#include <target/configfs_macros.h>\n\n"
+ buf += "#include <" + fabric_mod_name + "_base.h>\n"
+ buf += "#include <" + fabric_mod_name + "_fabric.h>\n\n"
+
+ buf += "/* Local pointer to allocated TCM configfs fabric module */\n"
+ buf += "struct target_fabric_configfs *" + fabric_mod_name + "_fabric_configfs;\n\n"
+
+ buf += "static struct se_node_acl *" + fabric_mod_name + "_make_nodeacl(\n"
+ buf += " struct se_portal_group *se_tpg,\n"
+ buf += " struct config_group *group,\n"
+ buf += " const char *name)\n"
+ buf += "{\n"
+ buf += " struct se_node_acl *se_nacl, *se_nacl_new;\n"
+ buf += " struct " + fabric_mod_name + "_nacl *nacl;\n"
+
+ if proto_ident == "FC" or proto_ident == "SAS":
+ buf += " u64 wwpn = 0;\n"
+
+ buf += " u32 nexus_depth;\n\n"
+ buf += " /* " + fabric_mod_name + "_parse_wwn(name, &wwpn, 1) < 0)\n"
+ buf += " return ERR_PTR(-EINVAL); */\n"
+ buf += " se_nacl_new = " + fabric_mod_name + "_alloc_fabric_acl(se_tpg);\n"
+ buf += " if (!(se_nacl_new))\n"
+ buf += " return ERR_PTR(-ENOMEM);\n"
+ buf += "//#warning FIXME: Hardcoded nexus depth in " + fabric_mod_name + "_make_nodeacl()\n"
+ buf += " nexus_depth = 1;\n"
+ buf += " /*\n"
+ buf += " * se_nacl_new may be released by core_tpg_add_initiator_node_acl()\n"
+ buf += " * when converting a NodeACL from demo mode -> explict\n"
+ buf += " */\n"
+ buf += " se_nacl = core_tpg_add_initiator_node_acl(se_tpg, se_nacl_new,\n"
+ buf += " name, nexus_depth);\n"
+ buf += " if (IS_ERR(se_nacl)) {\n"
+ buf += " " + fabric_mod_name + "_release_fabric_acl(se_tpg, se_nacl_new);\n"
+ buf += " return se_nacl;\n"
+ buf += " }\n"
+ buf += " /*\n"
+ buf += " * Locate our struct " + fabric_mod_name + "_nacl and set the FC Nport WWPN\n"
+ buf += " */\n"
+ buf += " nacl = container_of(se_nacl, struct " + fabric_mod_name + "_nacl, se_node_acl);\n"
+
+ if proto_ident == "FC" or proto_ident == "SAS":
+ buf += " nacl->" + fabric_mod_init_port + "_wwpn = wwpn;\n"
+
+ buf += " /* " + fabric_mod_name + "_format_wwn(&nacl->" + fabric_mod_init_port + "_name[0], " + fabric_mod_name.upper() + "_NAMELEN, wwpn); */\n\n"
+ buf += " return se_nacl;\n"
+ buf += "}\n\n"
+ buf += "static void " + fabric_mod_name + "_drop_nodeacl(struct se_node_acl *se_acl)\n"
+ buf += "{\n"
+ buf += " struct " + fabric_mod_name + "_nacl *nacl = container_of(se_acl,\n"
+ buf += " struct " + fabric_mod_name + "_nacl, se_node_acl);\n"
+ buf += " kfree(nacl);\n"
+ buf += "}\n\n"
+
+ buf += "static struct se_portal_group *" + fabric_mod_name + "_make_tpg(\n"
+ buf += " struct se_wwn *wwn,\n"
+ buf += " struct config_group *group,\n"
+ buf += " const char *name)\n"
+ buf += "{\n"
+ buf += " struct " + fabric_mod_name + "_" + fabric_mod_port + "*" + fabric_mod_port + " = container_of(wwn,\n"
+ buf += " struct " + fabric_mod_name + "_" + fabric_mod_port + ", " + fabric_mod_port + "_wwn);\n\n"
+ buf += " struct " + fabric_mod_name + "_tpg *tpg;\n"
+ buf += " unsigned long tpgt;\n"
+ buf += " int ret;\n\n"
+ buf += " if (strstr(name, \"tpgt_\") != name)\n"
+ buf += " return ERR_PTR(-EINVAL);\n"
+ buf += " if (strict_strtoul(name + 5, 10, &tpgt) || tpgt > UINT_MAX)\n"
+ buf += " return ERR_PTR(-EINVAL);\n\n"
+ buf += " tpg = kzalloc(sizeof(struct " + fabric_mod_name + "_tpg), GFP_KERNEL);\n"
+ buf += " if (!(tpg)) {\n"
+ buf += " printk(KERN_ERR \"Unable to allocate struct " + fabric_mod_name + "_tpg\");\n"
+ buf += " return ERR_PTR(-ENOMEM);\n"
+ buf += " }\n"
+ buf += " tpg->" + fabric_mod_port + " = " + fabric_mod_port + ";\n"
+ buf += " tpg->" + fabric_mod_port + "_tpgt = tpgt;\n\n"
+ buf += " ret = core_tpg_register(&" + fabric_mod_name + "_fabric_configfs->tf_ops, wwn,\n"
+ buf += " &tpg->se_tpg, (void *)tpg,\n"
+ buf += " TRANSPORT_TPG_TYPE_NORMAL);\n"
+ buf += " if (ret < 0) {\n"
+ buf += " kfree(tpg);\n"
+ buf += " return NULL;\n"
+ buf += " }\n"
+ buf += " return &tpg->se_tpg;\n"
+ buf += "}\n\n"
+ buf += "static void " + fabric_mod_name + "_drop_tpg(struct se_portal_group *se_tpg)\n"
+ buf += "{\n"
+ buf += " struct " + fabric_mod_name + "_tpg *tpg = container_of(se_tpg,\n"
+ buf += " struct " + fabric_mod_name + "_tpg, se_tpg);\n\n"
+ buf += " core_tpg_deregister(se_tpg);\n"
+ buf += " kfree(tpg);\n"
+ buf += "}\n\n"
+
+ buf += "static struct se_wwn *" + fabric_mod_name + "_make_" + fabric_mod_port + "(\n"
+ buf += " struct target_fabric_configfs *tf,\n"
+ buf += " struct config_group *group,\n"
+ buf += " const char *name)\n"
+ buf += "{\n"
+ buf += " struct " + fabric_mod_name + "_" + fabric_mod_port + " *" + fabric_mod_port + ";\n"
+
+ if proto_ident == "FC" or proto_ident == "SAS":
+ buf += " u64 wwpn = 0;\n\n"
+
+ buf += " /* if (" + fabric_mod_name + "_parse_wwn(name, &wwpn, 1) < 0)\n"
+ buf += " return ERR_PTR(-EINVAL); */\n\n"
+ buf += " " + fabric_mod_port + " = kzalloc(sizeof(struct " + fabric_mod_name + "_" + fabric_mod_port + "), GFP_KERNEL);\n"
+ buf += " if (!(" + fabric_mod_port + ")) {\n"
+ buf += " printk(KERN_ERR \"Unable to allocate struct " + fabric_mod_name + "_" + fabric_mod_port + "\");\n"
+ buf += " return ERR_PTR(-ENOMEM);\n"
+ buf += " }\n"
+
+ if proto_ident == "FC" or proto_ident == "SAS":
+ buf += " " + fabric_mod_port + "->" + fabric_mod_port + "_wwpn = wwpn;\n"
+
+ buf += " /* " + fabric_mod_name + "_format_wwn(&" + fabric_mod_port + "->" + fabric_mod_port + "_name[0], " + fabric_mod_name.upper() + "__NAMELEN, wwpn); */\n\n"
+ buf += " return &" + fabric_mod_port + "->" + fabric_mod_port + "_wwn;\n"
+ buf += "}\n\n"
+ buf += "static void " + fabric_mod_name + "_drop_" + fabric_mod_port + "(struct se_wwn *wwn)\n"
+ buf += "{\n"
+ buf += " struct " + fabric_mod_name + "_" + fabric_mod_port + " *" + fabric_mod_port + " = container_of(wwn,\n"
+ buf += " struct " + fabric_mod_name + "_" + fabric_mod_port + ", " + fabric_mod_port + "_wwn);\n"
+ buf += " kfree(" + fabric_mod_port + ");\n"
+ buf += "}\n\n"
+ buf += "static ssize_t " + fabric_mod_name + "_wwn_show_attr_version(\n"
+ buf += " struct target_fabric_configfs *tf,\n"
+ buf += " char *page)\n"
+ buf += "{\n"
+ buf += " return sprintf(page, \"" + fabric_mod_name.upper() + " fabric module %s on %s/%s\"\n"
+ buf += " \"on \"UTS_RELEASE\"\\n\", " + fabric_mod_name.upper() + "_VERSION, utsname()->sysname,\n"
+ buf += " utsname()->machine);\n"
+ buf += "}\n\n"
+ buf += "TF_WWN_ATTR_RO(" + fabric_mod_name + ", version);\n\n"
+ buf += "static struct configfs_attribute *" + fabric_mod_name + "_wwn_attrs[] = {\n"
+ buf += " &" + fabric_mod_name + "_wwn_version.attr,\n"
+ buf += " NULL,\n"
+ buf += "};\n\n"
+
+ buf += "static struct target_core_fabric_ops " + fabric_mod_name + "_ops = {\n"
+ buf += " .get_fabric_name = " + fabric_mod_name + "_get_fabric_name,\n"
+ buf += " .get_fabric_proto_ident = " + fabric_mod_name + "_get_fabric_proto_ident,\n"
+ buf += " .tpg_get_wwn = " + fabric_mod_name + "_get_fabric_wwn,\n"
+ buf += " .tpg_get_tag = " + fabric_mod_name + "_get_tag,\n"
+ buf += " .tpg_get_default_depth = " + fabric_mod_name + "_get_default_depth,\n"
+ buf += " .tpg_get_pr_transport_id = " + fabric_mod_name + "_get_pr_transport_id,\n"
+ buf += " .tpg_get_pr_transport_id_len = " + fabric_mod_name + "_get_pr_transport_id_len,\n"
+ buf += " .tpg_parse_pr_out_transport_id = " + fabric_mod_name + "_parse_pr_out_transport_id,\n"
+ buf += " .tpg_check_demo_mode = " + fabric_mod_name + "_check_false,\n"
+ buf += " .tpg_check_demo_mode_cache = " + fabric_mod_name + "_check_true,\n"
+ buf += " .tpg_check_demo_mode_write_protect = " + fabric_mod_name + "_check_true,\n"
+ buf += " .tpg_check_prod_mode_write_protect = " + fabric_mod_name + "_check_false,\n"
+ buf += " .tpg_alloc_fabric_acl = " + fabric_mod_name + "_alloc_fabric_acl,\n"
+ buf += " .tpg_release_fabric_acl = " + fabric_mod_name + "_release_fabric_acl,\n"
+ buf += " .tpg_get_inst_index = " + fabric_mod_name + "_tpg_get_inst_index,\n"
+ buf += " .release_cmd_to_pool = " + fabric_mod_name + "_release_cmd,\n"
+ buf += " .release_cmd_direct = " + fabric_mod_name + "_release_cmd,\n"
+ buf += " .shutdown_session = " + fabric_mod_name + "_shutdown_session,\n"
+ buf += " .close_session = " + fabric_mod_name + "_close_session,\n"
+ buf += " .stop_session = " + fabric_mod_name + "_stop_session,\n"
+ buf += " .fall_back_to_erl0 = " + fabric_mod_name + "_reset_nexus,\n"
+ buf += " .sess_logged_in = " + fabric_mod_name + "_sess_logged_in,\n"
+ buf += " .sess_get_index = " + fabric_mod_name + "_sess_get_index,\n"
+ buf += " .sess_get_initiator_sid = NULL,\n"
+ buf += " .write_pending = " + fabric_mod_name + "_write_pending,\n"
+ buf += " .write_pending_status = " + fabric_mod_name + "_write_pending_status,\n"
+ buf += " .set_default_node_attributes = " + fabric_mod_name + "_set_default_node_attrs,\n"
+ buf += " .get_task_tag = " + fabric_mod_name + "_get_task_tag,\n"
+ buf += " .get_cmd_state = " + fabric_mod_name + "_get_cmd_state,\n"
+ buf += " .new_cmd_failure = " + fabric_mod_name + "_new_cmd_failure,\n"
+ buf += " .queue_data_in = " + fabric_mod_name + "_queue_data_in,\n"
+ buf += " .queue_status = " + fabric_mod_name + "_queue_status,\n"
+ buf += " .queue_tm_rsp = " + fabric_mod_name + "_queue_tm_rsp,\n"
+ buf += " .get_fabric_sense_len = " + fabric_mod_name + "_get_fabric_sense_len,\n"
+ buf += " .set_fabric_sense_len = " + fabric_mod_name + "_set_fabric_sense_len,\n"
+ buf += " .is_state_remove = " + fabric_mod_name + "_is_state_remove,\n"
+ buf += " .pack_lun = " + fabric_mod_name + "_pack_lun,\n"
+ buf += " /*\n"
+ buf += " * Setup function pointers for generic logic in target_core_fabric_configfs.c\n"
+ buf += " */\n"
+ buf += " .fabric_make_wwn = " + fabric_mod_name + "_make_" + fabric_mod_port + ",\n"
+ buf += " .fabric_drop_wwn = " + fabric_mod_name + "_drop_" + fabric_mod_port + ",\n"
+ buf += " .fabric_make_tpg = " + fabric_mod_name + "_make_tpg,\n"
+ buf += " .fabric_drop_tpg = " + fabric_mod_name + "_drop_tpg,\n"
+ buf += " .fabric_post_link = NULL,\n"
+ buf += " .fabric_pre_unlink = NULL,\n"
+ buf += " .fabric_make_np = NULL,\n"
+ buf += " .fabric_drop_np = NULL,\n"
+ buf += " .fabric_make_nodeacl = " + fabric_mod_name + "_make_nodeacl,\n"
+ buf += " .fabric_drop_nodeacl = " + fabric_mod_name + "_drop_nodeacl,\n"
+ buf += "};\n\n"
+
+ buf += "static int " + fabric_mod_name + "_register_configfs(void)\n"
+ buf += "{\n"
+ buf += " struct target_fabric_configfs *fabric;\n"
+ buf += " int ret;\n\n"
+ buf += " printk(KERN_INFO \"" + fabric_mod_name.upper() + " fabric module %s on %s/%s\"\n"
+ buf += " \" on \"UTS_RELEASE\"\\n\"," + fabric_mod_name.upper() + "_VERSION, utsname()->sysname,\n"
+ buf += " utsname()->machine);\n"
+ buf += " /*\n"
+ buf += " * Register the top level struct config_item_type with TCM core\n"
+ buf += " */\n"
+ buf += " fabric = target_fabric_configfs_init(THIS_MODULE, \"" + fabric_mod_name[4:] + "\");\n"
+ buf += " if (!(fabric)) {\n"
+ buf += " printk(KERN_ERR \"target_fabric_configfs_init() failed\\n\");\n"
+ buf += " return -ENOMEM;\n"
+ buf += " }\n"
+ buf += " /*\n"
+ buf += " * Setup fabric->tf_ops from our local " + fabric_mod_name + "_ops\n"
+ buf += " */\n"
+ buf += " fabric->tf_ops = " + fabric_mod_name + "_ops;\n"
+ buf += " /*\n"
+ buf += " * Setup default attribute lists for various fabric->tf_cit_tmpl\n"
+ buf += " */\n"
+ buf += " TF_CIT_TMPL(fabric)->tfc_wwn_cit.ct_attrs = " + fabric_mod_name + "_wwn_attrs;\n"
+ buf += " TF_CIT_TMPL(fabric)->tfc_tpg_base_cit.ct_attrs = NULL;\n"
+ buf += " TF_CIT_TMPL(fabric)->tfc_tpg_attrib_cit.ct_attrs = NULL;\n"
+ buf += " TF_CIT_TMPL(fabric)->tfc_tpg_param_cit.ct_attrs = NULL;\n"
+ buf += " TF_CIT_TMPL(fabric)->tfc_tpg_np_base_cit.ct_attrs = NULL;\n"
+ buf += " TF_CIT_TMPL(fabric)->tfc_tpg_nacl_base_cit.ct_attrs = NULL;\n"
+ buf += " TF_CIT_TMPL(fabric)->tfc_tpg_nacl_attrib_cit.ct_attrs = NULL;\n"
+ buf += " TF_CIT_TMPL(fabric)->tfc_tpg_nacl_auth_cit.ct_attrs = NULL;\n"
+ buf += " TF_CIT_TMPL(fabric)->tfc_tpg_nacl_param_cit.ct_attrs = NULL;\n"
+ buf += " /*\n"
+ buf += " * Register the fabric for use within TCM\n"
+ buf += " */\n"
+ buf += " ret = target_fabric_configfs_register(fabric);\n"
+ buf += " if (ret < 0) {\n"
+ buf += " printk(KERN_ERR \"target_fabric_configfs_register() failed\"\n"
+ buf += " \" for " + fabric_mod_name.upper() + "\\n\");\n"
+ buf += " return ret;\n"
+ buf += " }\n"
+ buf += " /*\n"
+ buf += " * Setup our local pointer to *fabric\n"
+ buf += " */\n"
+ buf += " " + fabric_mod_name + "_fabric_configfs = fabric;\n"
+ buf += " printk(KERN_INFO \"" + fabric_mod_name.upper() + "[0] - Set fabric -> " + fabric_mod_name + "_fabric_configfs\\n\");\n"
+ buf += " return 0;\n"
+ buf += "};\n\n"
+ buf += "static void " + fabric_mod_name + "_deregister_configfs(void)\n"
+ buf += "{\n"
+ buf += " if (!(" + fabric_mod_name + "_fabric_configfs))\n"
+ buf += " return;\n\n"
+ buf += " target_fabric_configfs_deregister(" + fabric_mod_name + "_fabric_configfs);\n"
+ buf += " " + fabric_mod_name + "_fabric_configfs = NULL;\n"
+ buf += " printk(KERN_INFO \"" + fabric_mod_name.upper() + "[0] - Cleared " + fabric_mod_name + "_fabric_configfs\\n\");\n"
+ buf += "};\n\n"
+
+ buf += "static int __init " + fabric_mod_name + "_init(void)\n"
+ buf += "{\n"
+ buf += " int ret;\n\n"
+ buf += " ret = " + fabric_mod_name + "_register_configfs();\n"
+ buf += " if (ret < 0)\n"
+ buf += " return ret;\n\n"
+ buf += " return 0;\n"
+ buf += "};\n\n"
+ buf += "static void " + fabric_mod_name + "_exit(void)\n"
+ buf += "{\n"
+ buf += " " + fabric_mod_name + "_deregister_configfs();\n"
+ buf += "};\n\n"
+
+ buf += "#ifdef MODULE\n"
+ buf += "MODULE_DESCRIPTION(\"" + fabric_mod_name.upper() + " series fabric driver\");\n"
+ buf += "MODULE_LICENSE(\"GPL\");\n"
+ buf += "module_init(" + fabric_mod_name + "_init);\n"
+ buf += "module_exit(" + fabric_mod_name + "_exit);\n"
+ buf += "#endif\n"
+
+ ret = p.write(buf)
+ if ret:
+ tcm_mod_err("Unable to write f: " + f)
+
+ p.close()
+
+ return
+
+def tcm_mod_scan_fabric_ops(tcm_dir):
+
+ fabric_ops_api = tcm_dir + "include/target/target_core_fabric_ops.h"
+
+ print "Using tcm_mod_scan_fabric_ops: " + fabric_ops_api
+ process_fo = 0;
+
+ p = open(fabric_ops_api, 'r')
+
+ line = p.readline()
+ while line:
+ if process_fo == 0 and re.search('struct target_core_fabric_ops {', line):
+ line = p.readline()
+ continue
+
+ if process_fo == 0:
+ process_fo = 1;
+ line = p.readline()
+ # Search for function pointer
+ if not re.search('\(\*', line):
+ continue
+
+ fabric_ops.append(line.rstrip())
+ continue
+
+ line = p.readline()
+ # Search for function pointer
+ if not re.search('\(\*', line):
+ continue
+
+ fabric_ops.append(line.rstrip())
+
+ p.close()
+ return
+
+def tcm_mod_dump_fabric_ops(proto_ident, fabric_mod_dir_var, fabric_mod_name):
+ buf = ""
+ bufi = ""
+
+ f = fabric_mod_dir_var + "/" + fabric_mod_name + "_fabric.c"
+ print "Writing file: " + f
+
+ p = open(f, 'w')
+ if not p:
+ tcm_mod_err("Unable to open file: " + f)
+
+ fi = fabric_mod_dir_var + "/" + fabric_mod_name + "_fabric.h"
+ print "Writing file: " + fi
+
+ pi = open(fi, 'w')
+ if not pi:
+ tcm_mod_err("Unable to open file: " + fi)
+
+ buf = "#include <linux/slab.h>\n"
+ buf += "#include <linux/kthread.h>\n"
+ buf += "#include <linux/types.h>\n"
+ buf += "#include <linux/list.h>\n"
+ buf += "#include <linux/types.h>\n"
+ buf += "#include <linux/string.h>\n"
+ buf += "#include <linux/ctype.h>\n"
+ buf += "#include <asm/unaligned.h>\n"
+ buf += "#include <scsi/scsi.h>\n"
+ buf += "#include <scsi/scsi_host.h>\n"
+ buf += "#include <scsi/scsi_device.h>\n"
+ buf += "#include <scsi/scsi_cmnd.h>\n"
+ buf += "#include <scsi/libfc.h>\n\n"
+ buf += "#include <target/target_core_base.h>\n"
+ buf += "#include <target/target_core_transport.h>\n"
+ buf += "#include <target/target_core_fabric_ops.h>\n"
+ buf += "#include <target/target_core_fabric_lib.h>\n"
+ buf += "#include <target/target_core_device.h>\n"
+ buf += "#include <target/target_core_tpg.h>\n"
+ buf += "#include <target/target_core_configfs.h>\n"
+ buf += "#include <" + fabric_mod_name + "_base.h>\n"
+ buf += "#include <" + fabric_mod_name + "_fabric.h>\n\n"
+
+ buf += "int " + fabric_mod_name + "_check_true(struct se_portal_group *se_tpg)\n"
+ buf += "{\n"
+ buf += " return 1;\n"
+ buf += "}\n\n"
+ bufi += "int " + fabric_mod_name + "_check_true(struct se_portal_group *);\n"
+
+ buf += "int " + fabric_mod_name + "_check_false(struct se_portal_group *se_tpg)\n"
+ buf += "{\n"
+ buf += " return 0;\n"
+ buf += "}\n\n"
+ bufi += "int " + fabric_mod_name + "_check_false(struct se_portal_group *);\n"
+
+ total_fabric_ops = len(fabric_ops)
+ i = 0
+
+ while i < total_fabric_ops:
+ fo = fabric_ops[i]
+ i += 1
+# print "fabric_ops: " + fo
+
+ if re.search('get_fabric_name', fo):
+ buf += "char *" + fabric_mod_name + "_get_fabric_name(void)\n"
+ buf += "{\n"
+ buf += " return \"" + fabric_mod_name[4:] + "\";\n"
+ buf += "}\n\n"
+ bufi += "char *" + fabric_mod_name + "_get_fabric_name(void);\n"
+ continue
+
+ if re.search('get_fabric_proto_ident', fo):
+ buf += "u8 " + fabric_mod_name + "_get_fabric_proto_ident(struct se_portal_group *se_tpg)\n"
+ buf += "{\n"
+ buf += " struct " + fabric_mod_name + "_tpg *tpg = container_of(se_tpg,\n"
+ buf += " struct " + fabric_mod_name + "_tpg, se_tpg);\n"
+ buf += " struct " + fabric_mod_name + "_" + fabric_mod_port + " *" + fabric_mod_port + " = tpg->" + fabric_mod_port + ";\n"
+ buf += " u8 proto_id;\n\n"
+ buf += " switch (" + fabric_mod_port + "->" + fabric_mod_port + "_proto_id) {\n"
+ if proto_ident == "FC":
+ buf += " case SCSI_PROTOCOL_FCP:\n"
+ buf += " default:\n"
+ buf += " proto_id = fc_get_fabric_proto_ident(se_tpg);\n"
+ buf += " break;\n"
+ elif proto_ident == "SAS":
+ buf += " case SCSI_PROTOCOL_SAS:\n"
+ buf += " default:\n"
+ buf += " proto_id = sas_get_fabric_proto_ident(se_tpg);\n"
+ buf += " break;\n"
+ elif proto_ident == "iSCSI":
+ buf += " case SCSI_PROTOCOL_ISCSI:\n"
+ buf += " default:\n"
+ buf += " proto_id = iscsi_get_fabric_proto_ident(se_tpg);\n"
+ buf += " break;\n"
+
+ buf += " }\n\n"
+ buf += " return proto_id;\n"
+ buf += "}\n\n"
+ bufi += "u8 " + fabric_mod_name + "_get_fabric_proto_ident(struct se_portal_group *);\n"
+
+ if re.search('get_wwn', fo):
+ buf += "char *" + fabric_mod_name + "_get_fabric_wwn(struct se_portal_group *se_tpg)\n"
+ buf += "{\n"
+ buf += " struct " + fabric_mod_name + "_tpg *tpg = container_of(se_tpg,\n"
+ buf += " struct " + fabric_mod_name + "_tpg, se_tpg);\n"
+ buf += " struct " + fabric_mod_name + "_" + fabric_mod_port + " *" + fabric_mod_port + " = tpg->" + fabric_mod_port + ";\n\n"
+ buf += " return &" + fabric_mod_port + "->" + fabric_mod_port + "_name[0];\n"
+ buf += "}\n\n"
+ bufi += "char *" + fabric_mod_name + "_get_fabric_wwn(struct se_portal_group *);\n"
+
+ if re.search('get_tag', fo):
+ buf += "u16 " + fabric_mod_name + "_get_tag(struct se_portal_group *se_tpg)\n"
+ buf += "{\n"
+ buf += " struct " + fabric_mod_name + "_tpg *tpg = container_of(se_tpg,\n"
+ buf += " struct " + fabric_mod_name + "_tpg, se_tpg);\n"
+ buf += " return tpg->" + fabric_mod_port + "_tpgt;\n"
+ buf += "}\n\n"
+ bufi += "u16 " + fabric_mod_name + "_get_tag(struct se_portal_group *);\n"
+
+ if re.search('get_default_depth', fo):
+ buf += "u32 " + fabric_mod_name + "_get_default_depth(struct se_portal_group *se_tpg)\n"
+ buf += "{\n"
+ buf += " return 1;\n"
+ buf += "}\n\n"
+ bufi += "u32 " + fabric_mod_name + "_get_default_depth(struct se_portal_group *);\n"
+
+ if re.search('get_pr_transport_id\)\(', fo):
+ buf += "u32 " + fabric_mod_name + "_get_pr_transport_id(\n"
+ buf += " struct se_portal_group *se_tpg,\n"
+ buf += " struct se_node_acl *se_nacl,\n"
+ buf += " struct t10_pr_registration *pr_reg,\n"
+ buf += " int *format_code,\n"
+ buf += " unsigned char *buf)\n"
+ buf += "{\n"
+ buf += " struct " + fabric_mod_name + "_tpg *tpg = container_of(se_tpg,\n"
+ buf += " struct " + fabric_mod_name + "_tpg, se_tpg);\n"
+ buf += " struct " + fabric_mod_name + "_" + fabric_mod_port + " *" + fabric_mod_port + " = tpg->" + fabric_mod_port + ";\n"
+ buf += " int ret = 0;\n\n"
+ buf += " switch (" + fabric_mod_port + "->" + fabric_mod_port + "_proto_id) {\n"
+ if proto_ident == "FC":
+ buf += " case SCSI_PROTOCOL_FCP:\n"
+ buf += " default:\n"
+ buf += " ret = fc_get_pr_transport_id(se_tpg, se_nacl, pr_reg,\n"
+ buf += " format_code, buf);\n"
+ buf += " break;\n"
+ elif proto_ident == "SAS":
+ buf += " case SCSI_PROTOCOL_SAS:\n"
+ buf += " default:\n"
+ buf += " ret = sas_get_pr_transport_id(se_tpg, se_nacl, pr_reg,\n"
+ buf += " format_code, buf);\n"
+ buf += " break;\n"
+ elif proto_ident == "iSCSI":
+ buf += " case SCSI_PROTOCOL_ISCSI:\n"
+ buf += " default:\n"
+ buf += " ret = iscsi_get_pr_transport_id(se_tpg, se_nacl, pr_reg,\n"
+ buf += " format_code, buf);\n"
+ buf += " break;\n"
+
+ buf += " }\n\n"
+ buf += " return ret;\n"
+ buf += "}\n\n"
+ bufi += "u32 " + fabric_mod_name + "_get_pr_transport_id(struct se_portal_group *,\n"
+ bufi += " struct se_node_acl *, struct t10_pr_registration *,\n"
+ bufi += " int *, unsigned char *);\n"
+
+ if re.search('get_pr_transport_id_len\)\(', fo):
+ buf += "u32 " + fabric_mod_name + "_get_pr_transport_id_len(\n"
+ buf += " struct se_portal_group *se_tpg,\n"
+ buf += " struct se_node_acl *se_nacl,\n"
+ buf += " struct t10_pr_registration *pr_reg,\n"
+ buf += " int *format_code)\n"
+ buf += "{\n"
+ buf += " struct " + fabric_mod_name + "_tpg *tpg = container_of(se_tpg,\n"
+ buf += " struct " + fabric_mod_name + "_tpg, se_tpg);\n"
+ buf += " struct " + fabric_mod_name + "_" + fabric_mod_port + " *" + fabric_mod_port + " = tpg->" + fabric_mod_port + ";\n"
+ buf += " int ret = 0;\n\n"
+ buf += " switch (" + fabric_mod_port + "->" + fabric_mod_port + "_proto_id) {\n"
+ if proto_ident == "FC":
+ buf += " case SCSI_PROTOCOL_FCP:\n"
+ buf += " default:\n"
+ buf += " ret = fc_get_pr_transport_id_len(se_tpg, se_nacl, pr_reg,\n"
+ buf += " format_code);\n"
+ buf += " break;\n"
+ elif proto_ident == "SAS":
+ buf += " case SCSI_PROTOCOL_SAS:\n"
+ buf += " default:\n"
+ buf += " ret = sas_get_pr_transport_id_len(se_tpg, se_nacl, pr_reg,\n"
+ buf += " format_code);\n"
+ buf += " break;\n"
+ elif proto_ident == "iSCSI":
+ buf += " case SCSI_PROTOCOL_ISCSI:\n"
+ buf += " default:\n"
+ buf += " ret = iscsi_get_pr_transport_id_len(se_tpg, se_nacl, pr_reg,\n"
+ buf += " format_code);\n"
+ buf += " break;\n"
+
+
+ buf += " }\n\n"
+ buf += " return ret;\n"
+ buf += "}\n\n"
+ bufi += "u32 " + fabric_mod_name + "_get_pr_transport_id_len(struct se_portal_group *,\n"
+ bufi += " struct se_node_acl *, struct t10_pr_registration *,\n"
+ bufi += " int *);\n"
+
+ if re.search('parse_pr_out_transport_id\)\(', fo):
+ buf += "char *" + fabric_mod_name + "_parse_pr_out_transport_id(\n"
+ buf += " struct se_portal_group *se_tpg,\n"
+ buf += " const char *buf,\n"
+ buf += " u32 *out_tid_len,\n"
+ buf += " char **port_nexus_ptr)\n"
+ buf += "{\n"
+ buf += " struct " + fabric_mod_name + "_tpg *tpg = container_of(se_tpg,\n"
+ buf += " struct " + fabric_mod_name + "_tpg, se_tpg);\n"
+ buf += " struct " + fabric_mod_name + "_" + fabric_mod_port + " *" + fabric_mod_port + " = tpg->" + fabric_mod_port + ";\n"
+ buf += " char *tid = NULL;\n\n"
+ buf += " switch (" + fabric_mod_port + "->" + fabric_mod_port + "_proto_id) {\n"
+ if proto_ident == "FC":
+ buf += " case SCSI_PROTOCOL_FCP:\n"
+ buf += " default:\n"
+ buf += " tid = fc_parse_pr_out_transport_id(se_tpg, buf, out_tid_len,\n"
+ buf += " port_nexus_ptr);\n"
+ elif proto_ident == "SAS":
+ buf += " case SCSI_PROTOCOL_SAS:\n"
+ buf += " default:\n"
+ buf += " tid = sas_parse_pr_out_transport_id(se_tpg, buf, out_tid_len,\n"
+ buf += " port_nexus_ptr);\n"
+ elif proto_ident == "iSCSI":
+ buf += " case SCSI_PROTOCOL_ISCSI:\n"
+ buf += " default:\n"
+ buf += " tid = iscsi_parse_pr_out_transport_id(se_tpg, buf, out_tid_len,\n"
+ buf += " port_nexus_ptr);\n"
+
+ buf += " }\n\n"
+ buf += " return tid;\n"
+ buf += "}\n\n"
+ bufi += "char *" + fabric_mod_name + "_parse_pr_out_transport_id(struct se_portal_group *,\n"
+ bufi += " const char *, u32 *, char **);\n"
+
+ if re.search('alloc_fabric_acl\)\(', fo):
+ buf += "struct se_node_acl *" + fabric_mod_name + "_alloc_fabric_acl(struct se_portal_group *se_tpg)\n"
+ buf += "{\n"
+ buf += " struct " + fabric_mod_name + "_nacl *nacl;\n\n"
+ buf += " nacl = kzalloc(sizeof(struct " + fabric_mod_name + "_nacl), GFP_KERNEL);\n"
+ buf += " if (!(nacl)) {\n"
+ buf += " printk(KERN_ERR \"Unable to alocate struct " + fabric_mod_name + "_nacl\\n\");\n"
+ buf += " return NULL;\n"
+ buf += " }\n\n"
+ buf += " return &nacl->se_node_acl;\n"
+ buf += "}\n\n"
+ bufi += "struct se_node_acl *" + fabric_mod_name + "_alloc_fabric_acl(struct se_portal_group *);\n"
+
+ if re.search('release_fabric_acl\)\(', fo):
+ buf += "void " + fabric_mod_name + "_release_fabric_acl(\n"
+ buf += " struct se_portal_group *se_tpg,\n"
+ buf += " struct se_node_acl *se_nacl)\n"
+ buf += "{\n"
+ buf += " struct " + fabric_mod_name + "_nacl *nacl = container_of(se_nacl,\n"
+ buf += " struct " + fabric_mod_name + "_nacl, se_node_acl);\n"
+ buf += " kfree(nacl);\n"
+ buf += "}\n\n"
+ bufi += "void " + fabric_mod_name + "_release_fabric_acl(struct se_portal_group *,\n"
+ bufi += " struct se_node_acl *);\n"
+
+ if re.search('tpg_get_inst_index\)\(', fo):
+ buf += "u32 " + fabric_mod_name + "_tpg_get_inst_index(struct se_portal_group *se_tpg)\n"
+ buf += "{\n"
+ buf += " return 1;\n"
+ buf += "}\n\n"
+ bufi += "u32 " + fabric_mod_name + "_tpg_get_inst_index(struct se_portal_group *);\n"
+
+ if re.search('release_cmd_to_pool', fo):
+ buf += "void " + fabric_mod_name + "_release_cmd(struct se_cmd *se_cmd)\n"
+ buf += "{\n"
+ buf += " return;\n"
+ buf += "}\n\n"
+ bufi += "void " + fabric_mod_name + "_release_cmd(struct se_cmd *);\n"
+
+ if re.search('shutdown_session\)\(', fo):
+ buf += "int " + fabric_mod_name + "_shutdown_session(struct se_session *se_sess)\n"
+ buf += "{\n"
+ buf += " return 0;\n"
+ buf += "}\n\n"
+ bufi += "int " + fabric_mod_name + "_shutdown_session(struct se_session *);\n"
+
+ if re.search('close_session\)\(', fo):
+ buf += "void " + fabric_mod_name + "_close_session(struct se_session *se_sess)\n"
+ buf += "{\n"
+ buf += " return;\n"
+ buf += "}\n\n"
+ bufi += "void " + fabric_mod_name + "_close_session(struct se_session *);\n"
+
+ if re.search('stop_session\)\(', fo):
+ buf += "void " + fabric_mod_name + "_stop_session(struct se_session *se_sess, int sess_sleep , int conn_sleep)\n"
+ buf += "{\n"
+ buf += " return;\n"
+ buf += "}\n\n"
+ bufi += "void " + fabric_mod_name + "_stop_session(struct se_session *, int, int);\n"
+
+ if re.search('fall_back_to_erl0\)\(', fo):
+ buf += "void " + fabric_mod_name + "_reset_nexus(struct se_session *se_sess)\n"
+ buf += "{\n"
+ buf += " return;\n"
+ buf += "}\n\n"
+ bufi += "void " + fabric_mod_name + "_reset_nexus(struct se_session *);\n"
+
+ if re.search('sess_logged_in\)\(', fo):
+ buf += "int " + fabric_mod_name + "_sess_logged_in(struct se_session *se_sess)\n"
+ buf += "{\n"
+ buf += " return 0;\n"
+ buf += "}\n\n"
+ bufi += "int " + fabric_mod_name + "_sess_logged_in(struct se_session *);\n"
+
+ if re.search('sess_get_index\)\(', fo):
+ buf += "u32 " + fabric_mod_name + "_sess_get_index(struct se_session *se_sess)\n"
+ buf += "{\n"
+ buf += " return 0;\n"
+ buf += "}\n\n"
+ bufi += "u32 " + fabric_mod_name + "_sess_get_index(struct se_session *);\n"
+
+ if re.search('write_pending\)\(', fo):
+ buf += "int " + fabric_mod_name + "_write_pending(struct se_cmd *se_cmd)\n"
+ buf += "{\n"
+ buf += " return 0;\n"
+ buf += "}\n\n"
+ bufi += "int " + fabric_mod_name + "_write_pending(struct se_cmd *);\n"
+
+ if re.search('write_pending_status\)\(', fo):
+ buf += "int " + fabric_mod_name + "_write_pending_status(struct se_cmd *se_cmd)\n"
+ buf += "{\n"
+ buf += " return 0;\n"
+ buf += "}\n\n"
+ bufi += "int " + fabric_mod_name + "_write_pending_status(struct se_cmd *);\n"
+
+ if re.search('set_default_node_attributes\)\(', fo):
+ buf += "void " + fabric_mod_name + "_set_default_node_attrs(struct se_node_acl *nacl)\n"
+ buf += "{\n"
+ buf += " return;\n"
+ buf += "}\n\n"
+ bufi += "void " + fabric_mod_name + "_set_default_node_attrs(struct se_node_acl *);\n"
+
+ if re.search('get_task_tag\)\(', fo):
+ buf += "u32 " + fabric_mod_name + "_get_task_tag(struct se_cmd *se_cmd)\n"
+ buf += "{\n"
+ buf += " return 0;\n"
+ buf += "}\n\n"
+ bufi += "u32 " + fabric_mod_name + "_get_task_tag(struct se_cmd *);\n"
+
+ if re.search('get_cmd_state\)\(', fo):
+ buf += "int " + fabric_mod_name + "_get_cmd_state(struct se_cmd *se_cmd)\n"
+ buf += "{\n"
+ buf += " return 0;\n"
+ buf += "}\n\n"
+ bufi += "int " + fabric_mod_name + "_get_cmd_state(struct se_cmd *);\n"
+
+ if re.search('new_cmd_failure\)\(', fo):
+ buf += "void " + fabric_mod_name + "_new_cmd_failure(struct se_cmd *se_cmd)\n"
+ buf += "{\n"
+ buf += " return;\n"
+ buf += "}\n\n"
+ bufi += "void " + fabric_mod_name + "_new_cmd_failure(struct se_cmd *);\n"
+
+ if re.search('queue_data_in\)\(', fo):
+ buf += "int " + fabric_mod_name + "_queue_data_in(struct se_cmd *se_cmd)\n"
+ buf += "{\n"
+ buf += " return 0;\n"
+ buf += "}\n\n"
+ bufi += "int " + fabric_mod_name + "_queue_data_in(struct se_cmd *);\n"
+
+ if re.search('queue_status\)\(', fo):
+ buf += "int " + fabric_mod_name + "_queue_status(struct se_cmd *se_cmd)\n"
+ buf += "{\n"
+ buf += " return 0;\n"
+ buf += "}\n\n"
+ bufi += "int " + fabric_mod_name + "_queue_status(struct se_cmd *);\n"
+
+ if re.search('queue_tm_rsp\)\(', fo):
+ buf += "int " + fabric_mod_name + "_queue_tm_rsp(struct se_cmd *se_cmd)\n"
+ buf += "{\n"
+ buf += " return 0;\n"
+ buf += "}\n\n"
+ bufi += "int " + fabric_mod_name + "_queue_tm_rsp(struct se_cmd *);\n"
+
+ if re.search('get_fabric_sense_len\)\(', fo):
+ buf += "u16 " + fabric_mod_name + "_get_fabric_sense_len(void)\n"
+ buf += "{\n"
+ buf += " return 0;\n"
+ buf += "}\n\n"
+ bufi += "u16 " + fabric_mod_name + "_get_fabric_sense_len(void);\n"
+
+ if re.search('set_fabric_sense_len\)\(', fo):
+ buf += "u16 " + fabric_mod_name + "_set_fabric_sense_len(struct se_cmd *se_cmd, u32 sense_length)\n"
+ buf += "{\n"
+ buf += " return 0;\n"
+ buf += "}\n\n"
+ bufi += "u16 " + fabric_mod_name + "_set_fabric_sense_len(struct se_cmd *, u32);\n"
+
+ if re.search('is_state_remove\)\(', fo):
+ buf += "int " + fabric_mod_name + "_is_state_remove(struct se_cmd *se_cmd)\n"
+ buf += "{\n"
+ buf += " return 0;\n"
+ buf += "}\n\n"
+ bufi += "int " + fabric_mod_name + "_is_state_remove(struct se_cmd *);\n"
+
+ if re.search('pack_lun\)\(', fo):
+ buf += "u64 " + fabric_mod_name + "_pack_lun(unsigned int lun)\n"
+ buf += "{\n"
+ buf += " WARN_ON(lun >= 256);\n"
+ buf += " /* Caller wants this byte-swapped */\n"
+ buf += " return cpu_to_le64((lun & 0xff) << 8);\n"
+ buf += "}\n\n"
+ bufi += "u64 " + fabric_mod_name + "_pack_lun(unsigned int);\n"
+
+
+ ret = p.write(buf)
+ if ret:
+ tcm_mod_err("Unable to write f: " + f)
+
+ p.close()
+
+ ret = pi.write(bufi)
+ if ret:
+ tcm_mod_err("Unable to write fi: " + fi)
+
+ pi.close()
+ return
+
+def tcm_mod_build_kbuild(fabric_mod_dir_var, fabric_mod_name):
+
+ buf = ""
+ f = fabric_mod_dir_var + "/Kbuild"
+ print "Writing file: " + f
+
+ p = open(f, 'w')
+ if not p:
+ tcm_mod_err("Unable to open file: " + f)
+
+ buf = "EXTRA_CFLAGS += -I$(srctree)/drivers/target/ -I$(srctree)/include/ -I$(srctree)/drivers/scsi/ -I$(srctree)/include/scsi/ -I$(srctree)/drivers/target/" + fabric_mod_name + "\n\n"
+ buf += fabric_mod_name + "-objs := " + fabric_mod_name + "_fabric.o \\\n"
+ buf += " " + fabric_mod_name + "_configfs.o\n"
+ buf += "obj-$(CONFIG_" + fabric_mod_name.upper() + ") += " + fabric_mod_name + ".o\n"
+
+ ret = p.write(buf)
+ if ret:
+ tcm_mod_err("Unable to write f: " + f)
+
+ p.close()
+ return
+
+def tcm_mod_build_kconfig(fabric_mod_dir_var, fabric_mod_name):
+
+ buf = ""
+ f = fabric_mod_dir_var + "/Kconfig"
+ print "Writing file: " + f
+
+ p = open(f, 'w')
+ if not p:
+ tcm_mod_err("Unable to open file: " + f)
+
+ buf = "config " + fabric_mod_name.upper() + "\n"
+ buf += " tristate \"" + fabric_mod_name.upper() + " fabric module\"\n"
+ buf += " depends on TARGET_CORE && CONFIGFS_FS\n"
+ buf += " default n\n"
+ buf += " ---help---\n"
+ buf += " Say Y here to enable the " + fabric_mod_name.upper() + " fabric module\n"
+
+ ret = p.write(buf)
+ if ret:
+ tcm_mod_err("Unable to write f: " + f)
+
+ p.close()
+ return
+
+def tcm_mod_add_kbuild(tcm_dir, fabric_mod_name):
+ buf = "obj-$(CONFIG_" + fabric_mod_name.upper() + ") += " + fabric_mod_name.lower() + "/\n"
+ kbuild = tcm_dir + "/drivers/target/Kbuild"
+
+ f = open(kbuild, 'a')
+ f.write(buf)
+ f.close()
+ return
+
+def tcm_mod_add_kconfig(tcm_dir, fabric_mod_name):
+ buf = "source \"drivers/target/" + fabric_mod_name.lower() + "/Kconfig\"\n"
+ kconfig = tcm_dir + "/drivers/target/Kconfig"
+
+ f = open(kconfig, 'a')
+ f.write(buf)
+ f.close()
+ return
+
+def main(modname, proto_ident):
+# proto_ident = "FC"
+# proto_ident = "SAS"
+# proto_ident = "iSCSI"
+
+ tcm_dir = os.getcwd();
+ tcm_dir += "/../../"
+ print "tcm_dir: " + tcm_dir
+ fabric_mod_name = modname
+ fabric_mod_dir = tcm_dir + "drivers/target/" + fabric_mod_name
+ print "Set fabric_mod_name: " + fabric_mod_name
+ print "Set fabric_mod_dir: " + fabric_mod_dir
+ print "Using proto_ident: " + proto_ident
+
+ if proto_ident != "FC" and proto_ident != "SAS" and proto_ident != "iSCSI":
+ print "Unsupported proto_ident: " + proto_ident
+ sys.exit(1)
+
+ ret = tcm_mod_create_module_subdir(fabric_mod_dir)
+ if ret:
+ print "tcm_mod_create_module_subdir() failed because module already exists!"
+ sys.exit(1)
+
+ tcm_mod_build_base_includes(proto_ident, fabric_mod_dir, fabric_mod_name)
+ tcm_mod_scan_fabric_ops(tcm_dir)
+ tcm_mod_dump_fabric_ops(proto_ident, fabric_mod_dir, fabric_mod_name)
+ tcm_mod_build_configfs(proto_ident, fabric_mod_dir, fabric_mod_name)
+ tcm_mod_build_kbuild(fabric_mod_dir, fabric_mod_name)
+ tcm_mod_build_kconfig(fabric_mod_dir, fabric_mod_name)
+
+ input = raw_input("Would you like to add " + fabric_mod_name + "to drivers/target/Kbuild..? [yes,no]: ")
+ if input == "yes" or input == "y":
+ tcm_mod_add_kbuild(tcm_dir, fabric_mod_name)
+
+ input = raw_input("Would you like to add " + fabric_mod_name + "to drivers/target/Kconfig..? [yes,no]: ")
+ if input == "yes" or input == "y":
+ tcm_mod_add_kconfig(tcm_dir, fabric_mod_name)
+
+ return
+
+parser = optparse.OptionParser()
+parser.add_option('-m', '--modulename', help='Module name', dest='modname',
+ action='store', nargs=1, type='string')
+parser.add_option('-p', '--protoident', help='Protocol Ident', dest='protoident',
+ action='store', nargs=1, type='string')
+
+(opts, args) = parser.parse_args()
+
+mandatories = ['modname', 'protoident']
+for m in mandatories:
+ if not opts.__dict__[m]:
+ print "mandatory option is missing\n"
+ parser.print_help()
+ exit(-1)
+
+if __name__ == "__main__":
+
+ main(str(opts.modname), opts.protoident)
diff --git a/Documentation/target/tcm_mod_builder.txt b/Documentation/target/tcm_mod_builder.txt
new file mode 100644
index 0000000..84533d8
--- /dev/null
+++ b/Documentation/target/tcm_mod_builder.txt
@@ -0,0 +1,145 @@
+>>>>>>>>>> The TCM v4 fabric module script generator <<<<<<<<<<
+
+Greetings all,
+
+This document is intended to be a mini-HOWTO for using the tcm_mod_builder.py
+script to generate a brand new functional TCM v4 fabric .ko module of your very own,
+that once built can be immediately be loaded to start access the new TCM/ConfigFS
+fabric skeleton, by simply using:
+
+ modprobe $TCM_NEW_MOD
+ mkdir -p /sys/kernel/config/target/$TCM_NEW_MOD
+
+This script will create a new drivers/target/$TCM_NEW_MOD/, and will do the following
+
+ *) Generate new API callers for drivers/target/target_core_fabric_configs.c logic
+ ->make_nodeacl(), ->drop_nodeacl(), ->make_tpg(), ->drop_tpg()
+ ->make_wwn(), ->drop_wwn(). These are created into $TCM_NEW_MOD/$TCM_NEW_MOD_configfs.c
+ *) Generate basic infrastructure for loading/unloading LKMs and TCM/ConfigFS fabric module
+ using a skeleton struct target_core_fabric_ops API template.
+ *) Based on user defined T10 Proto_Ident for the new fabric module being built,
+ the TransportID / Initiator and Target WWPN related handlers for
+ SPC-3 persistent reservation are automatically generated in $TCM_NEW_MOD/$TCM_NEW_MOD_fabric.c
+ using drivers/target/target_core_fabric_lib.c logic.
+ *) NOP API calls for all other Data I/O path and fabric dependent attribute logic
+ in $TCM_NEW_MOD/$TCM_NEW_MOD_fabric.c
+
+tcm_mod_builder.py depends upon the mandatory '-p $PROTO_IDENT' and '-m
+$FABRIC_MOD_name' parameters, and actually running the script looks like:
+
+target:/mnt/sdb/lio-core-2.6.git/Documentation/target# python tcm_mod_builder.py -p iSCSI -m tcm_nab5000
+tcm_dir: /mnt/sdb/lio-core-2.6.git/Documentation/target/../../
+Set fabric_mod_name: tcm_nab5000
+Set fabric_mod_dir:
+/mnt/sdb/lio-core-2.6.git/Documentation/target/../../drivers/target/tcm_nab5000
+Using proto_ident: iSCSI
+Creating fabric_mod_dir:
+/mnt/sdb/lio-core-2.6.git/Documentation/target/../../drivers/target/tcm_nab5000
+Writing file:
+/mnt/sdb/lio-core-2.6.git/Documentation/target/../../drivers/target/tcm_nab5000/tcm_nab5000_base.h
+Using tcm_mod_scan_fabric_ops:
+/mnt/sdb/lio-core-2.6.git/Documentation/target/../../include/target/target_core_fabric_ops.h
+Writing file:
+/mnt/sdb/lio-core-2.6.git/Documentation/target/../../drivers/target/tcm_nab5000/tcm_nab5000_fabric.c
+Writing file:
+/mnt/sdb/lio-core-2.6.git/Documentation/target/../../drivers/target/tcm_nab5000/tcm_nab5000_fabric.h
+Writing file:
+/mnt/sdb/lio-core-2.6.git/Documentation/target/../../drivers/target/tcm_nab5000/tcm_nab5000_configfs.c
+Writing file:
+/mnt/sdb/lio-core-2.6.git/Documentation/target/../../drivers/target/tcm_nab5000/Kbuild
+Writing file:
+/mnt/sdb/lio-core-2.6.git/Documentation/target/../../drivers/target/tcm_nab5000/Kconfig
+Would you like to add tcm_nab5000to drivers/target/Kbuild..? [yes,no]: yes
+Would you like to add tcm_nab5000to drivers/target/Kconfig..? [yes,no]: yes
+
+At the end of tcm_mod_builder.py. the script will ask to add the following
+line to drivers/target/Kbuild:
+
+ obj-$(CONFIG_TCM_NAB5000) += tcm_nab5000/
+
+and the same for drivers/target/Kconfig:
+
+ source "drivers/target/tcm_nab5000/Kconfig"
+
+*) Run 'make menuconfig' and select the new CONFIG_TCM_NAB5000 item:
+
+ <M> TCM_NAB5000 fabric module
+
+*) Build using 'make modules', once completed you will have:
+
+target:/mnt/sdb/lio-core-2.6.git# ls -la drivers/target/tcm_nab5000/
+total 1348
+drwxr-xr-x 2 root root 4096 2010-10-05 03:23 .
+drwxr-xr-x 9 root root 4096 2010-10-05 03:22 ..
+-rw-r--r-- 1 root root 282 2010-10-05 03:22 Kbuild
+-rw-r--r-- 1 root root 171 2010-10-05 03:22 Kconfig
+-rw-r--r-- 1 root root 49 2010-10-05 03:23 modules.order
+-rw-r--r-- 1 root root 738 2010-10-05 03:22 tcm_nab5000_base.h
+-rw-r--r-- 1 root root 9096 2010-10-05 03:22 tcm_nab5000_configfs.c
+-rw-r--r-- 1 root root 191200 2010-10-05 03:23 tcm_nab5000_configfs.o
+-rw-r--r-- 1 root root 40504 2010-10-05 03:23 .tcm_nab5000_configfs.o.cmd
+-rw-r--r-- 1 root root 5414 2010-10-05 03:22 tcm_nab5000_fabric.c
+-rw-r--r-- 1 root root 2016 2010-10-05 03:22 tcm_nab5000_fabric.h
+-rw-r--r-- 1 root root 190932 2010-10-05 03:23 tcm_nab5000_fabric.o
+-rw-r--r-- 1 root root 40713 2010-10-05 03:23 .tcm_nab5000_fabric.o.cmd
+-rw-r--r-- 1 root root 401861 2010-10-05 03:23 tcm_nab5000.ko
+-rw-r--r-- 1 root root 265 2010-10-05 03:23 .tcm_nab5000.ko.cmd
+-rw-r--r-- 1 root root 459 2010-10-05 03:23 tcm_nab5000.mod.c
+-rw-r--r-- 1 root root 23896 2010-10-05 03:23 tcm_nab5000.mod.o
+-rw-r--r-- 1 root root 22655 2010-10-05 03:23 .tcm_nab5000.mod.o.cmd
+-rw-r--r-- 1 root root 379022 2010-10-05 03:23 tcm_nab5000.o
+-rw-r--r-- 1 root root 211 2010-10-05 03:23 .tcm_nab5000.o.cmd
+
+*) Load the new module, create a lun_0 configfs group, and add new TCM Core
+ IBLOCK backstore symlink to port:
+
+target:/mnt/sdb/lio-core-2.6.git# insmod drivers/target/tcm_nab5000.ko
+target:/mnt/sdb/lio-core-2.6.git# mkdir -p /sys/kernel/config/target/nab5000/iqn.foo/tpgt_1/lun/lun_0
+target:/mnt/sdb/lio-core-2.6.git# cd /sys/kernel/config/target/nab5000/iqn.foo/tpgt_1/lun/lun_0/
+target:/sys/kernel/config/target/nab5000/iqn.foo/tpgt_1/lun/lun_0# ln -s /sys/kernel/config/target/core/iblock_0/lvm_test0 nab5000_port
+
+target:/sys/kernel/config/target/nab5000/iqn.foo/tpgt_1/lun/lun_0# cd -
+target:/mnt/sdb/lio-core-2.6.git# tree /sys/kernel/config/target/nab5000/
+/sys/kernel/config/target/nab5000/
+|-- discovery_auth
+|-- iqn.foo
+| `-- tpgt_1
+| |-- acls
+| |-- attrib
+| |-- lun
+| | `-- lun_0
+| | |-- alua_tg_pt_gp
+| | |-- alua_tg_pt_offline
+| | |-- alua_tg_pt_status
+| | |-- alua_tg_pt_write_md
+| | `-- nab5000_port -> ../../../../../../target/core/iblock_0/lvm_test0
+| |-- np
+| `-- param
+`-- version
+
+target:/mnt/sdb/lio-core-2.6.git# lsmod
+Module Size Used by
+tcm_nab5000 3935 4
+iscsi_target_mod 193211 0
+target_core_stgt 8090 0
+target_core_pscsi 11122 1
+target_core_file 9172 2
+target_core_iblock 9280 1
+target_core_mod 228575 31
+tcm_nab5000,iscsi_target_mod,target_core_stgt,target_core_pscsi,target_core_file,target_core_iblock
+libfc 73681 0
+scsi_debug 56265 0
+scsi_tgt 8666 1 target_core_stgt
+configfs 20644 2 target_core_mod
+
+----------------------------------------------------------------------
+
+Future TODO items:
+
+ *) Add more T10 proto_idents
+ *) Make tcm_mod_dump_fabric_ops() smarter and generate function pointer
+ defs directly from include/target/target_core_fabric_ops.h:struct target_core_fabric_ops
+ structure members.
+
+October 5th, 2010
+Nicholas A. Bellinger <nab@linux-iscsi.org>
diff --git a/Documentation/thermal/sysfs-api.txt b/Documentation/thermal/sysfs-api.txt
index cb3d15b..b61e46f 100644
--- a/Documentation/thermal/sysfs-api.txt
+++ b/Documentation/thermal/sysfs-api.txt
@@ -278,3 +278,15 @@ method, the sys I/F structure will be built like this:
|---name: acpitz
|---temp1_input: 37000
|---temp1_crit: 100000
+
+4. Event Notification
+
+The framework includes a simple notification mechanism, in the form of a
+netlink event. Netlink socket initialization is done during the _init_
+of the framework. Drivers which intend to use the notification mechanism
+just need to call generate_netlink_event() with two arguments viz
+(originator, event). Typically the originator will be an integer assigned
+to a thermal_zone_device when it registers itself with the framework. The
+event will be one of:{THERMAL_AUX0, THERMAL_AUX1, THERMAL_CRITICAL,
+THERMAL_DEV_FAULT}. Notification can be sent when the current temperature
+crosses any of the configured thresholds.
diff --git a/Documentation/video4linux/v4l2-controls.txt b/Documentation/video4linux/v4l2-controls.txt
index 8773778..881e7f4 100644
--- a/Documentation/video4linux/v4l2-controls.txt
+++ b/Documentation/video4linux/v4l2-controls.txt
@@ -285,6 +285,9 @@ implement g_volatile_ctrl like this:
The 'new value' union is not used in g_volatile_ctrl. In general controls
that need to implement g_volatile_ctrl are read-only controls.
+Note that if one or more controls in a control cluster are marked as volatile,
+then all the controls in the cluster are seen as volatile.
+
To mark a control as volatile you have to set the is_volatile flag:
ctrl = v4l2_ctrl_new_std(&sd->ctrl_handler, ...);
@@ -462,6 +465,15 @@ pointer to the v4l2_ctrl_ops struct that is used for that cluster.
Obviously, all controls in the cluster array must be initialized to either
a valid control or to NULL.
+In rare cases you might want to know which controls of a cluster actually
+were set explicitly by the user. For this you can check the 'is_new' flag of
+each control. For example, in the case of a volume/mute cluster the 'is_new'
+flag of the mute control would be set if the user called VIDIOC_S_CTRL for
+mute only. If the user would call VIDIOC_S_EXT_CTRLS for both mute and volume
+controls, then the 'is_new' flag would be 1 for both controls.
+
+The 'is_new' flag is always 1 when called from v4l2_ctrl_handler_setup().
+
VIDIOC_LOG_STATUS Support
=========================
diff --git a/MAINTAINERS b/MAINTAINERS
index af656de..cf0f3a5 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -162,7 +162,7 @@ L: linux-serial@vger.kernel.org
W: http://serial.sourceforge.net
S: Maintained
T: git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty-2.6.git
-F: drivers/serial/8250*
+F: drivers/tty/serial/8250*
F: include/linux/serial_8250.h
8390 NETWORK DRIVERS [WD80x3/SMC-ELITE, SMC-ULTRA, NE2000, 3C503, etc.]
@@ -624,11 +624,15 @@ M: Lennert Buytenhek <kernel@wantstofly.org>
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
S: Maintained
-ARM/ATMEL AT91RM9200 ARM ARCHITECTURE
+ARM/ATMEL AT91RM9200 AND AT91SAM ARM ARCHITECTURES
M: Andrew Victor <linux@maxim.org.za>
+M: Nicolas Ferre <nicolas.ferre@atmel.com>
+M: Jean-Christophe Plagniol-Villard <plagnioj@jcrosoft.com>
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
W: http://maxim.org.za/at91_26.html
-S: Maintained
+W: http://www.linux4sam.org
+S: Supported
+F: arch/arm/mach-at91/
ARM/BCMRING ARM ARCHITECTURE
M: Jiandong Zheng <jdzheng@broadcom.com>
@@ -888,8 +892,8 @@ F: arch/arm/mach-msm/
F: drivers/video/msm/
F: drivers/mmc/host/msm_sdcc.c
F: drivers/mmc/host/msm_sdcc.h
-F: drivers/serial/msm_serial.h
-F: drivers/serial/msm_serial.c
+F: drivers/tty/serial/msm_serial.h
+F: drivers/tty/serial/msm_serial.c
T: git git://codeaurora.org/quic/kernel/davidb/linux-msm.git
S: Maintained
@@ -1256,7 +1260,7 @@ F: drivers/mmc/host/atmel-mci-regs.h
ATMEL AT91 / AT32 SERIAL DRIVER
M: Nicolas Ferre <nicolas.ferre@atmel.com>
S: Supported
-F: drivers/serial/atmel_serial.c
+F: drivers/tty/serial/atmel_serial.c
ATMEL LCDFB DRIVER
M: Nicolas Ferre <nicolas.ferre@atmel.com>
@@ -1412,7 +1416,7 @@ M: Sonic Zhang <sonic.zhang@analog.com>
L: uclinux-dist-devel@blackfin.uclinux.org
W: http://blackfin.uclinux.org
S: Supported
-F: drivers/serial/bfin_5xx.c
+F: drivers/tty/serial/bfin_5xx.c
BLACKFIN WATCHDOG DRIVER
M: Mike Frysinger <vapier.adi@gmail.com>
@@ -1877,7 +1881,7 @@ L: linux-cris-kernel@axis.com
W: http://developer.axis.com
S: Maintained
F: arch/cris/
-F: drivers/serial/crisv10.*
+F: drivers/tty/serial/crisv10.*
CRYPTO API
M: Herbert Xu <herbert@gondor.apana.org.au>
@@ -2216,7 +2220,7 @@ F: drivers/net/wan/dscc4.c
DZ DECSTATION DZ11 SERIAL DRIVER
M: "Maciej W. Rozycki" <macro@linux-mips.org>
S: Maintained
-F: drivers/serial/dz.*
+F: drivers/tty/serial/dz.*
EATA-DMA SCSI DRIVER
M: Michael Neuffer <mike@i-Connect.Net>
@@ -2643,7 +2647,7 @@ FREESCALE QUICC ENGINE UCC UART DRIVER
M: Timur Tabi <timur@freescale.com>
L: linuxppc-dev@lists.ozlabs.org
S: Supported
-F: drivers/serial/ucc_uart.c
+F: drivers/tty/serial/ucc_uart.c
FREESCALE SOC SOUND DRIVERS
M: Timur Tabi <timur@freescale.com>
@@ -3146,7 +3150,7 @@ S: Orphan
F: drivers/video/imsttfb.c
INFINIBAND SUBSYSTEM
-M: Roland Dreier <rolandd@cisco.com>
+M: Roland Dreier <roland@kernel.org>
M: Sean Hefty <sean.hefty@intel.com>
M: Hal Rosenstock <hal.rosenstock@gmail.com>
L: linux-rdma@vger.kernel.org
@@ -3350,7 +3354,7 @@ IOC3 SERIAL DRIVER
M: Pat Gefre <pfg@sgi.com>
L: linux-serial@vger.kernel.org
S: Maintained
-F: drivers/serial/ioc3_serial.c
+F: drivers/tty/serial/ioc3_serial.c
IP MASQUERADING
M: Juanjo Ciarlante <jjciarla@raiz.uncu.edu.ar>
@@ -3527,7 +3531,7 @@ JSM Neo PCI based serial card
M: Breno Leitao <leitao@linux.vnet.ibm.com>
L: linux-serial@vger.kernel.org
S: Maintained
-F: drivers/serial/jsm/
+F: drivers/tty/serial/jsm/
K10TEMP HARDWARE MONITORING DRIVER
M: Clemens Ladisch <clemens@ladisch.de>
@@ -3670,6 +3674,28 @@ F: include/linux/key-type.h
F: include/keys/
F: security/keys/
+KEYS-TRUSTED
+M: David Safford <safford@watson.ibm.com>
+M: Mimi Zohar <zohar@us.ibm.com>
+L: linux-security-module@vger.kernel.org
+L: keyrings@linux-nfs.org
+S: Supported
+F: Documentation/keys-trusted-encrypted.txt
+F: include/keys/trusted-type.h
+F: security/keys/trusted.c
+F: security/keys/trusted.h
+
+KEYS-ENCRYPTED
+M: Mimi Zohar <zohar@us.ibm.com>
+M: David Safford <safford@watson.ibm.com>
+L: linux-security-module@vger.kernel.org
+L: keyrings@linux-nfs.org
+S: Supported
+F: Documentation/keys-trusted-encrypted.txt
+F: include/keys/encrypted-type.h
+F: security/keys/encrypted.c
+F: security/keys/encrypted.h
+
KGDB / KDB /debug_core
M: Jason Wessel <jason.wessel@windriver.com>
W: http://kgdb.wiki.kernel.org/
@@ -3677,14 +3703,14 @@ L: kgdb-bugreport@lists.sourceforge.net
S: Maintained
F: Documentation/DocBook/kgdb.tmpl
F: drivers/misc/kgdbts.c
-F: drivers/serial/kgdboc.c
+F: drivers/tty/serial/kgdboc.c
F: include/linux/kdb.h
F: include/linux/kgdb.h
F: kernel/debug/
KMEMCHECK
M: Vegard Nossum <vegardno@ifi.uio.no>
-M: Pekka Enberg <penberg@cs.helsinki.fi>
+M: Pekka Enberg <penberg@kernel.org>
S: Maintained
F: Documentation/kmemcheck.txt
F: arch/x86/include/asm/kmemcheck.h
@@ -5272,8 +5298,7 @@ S: Supported
F: drivers/s390/net/
S390 ZCRYPT DRIVER
-M: Felix Beck <felix.beck@de.ibm.com>
-M: Ralph Wuerthner <ralph.wuerthner@de.ibm.com>
+M: Holger Dengler <hd@linux.vnet.ibm.com>
M: linux390@de.ibm.com
L: linux-s390@vger.kernel.org
W: http://www.ibm.com/developerworks/linux/linux390/
@@ -5546,7 +5571,7 @@ M: Pat Gefre <pfg@sgi.com>
L: linux-ia64@vger.kernel.org
S: Supported
F: Documentation/ia64/serial.txt
-F: drivers/serial/ioc?_serial.c
+F: drivers/tty/serial/ioc?_serial.c
F: include/linux/ioc?.h
SGI VISUAL WORKSTATION 320 AND 540
@@ -5568,7 +5593,7 @@ L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
S: Maintained
F: Documentation/arm/Sharp-LH/ADC-LH7-Touchscreen
F: arch/arm/mach-lh7a40x/
-F: drivers/serial/serial_lh7a40x.c
+F: drivers/tty/serial/serial_lh7a40x.c
F: drivers/usb/gadget/lh7a40*
F: drivers/usb/host/ohci-lh7a40*
@@ -5647,7 +5672,7 @@ F: drivers/net/sky2.*
SLAB ALLOCATOR
M: Christoph Lameter <cl@linux-foundation.org>
-M: Pekka Enberg <penberg@cs.helsinki.fi>
+M: Pekka Enberg <penberg@kernel.org>
M: Matt Mackall <mpm@selenic.com>
L: linux-mm@kvack.org
S: Maintained
@@ -5788,14 +5813,14 @@ L: sparclinux@vger.kernel.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc-2.6.git
T: git git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc-next-2.6.git
S: Maintained
-F: drivers/serial/suncore.c
-F: drivers/serial/suncore.h
-F: drivers/serial/sunhv.c
-F: drivers/serial/sunsab.c
-F: drivers/serial/sunsab.h
-F: drivers/serial/sunsu.c
-F: drivers/serial/sunzilog.c
-F: drivers/serial/sunzilog.h
+F: drivers/tty/serial/suncore.c
+F: drivers/tty/serial/suncore.h
+F: drivers/tty/serial/sunhv.c
+F: drivers/tty/serial/sunsab.c
+F: drivers/tty/serial/sunsab.h
+F: drivers/tty/serial/sunsu.c
+F: drivers/tty/serial/sunzilog.c
+F: drivers/tty/serial/sunzilog.h
SPEAR PLATFORM SUPPORT
M: Viresh Kumar <viresh.kumar@st.com>
@@ -6125,8 +6150,8 @@ TTY LAYER
M: Greg Kroah-Hartman <gregkh@suse.de>
S: Maintained
T: git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty-2.6.git
-F: drivers/char/tty_*
-F: drivers/serial/serial_core.c
+F: drivers/tty/*
+F: drivers/tty/serial/serial_core.c
F: include/linux/serial_core.h
F: include/linux/serial.h
F: include/linux/tty.h
@@ -6871,7 +6896,7 @@ XILINX UARTLITE SERIAL DRIVER
M: Peter Korsgaard <jacmet@sunsite.dk>
L: linux-serial@vger.kernel.org
S: Maintained
-F: drivers/serial/uartlite.c
+F: drivers/tty/serial/uartlite.c
YAM DRIVER FOR AX.25
M: Jean-Paul Roubelat <jpr@f6fbb.org>
@@ -6917,7 +6942,7 @@ F: drivers/media/video/zoran/
ZS DECSTATION Z85C30 SERIAL DRIVER
M: "Maciej W. Rozycki" <macro@linux-mips.org>
S: Maintained
-F: drivers/serial/zs.*
+F: drivers/tty/serial/zs.*
GRE DEMULTIPLEXER DRIVER
M: Dmitry Kozlov <xeb@mail.ru>
diff --git a/Makefile b/Makefile
index 6a45769..1f47495 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
VERSION = 2
PATCHLEVEL = 6
-SUBLEVEL = 37
-EXTRAVERSION =
+SUBLEVEL = 38
+EXTRAVERSION = -rc2
NAME = Flesh-Eating Bats with Fangs
# *DOCUMENTATION*
diff --git a/arch/alpha/Kconfig b/arch/alpha/Kconfig
index 943fe69..47f63d4 100644
--- a/arch/alpha/Kconfig
+++ b/arch/alpha/Kconfig
@@ -8,6 +8,9 @@ config ALPHA
select HAVE_IRQ_WORK
select HAVE_PERF_EVENTS
select HAVE_DMA_ATTRS
+ select HAVE_GENERIC_HARDIRQS
+ select GENERIC_IRQ_PROBE
+ select AUTO_IRQ_AFFINITY if SMP
help
The Alpha is a 64-bit general-purpose processor designed and
marketed by the Digital Equipment Corporation of blessed memory,
@@ -68,19 +71,6 @@ config GENERIC_IOMAP
bool
default n
-config GENERIC_HARDIRQS
- bool
- default y
-
-config GENERIC_IRQ_PROBE
- bool
- default y
-
-config AUTO_IRQ_AFFINITY
- bool
- depends on SMP
- default y
-
source "init/Kconfig"
source "kernel/Kconfig.freezer"
diff --git a/arch/alpha/include/asm/io.h b/arch/alpha/include/asm/io.h
index eda9b90..56ff965 100644
--- a/arch/alpha/include/asm/io.h
+++ b/arch/alpha/include/asm/io.h
@@ -37,8 +37,9 @@
*/
extern inline void __set_hae(unsigned long new_hae)
{
- unsigned long flags;
- local_irq_save(flags);
+ unsigned long flags = swpipl(IPL_MAX);
+
+ barrier();
alpha_mv.hae_cache = new_hae;
*alpha_mv.hae_register = new_hae;
@@ -46,7 +47,8 @@ extern inline void __set_hae(unsigned long new_hae)
/* Re-read to make sure it was written. */
new_hae = *alpha_mv.hae_register;
- local_irq_restore(flags);
+ setipl(flags);
+ barrier();
}
extern inline void set_hae(unsigned long new_hae)
diff --git a/arch/alpha/kernel/Makefile b/arch/alpha/kernel/Makefile
index 1ee9b5b..9bb7b858 100644
--- a/arch/alpha/kernel/Makefile
+++ b/arch/alpha/kernel/Makefile
@@ -3,8 +3,8 @@
#
extra-y := head.o vmlinux.lds
-EXTRA_AFLAGS := $(KBUILD_CFLAGS)
-EXTRA_CFLAGS := -Werror -Wno-sign-compare
+asflags-y := $(KBUILD_CFLAGS)
+ccflags-y := -Werror -Wno-sign-compare
obj-y := entry.o traps.o process.o init_task.o osf_sys.o irq.o \
irq_alpha.o signal.o setup.o ptrace.o time.o \
diff --git a/arch/alpha/kernel/irq.c b/arch/alpha/kernel/irq.c
index fe91298..9ab234f 100644
--- a/arch/alpha/kernel/irq.c
+++ b/arch/alpha/kernel/irq.c
@@ -44,10 +44,11 @@ static char irq_user_affinity[NR_IRQS];
int irq_select_affinity(unsigned int irq)
{
+ struct irq_desc *desc = irq_to_desc[irq];
static int last_cpu;
int cpu = last_cpu + 1;
- if (!irq_desc[irq].chip->set_affinity || irq_user_affinity[irq])
+ if (!desc || !get_irq_desc_chip(desc)->set_affinity || irq_user_affinity[irq])
return 1;
while (!cpu_possible(cpu) ||
@@ -55,8 +56,8 @@ int irq_select_affinity(unsigned int irq)
cpu = (cpu < (NR_CPUS-1) ? cpu + 1 : 0);
last_cpu = cpu;
- cpumask_copy(irq_desc[irq].affinity, cpumask_of(cpu));
- irq_desc[irq].chip->set_affinity(irq, cpumask_of(cpu));
+ cpumask_copy(desc->affinity, cpumask_of(cpu));
+ get_irq_desc_chip(desc)->set_affinity(irq, cpumask_of(cpu));
return 0;
}
#endif /* CONFIG_SMP */
@@ -67,6 +68,7 @@ show_interrupts(struct seq_file *p, void *v)
int j;
int irq = *(loff_t *) v;
struct irqaction * action;
+ struct irq_desc *desc;
unsigned long flags;
#ifdef CONFIG_SMP
@@ -79,8 +81,13 @@ show_interrupts(struct seq_file *p, void *v)
#endif
if (irq < ACTUAL_NR_IRQS) {
- raw_spin_lock_irqsave(&irq_desc[irq].lock, flags);
- action = irq_desc[irq].action;
+ desc = irq_to_desc(irq);
+
+ if (!desc)
+ return 0;
+
+ raw_spin_lock_irqsave(&desc->lock, flags);
+ action = desc->action;
if (!action)
goto unlock;
seq_printf(p, "%3d: ", irq);
@@ -90,7 +97,7 @@ show_interrupts(struct seq_file *p, void *v)
for_each_online_cpu(j)
seq_printf(p, "%10u ", kstat_irqs_cpu(irq, j));
#endif
- seq_printf(p, " %14s", irq_desc[irq].chip->name);
+ seq_printf(p, " %14s", get_irq_desc_chip(desc)->name);
seq_printf(p, " %c%s",
(action->flags & IRQF_DISABLED)?'+':' ',
action->name);
@@ -103,7 +110,7 @@ show_interrupts(struct seq_file *p, void *v)
seq_putc(p, '\n');
unlock:
- raw_spin_unlock_irqrestore(&irq_desc[irq].lock, flags);
+ raw_spin_unlock_irqrestore(&desc->lock, flags);
} else if (irq == ACTUAL_NR_IRQS) {
#ifdef CONFIG_SMP
seq_puts(p, "IPI: ");
@@ -142,8 +149,10 @@ handle_irq(int irq)
* handled by some other CPU. (or is disabled)
*/
static unsigned int illegal_count=0;
+ struct irq_desc *desc = irq_to_desc(irq);
- if ((unsigned) irq > ACTUAL_NR_IRQS && illegal_count < MAX_ILLEGAL_IRQS ) {
+ if (!desc || ((unsigned) irq > ACTUAL_NR_IRQS &&
+ illegal_count < MAX_ILLEGAL_IRQS)) {
irq_err_count++;
illegal_count++;
printk(KERN_CRIT "device_interrupt: invalid interrupt %d\n",
@@ -151,14 +160,14 @@ handle_irq(int irq)
return;
}
- irq_enter();
/*
- * __do_IRQ() must be called with IPL_MAX. Note that we do not
+ * From here we must proceed with IPL_MAX. Note that we do not
* explicitly enable interrupts afterwards - some MILO PALcode
* (namely LX164 one) seems to have severe problems with RTI
* at IPL 0.
*/
local_irq_disable();
- __do_IRQ(irq);
+ irq_enter();
+ generic_handle_irq_desc(irq, desc);
irq_exit();
}
diff --git a/arch/alpha/kernel/irq_alpha.c b/arch/alpha/kernel/irq_alpha.c
index 4c8bb37..2d0679b 100644
--- a/arch/alpha/kernel/irq_alpha.c
+++ b/arch/alpha/kernel/irq_alpha.c
@@ -219,31 +219,23 @@ process_mcheck_info(unsigned long vector, unsigned long la_ptr,
* processed by PALcode, and comes in via entInt vector 1.
*/
-static void rtc_enable_disable(unsigned int irq) { }
-static unsigned int rtc_startup(unsigned int irq) { return 0; }
-
struct irqaction timer_irqaction = {
.handler = timer_interrupt,
.flags = IRQF_DISABLED,
.name = "timer",
};
-static struct irq_chip rtc_irq_type = {
- .name = "RTC",
- .startup = rtc_startup,
- .shutdown = rtc_enable_disable,
- .enable = rtc_enable_disable,
- .disable = rtc_enable_disable,
- .ack = rtc_enable_disable,
- .end = rtc_enable_disable,
-};
-
void __init
init_rtc_irq(void)
{
- irq_desc[RTC_IRQ].status = IRQ_DISABLED;
- irq_desc[RTC_IRQ].chip = &rtc_irq_type;
- setup_irq(RTC_IRQ, &timer_irqaction);
+ struct irq_desc *desc = irq_to_desc(RTC_IRQ);
+
+ if (desc) {
+ desc->status |= IRQ_DISABLED;
+ set_irq_chip_and_handler_name(RTC_IRQ, &no_irq_chip,
+ handle_simple_irq, "RTC");
+ setup_irq(RTC_IRQ, &timer_irqaction);
+ }
}
/* Dummy irqactions. */
diff --git a/arch/alpha/kernel/irq_i8259.c b/arch/alpha/kernel/irq_i8259.c
index 83a9ac2..956ea0e 100644
--- a/arch/alpha/kernel/irq_i8259.c
+++ b/arch/alpha/kernel/irq_i8259.c
@@ -69,28 +69,11 @@ i8259a_mask_and_ack_irq(unsigned int irq)
spin_unlock(&i8259_irq_lock);
}
-unsigned int
-i8259a_startup_irq(unsigned int irq)
-{
- i8259a_enable_irq(irq);
- return 0; /* never anything pending */
-}
-
-void
-i8259a_end_irq(unsigned int irq)
-{
- if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
- i8259a_enable_irq(irq);
-}
-
struct irq_chip i8259a_irq_type = {
.name = "XT-PIC",
- .startup = i8259a_startup_irq,
- .shutdown = i8259a_disable_irq,
- .enable = i8259a_enable_irq,
- .disable = i8259a_disable_irq,
- .ack = i8259a_mask_and_ack_irq,
- .end = i8259a_end_irq,
+ .unmask = i8259a_enable_irq,
+ .mask = i8259a_disable_irq,
+ .mask_ack = i8259a_mask_and_ack_irq,
};
void __init
@@ -107,8 +90,7 @@ init_i8259a_irqs(void)
outb(0xff, 0xA1); /* mask all of 8259A-2 */
for (i = 0; i < 16; i++) {
- irq_desc[i].status = IRQ_DISABLED;
- irq_desc[i].chip = &i8259a_irq_type;
+ set_irq_chip_and_handler(i, &i8259a_irq_type, handle_level_irq);
}
setup_irq(2, &cascade);
diff --git a/arch/alpha/kernel/irq_pyxis.c b/arch/alpha/kernel/irq_pyxis.c
index 989ce46..2863458 100644
--- a/arch/alpha/kernel/irq_pyxis.c
+++ b/arch/alpha/kernel/irq_pyxis.c
@@ -40,20 +40,6 @@ pyxis_disable_irq(unsigned int irq)
pyxis_update_irq_hw(cached_irq_mask &= ~(1UL << (irq - 16)));
}
-static unsigned int
-pyxis_startup_irq(unsigned int irq)
-{
- pyxis_enable_irq(irq);
- return 0;
-}
-
-static void
-pyxis_end_irq(unsigned int irq)
-{
- if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
- pyxis_enable_irq(irq);
-}
-
static void
pyxis_mask_and_ack_irq(unsigned int irq)
{
@@ -72,12 +58,9 @@ pyxis_mask_and_ack_irq(unsigned int irq)
static struct irq_chip pyxis_irq_type = {
.name = "PYXIS",
- .startup = pyxis_startup_irq,
- .shutdown = pyxis_disable_irq,
- .enable = pyxis_enable_irq,
- .disable = pyxis_disable_irq,
- .ack = pyxis_mask_and_ack_irq,
- .end = pyxis_end_irq,
+ .mask_ack = pyxis_mask_and_ack_irq,
+ .mask = pyxis_disable_irq,
+ .unmask = pyxis_enable_irq,
};
void
@@ -119,8 +102,8 @@ init_pyxis_irqs(unsigned long ignore_mask)
for (i = 16; i < 48; ++i) {
if ((ignore_mask >> i) & 1)
continue;
- irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL;
- irq_desc[i].chip = &pyxis_irq_type;
+ set_irq_chip_and_handler(i, &pyxis_irq_type, handle_level_irq);
+ irq_to_desc(i)->status |= IRQ_LEVEL;
}
setup_irq(16+7, &isa_cascade_irqaction);
diff --git a/arch/alpha/kernel/irq_srm.c b/arch/alpha/kernel/irq_srm.c
index d63e93e..0e57e82 100644
--- a/arch/alpha/kernel/irq_srm.c
+++ b/arch/alpha/kernel/irq_srm.c
@@ -33,29 +33,12 @@ srm_disable_irq(unsigned int irq)
spin_unlock(&srm_irq_lock);
}
-static unsigned int
-srm_startup_irq(unsigned int irq)
-{
- srm_enable_irq(irq);
- return 0;
-}
-
-static void
-srm_end_irq(unsigned int irq)
-{
- if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
- srm_enable_irq(irq);
-}
-
/* Handle interrupts from the SRM, assuming no additional weirdness. */
static struct irq_chip srm_irq_type = {
.name = "SRM",
- .startup = srm_startup_irq,
- .shutdown = srm_disable_irq,
- .enable = srm_enable_irq,
- .disable = srm_disable_irq,
- .ack = srm_disable_irq,
- .end = srm_end_irq,
+ .unmask = srm_enable_irq,
+ .mask = srm_disable_irq,
+ .mask_ack = srm_disable_irq,
};
void __init
@@ -68,8 +51,8 @@ init_srm_irqs(long max, unsigned long ignore_mask)
for (i = 16; i < max; ++i) {
if (i < 64 && ((ignore_mask >> i) & 1))
continue;
- irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL;
- irq_desc[i].chip = &srm_irq_type;
+ set_irq_chip_and_handler(i, &srm_irq_type, handle_level_irq);
+ irq_to_desc(i)->status |= IRQ_LEVEL;
}
}
diff --git a/arch/alpha/kernel/osf_sys.c b/arch/alpha/kernel/osf_sys.c
index 547e8b8..fe698b5 100644
--- a/arch/alpha/kernel/osf_sys.c
+++ b/arch/alpha/kernel/osf_sys.c
@@ -951,9 +951,6 @@ SYSCALL_DEFINE2(osf_utimes, const char __user *, filename,
return do_utimes(AT_FDCWD, filename, tvs ? tv : NULL, 0);
}
-#define MAX_SELECT_SECONDS \
- ((unsigned long) (MAX_SCHEDULE_TIMEOUT / HZ)-1)
-
SYSCALL_DEFINE5(osf_select, int, n, fd_set __user *, inp, fd_set __user *, outp,
fd_set __user *, exp, struct timeval32 __user *, tvp)
{
diff --git a/arch/alpha/kernel/sys_alcor.c b/arch/alpha/kernel/sys_alcor.c
index 20a30b8..7bef617 100644
--- a/arch/alpha/kernel/sys_alcor.c
+++ b/arch/alpha/kernel/sys_alcor.c
@@ -65,13 +65,6 @@ alcor_mask_and_ack_irq(unsigned int irq)
*(vuip)GRU_INT_CLEAR = 0; mb();
}
-static unsigned int
-alcor_startup_irq(unsigned int irq)
-{
- alcor_enable_irq(irq);
- return 0;
-}
-
static void
alcor_isa_mask_and_ack_irq(unsigned int irq)
{
@@ -82,21 +75,11 @@ alcor_isa_mask_and_ack_irq(unsigned int irq)
*(vuip)GRU_INT_CLEAR = 0; mb();
}
-static void
-alcor_end_irq(unsigned int irq)
-{
- if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
- alcor_enable_irq(irq);
-}
-
static struct irq_chip alcor_irq_type = {
.name = "ALCOR",
- .startup = alcor_startup_irq,
- .shutdown = alcor_disable_irq,
- .enable = alcor_enable_irq,
- .disable = alcor_disable_irq,
- .ack = alcor_mask_and_ack_irq,
- .end = alcor_end_irq,
+ .unmask = alcor_enable_irq,
+ .mask = alcor_disable_irq,
+ .mask_ack = alcor_mask_and_ack_irq,
};
static void
@@ -142,8 +125,8 @@ alcor_init_irq(void)
on while IRQ probing. */
if (i >= 16+20 && i <= 16+30)
continue;
- irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL;
- irq_desc[i].chip = &alcor_irq_type;
+ set_irq_chip_and_handler(i, &alcor_irq_type, handle_level_irq);
+ irq_to_desc(i)->status |= IRQ_LEVEL;
}
i8259a_irq_type.ack = alcor_isa_mask_and_ack_irq;
diff --git a/arch/alpha/kernel/sys_cabriolet.c b/arch/alpha/kernel/sys_cabriolet.c
index 14c8898..b0c9164 100644
--- a/arch/alpha/kernel/sys_cabriolet.c
+++ b/arch/alpha/kernel/sys_cabriolet.c
@@ -57,28 +57,11 @@ cabriolet_disable_irq(unsigned int irq)
cabriolet_update_irq_hw(irq, cached_irq_mask |= 1UL << irq);
}
-static unsigned int
-cabriolet_startup_irq(unsigned int irq)
-{
- cabriolet_enable_irq(irq);
- return 0; /* never anything pending */
-}
-
-static void
-cabriolet_end_irq(unsigned int irq)
-{
- if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
- cabriolet_enable_irq(irq);
-}
-
static struct irq_chip cabriolet_irq_type = {
.name = "CABRIOLET",
- .startup = cabriolet_startup_irq,
- .shutdown = cabriolet_disable_irq,
- .enable = cabriolet_enable_irq,
- .disable = cabriolet_disable_irq,
- .ack = cabriolet_disable_irq,
- .end = cabriolet_end_irq,
+ .unmask = cabriolet_enable_irq,
+ .mask = cabriolet_disable_irq,
+ .mask_ack = cabriolet_disable_irq,
};
static void
@@ -122,8 +105,9 @@ common_init_irq(void (*srm_dev_int)(unsigned long v))
outb(0xff, 0x806);
for (i = 16; i < 35; ++i) {
- irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL;
- irq_desc[i].chip = &cabriolet_irq_type;
+ set_irq_chip_and_handler(i, &cabriolet_irq_type,
+ handle_level_irq);
+ irq_to_desc(i)->status |= IRQ_LEVEL;
}
}
diff --git a/arch/alpha/kernel/sys_dp264.c b/arch/alpha/kernel/sys_dp264.c
index 4026502..edad5f7 100644
--- a/arch/alpha/kernel/sys_dp264.c
+++ b/arch/alpha/kernel/sys_dp264.c
@@ -115,20 +115,6 @@ dp264_disable_irq(unsigned int irq)
spin_unlock(&dp264_irq_lock);
}
-static unsigned int
-dp264_startup_irq(unsigned int irq)
-{
- dp264_enable_irq(irq);
- return 0; /* never anything pending */
-}
-
-static void
-dp264_end_irq(unsigned int irq)
-{
- if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
- dp264_enable_irq(irq);
-}
-
static void
clipper_enable_irq(unsigned int irq)
{
@@ -147,20 +133,6 @@ clipper_disable_irq(unsigned int irq)
spin_unlock(&dp264_irq_lock);
}
-static unsigned int
-clipper_startup_irq(unsigned int irq)
-{
- clipper_enable_irq(irq);
- return 0; /* never anything pending */
-}
-
-static void
-clipper_end_irq(unsigned int irq)
-{
- if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
- clipper_enable_irq(irq);
-}
-
static void
cpu_set_irq_affinity(unsigned int irq, cpumask_t affinity)
{
@@ -200,23 +172,17 @@ clipper_set_affinity(unsigned int irq, const struct cpumask *affinity)
static struct irq_chip dp264_irq_type = {
.name = "DP264",
- .startup = dp264_startup_irq,
- .shutdown = dp264_disable_irq,
- .enable = dp264_enable_irq,
- .disable = dp264_disable_irq,
- .ack = dp264_disable_irq,
- .end = dp264_end_irq,
+ .unmask = dp264_enable_irq,
+ .mask = dp264_disable_irq,
+ .mask_ack = dp264_disable_irq,
.set_affinity = dp264_set_affinity,
};
static struct irq_chip clipper_irq_type = {
.name = "CLIPPER",
- .startup = clipper_startup_irq,
- .shutdown = clipper_disable_irq,
- .enable = clipper_enable_irq,
- .disable = clipper_disable_irq,
- .ack = clipper_disable_irq,
- .end = clipper_end_irq,
+ .unmask = clipper_enable_irq,
+ .mask = clipper_disable_irq,
+ .mask_ack = clipper_disable_irq,
.set_affinity = clipper_set_affinity,
};
@@ -302,8 +268,8 @@ init_tsunami_irqs(struct irq_chip * ops, int imin, int imax)
{
long i;
for (i = imin; i <= imax; ++i) {
- irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL;
- irq_desc[i].chip = ops;
+ irq_to_desc(i)->status |= IRQ_LEVEL;
+ set_irq_chip_and_handler(i, ops, handle_level_irq);
}
}
diff --git a/arch/alpha/kernel/sys_eb64p.c b/arch/alpha/kernel/sys_eb64p.c
index df2090c..ae5f29d 100644
--- a/arch/alpha/kernel/sys_eb64p.c
+++ b/arch/alpha/kernel/sys_eb64p.c
@@ -55,28 +55,11 @@ eb64p_disable_irq(unsigned int irq)
eb64p_update_irq_hw(irq, cached_irq_mask |= 1 << irq);
}
-static unsigned int
-eb64p_startup_irq(unsigned int irq)
-{
- eb64p_enable_irq(irq);
- return 0; /* never anything pending */
-}
-
-static void
-eb64p_end_irq(unsigned int irq)
-{
- if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
- eb64p_enable_irq(irq);
-}
-
static struct irq_chip eb64p_irq_type = {
.name = "EB64P",
- .startup = eb64p_startup_irq,
- .shutdown = eb64p_disable_irq,
- .enable = eb64p_enable_irq,
- .disable = eb64p_disable_irq,
- .ack = eb64p_disable_irq,
- .end = eb64p_end_irq,
+ .unmask = eb64p_enable_irq,
+ .mask = eb64p_disable_irq,
+ .mask_ack = eb64p_disable_irq,
};
static void
@@ -135,8 +118,8 @@ eb64p_init_irq(void)
init_i8259a_irqs();
for (i = 16; i < 32; ++i) {
- irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL;
- irq_desc[i].chip = &eb64p_irq_type;
+ irq_to_desc(i)->status |= IRQ_LEVEL;
+ set_irq_chip_and_handler(i, &eb64p_irq_type, handle_level_irq);
}
common_init_isa_dma();
diff --git a/arch/alpha/kernel/sys_eiger.c b/arch/alpha/kernel/sys_eiger.c
index 3ca1dbc..1121bc5 100644
--- a/arch/alpha/kernel/sys_eiger.c
+++ b/arch/alpha/kernel/sys_eiger.c
@@ -66,28 +66,11 @@ eiger_disable_irq(unsigned int irq)
eiger_update_irq_hw(irq, mask);
}
-static unsigned int
-eiger_startup_irq(unsigned int irq)
-{
- eiger_enable_irq(irq);
- return 0; /* never anything pending */
-}
-
-static void
-eiger_end_irq(unsigned int irq)
-{
- if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
- eiger_enable_irq(irq);
-}
-
static struct irq_chip eiger_irq_type = {
.name = "EIGER",
- .startup = eiger_startup_irq,
- .shutdown = eiger_disable_irq,
- .enable = eiger_enable_irq,
- .disable = eiger_disable_irq,
- .ack = eiger_disable_irq,
- .end = eiger_end_irq,
+ .unmask = eiger_enable_irq,
+ .mask = eiger_disable_irq,
+ .mask_ack = eiger_disable_irq,
};
static void
@@ -153,8 +136,8 @@ eiger_init_irq(void)
init_i8259a_irqs();
for (i = 16; i < 128; ++i) {
- irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL;
- irq_desc[i].chip = &eiger_irq_type;
+ irq_to_desc(i)->status |= IRQ_LEVEL;
+ set_irq_chip_and_handler(i, &eiger_irq_type, handle_level_irq);
}
}
diff --git a/arch/alpha/kernel/sys_jensen.c b/arch/alpha/kernel/sys_jensen.c
index 7a7ae36..34f55e0 100644
--- a/arch/alpha/kernel/sys_jensen.c
+++ b/arch/alpha/kernel/sys_jensen.c
@@ -62,30 +62,6 @@
* world.
*/
-static unsigned int
-jensen_local_startup(unsigned int irq)
-{
- /* the parport is really hw IRQ 1, silly Jensen. */
- if (irq == 7)
- i8259a_startup_irq(1);
- else
- /*
- * For all true local interrupts, set the flag that prevents
- * the IPL from being dropped during handler processing.
- */
- if (irq_desc[irq].action)
- irq_desc[irq].action->flags |= IRQF_DISABLED;
- return 0;
-}
-
-static void
-jensen_local_shutdown(unsigned int irq)
-{
- /* the parport is really hw IRQ 1, silly Jensen. */
- if (irq == 7)
- i8259a_disable_irq(1);
-}
-
static void
jensen_local_enable(unsigned int irq)
{
@@ -103,29 +79,18 @@ jensen_local_disable(unsigned int irq)
}
static void
-jensen_local_ack(unsigned int irq)
+jensen_local_mask_ack(unsigned int irq)
{
/* the parport is really hw IRQ 1, silly Jensen. */
if (irq == 7)
i8259a_mask_and_ack_irq(1);
}
-static void
-jensen_local_end(unsigned int irq)
-{
- /* the parport is really hw IRQ 1, silly Jensen. */
- if (irq == 7)
- i8259a_end_irq(1);
-}
-
static struct irq_chip jensen_local_irq_type = {
.name = "LOCAL",
- .startup = jensen_local_startup,
- .shutdown = jensen_local_shutdown,
- .enable = jensen_local_enable,
- .disable = jensen_local_disable,
- .ack = jensen_local_ack,
- .end = jensen_local_end,
+ .unmask = jensen_local_enable,
+ .mask = jensen_local_disable,
+ .mask_ack = jensen_local_mask_ack,
};
static void
@@ -158,7 +123,7 @@ jensen_device_interrupt(unsigned long vector)
}
/* If there is no handler yet... */
- if (irq_desc[irq].action == NULL) {
+ if (!irq_has_action(irq)) {
/* If it is a local interrupt that cannot be masked... */
if (vector >= 0x900)
{
@@ -206,11 +171,11 @@ jensen_init_irq(void)
{
init_i8259a_irqs();
- irq_desc[1].chip = &jensen_local_irq_type;
- irq_desc[4].chip = &jensen_local_irq_type;
- irq_desc[3].chip = &jensen_local_irq_type;
- irq_desc[7].chip = &jensen_local_irq_type;
- irq_desc[9].chip = &jensen_local_irq_type;
+ set_irq_chip_and_handler(1, &jensen_local_irq_type, handle_level_irq);
+ set_irq_chip_and_handler(4, &jensen_local_irq_type, handle_level_irq);
+ set_irq_chip_and_handler(3, &jensen_local_irq_type, handle_level_irq);
+ set_irq_chip_and_handler(7, &jensen_local_irq_type, handle_level_irq);
+ set_irq_chip_and_handler(9, &jensen_local_irq_type, handle_level_irq);
common_init_isa_dma();
}
diff --git a/arch/alpha/kernel/sys_marvel.c b/arch/alpha/kernel/sys_marvel.c
index 0bb3b5c..2bfc9f1 100644
--- a/arch/alpha/kernel/sys_marvel.c
+++ b/arch/alpha/kernel/sys_marvel.c
@@ -143,20 +143,6 @@ io7_disable_irq(unsigned int irq)
spin_unlock(&io7->irq_lock);
}
-static unsigned int
-io7_startup_irq(unsigned int irq)
-{
- io7_enable_irq(irq);
- return 0; /* never anything pending */
-}
-
-static void
-io7_end_irq(unsigned int irq)
-{
- if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
- io7_enable_irq(irq);
-}
-
static void
marvel_irq_noop(unsigned int irq)
{
@@ -171,32 +157,22 @@ marvel_irq_noop_return(unsigned int irq)
static struct irq_chip marvel_legacy_irq_type = {
.name = "LEGACY",
- .startup = marvel_irq_noop_return,
- .shutdown = marvel_irq_noop,
- .enable = marvel_irq_noop,
- .disable = marvel_irq_noop,
- .ack = marvel_irq_noop,
- .end = marvel_irq_noop,
+ .mask = marvel_irq_noop,
+ .unmask = marvel_irq_noop,
};
static struct irq_chip io7_lsi_irq_type = {
.name = "LSI",
- .startup = io7_startup_irq,
- .shutdown = io7_disable_irq,
- .enable = io7_enable_irq,
- .disable = io7_disable_irq,
- .ack = io7_disable_irq,
- .end = io7_end_irq,
+ .unmask = io7_enable_irq,
+ .mask = io7_disable_irq,
+ .mask_ack = io7_disable_irq,
};
static struct irq_chip io7_msi_irq_type = {
.name = "MSI",
- .startup = io7_startup_irq,
- .shutdown = io7_disable_irq,
- .enable = io7_enable_irq,
- .disable = io7_disable_irq,
+ .unmask = io7_enable_irq,
+ .mask = io7_disable_irq,
.ack = marvel_irq_noop,
- .end = io7_end_irq,
};
static void
@@ -304,8 +280,8 @@ init_io7_irqs(struct io7 *io7,
/* Set up the lsi irqs. */
for (i = 0; i < 128; ++i) {
- irq_desc[base + i].status = IRQ_DISABLED | IRQ_LEVEL;
- irq_desc[base + i].chip = lsi_ops;
+ irq_to_desc(base + i)->status |= IRQ_LEVEL;
+ set_irq_chip_and_handler(base + i, lsi_ops, handle_level_irq);
}
/* Disable the implemented irqs in hardware. */
@@ -318,8 +294,8 @@ init_io7_irqs(struct io7 *io7,
/* Set up the msi irqs. */
for (i = 128; i < (128 + 512); ++i) {
- irq_desc[base + i].status = IRQ_DISABLED | IRQ_LEVEL;
- irq_desc[base + i].chip = msi_ops;
+ irq_to_desc(base + i)->status |= IRQ_LEVEL;
+ set_irq_chip_and_handler(base + i, msi_ops, handle_level_irq);
}
for (i = 0; i < 16; ++i)
@@ -336,8 +312,8 @@ marvel_init_irq(void)
/* Reserve the legacy irqs. */
for (i = 0; i < 16; ++i) {
- irq_desc[i].status = IRQ_DISABLED;
- irq_desc[i].chip = &marvel_legacy_irq_type;
+ set_irq_chip_and_handler(i, &marvel_legacy_irq_type,
+ handle_level_irq);
}
/* Init the io7 irqs. */
diff --git a/arch/alpha/kernel/sys_mikasa.c b/arch/alpha/kernel/sys_mikasa.c
index ee88651..bcc1639 100644
--- a/arch/alpha/kernel/sys_mikasa.c
+++ b/arch/alpha/kernel/sys_mikasa.c
@@ -54,28 +54,11 @@ mikasa_disable_irq(unsigned int irq)
mikasa_update_irq_hw(cached_irq_mask &= ~(1 << (irq - 16)));
}
-static unsigned int
-mikasa_startup_irq(unsigned int irq)
-{
- mikasa_enable_irq(irq);
- return 0;
-}
-
-static void
-mikasa_end_irq(unsigned int irq)
-{
- if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
- mikasa_enable_irq(irq);
-}
-
static struct irq_chip mikasa_irq_type = {
.name = "MIKASA",
- .startup = mikasa_startup_irq,
- .shutdown = mikasa_disable_irq,
- .enable = mikasa_enable_irq,
- .disable = mikasa_disable_irq,
- .ack = mikasa_disable_irq,
- .end = mikasa_end_irq,
+ .unmask = mikasa_enable_irq,
+ .mask = mikasa_disable_irq,
+ .mask_ack = mikasa_disable_irq,
};
static void
@@ -115,8 +98,8 @@ mikasa_init_irq(void)
mikasa_update_irq_hw(0);
for (i = 16; i < 32; ++i) {
- irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL;
- irq_desc[i].chip = &mikasa_irq_type;
+ irq_to_desc(i)->status |= IRQ_LEVEL;
+ set_irq_chip_and_handler(i, &mikasa_irq_type, handle_level_irq);
}
init_i8259a_irqs();
diff --git a/arch/alpha/kernel/sys_noritake.c b/arch/alpha/kernel/sys_noritake.c
index 86503fe..e88f4ae 100644
--- a/arch/alpha/kernel/sys_noritake.c
+++ b/arch/alpha/kernel/sys_noritake.c
@@ -59,28 +59,11 @@ noritake_disable_irq(unsigned int irq)
noritake_update_irq_hw(irq, cached_irq_mask &= ~(1 << (irq - 16)));
}
-static unsigned int
-noritake_startup_irq(unsigned int irq)
-{
- noritake_enable_irq(irq);
- return 0;
-}
-
-static void
-noritake_end_irq(unsigned int irq)
-{
- if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
- noritake_enable_irq(irq);
-}
-
static struct irq_chip noritake_irq_type = {
.name = "NORITAKE",
- .startup = noritake_startup_irq,
- .shutdown = noritake_disable_irq,
- .enable = noritake_enable_irq,
- .disable = noritake_disable_irq,
- .ack = noritake_disable_irq,
- .end = noritake_end_irq,
+ .unmask = noritake_enable_irq,
+ .mask = noritake_disable_irq,
+ .mask_ack = noritake_disable_irq,
};
static void
@@ -144,8 +127,8 @@ noritake_init_irq(void)
outw(0, 0x54c);
for (i = 16; i < 48; ++i) {
- irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL;
- irq_desc[i].chip = &noritake_irq_type;
+ irq_to_desc(i)->status |= IRQ_LEVEL;
+ set_irq_chip_and_handler(i, &noritake_irq_type, handle_level_irq);
}
init_i8259a_irqs();
diff --git a/arch/alpha/kernel/sys_rawhide.c b/arch/alpha/kernel/sys_rawhide.c
index 26c322b..6a51364 100644
--- a/arch/alpha/kernel/sys_rawhide.c
+++ b/arch/alpha/kernel/sys_rawhide.c
@@ -121,28 +121,11 @@ rawhide_mask_and_ack_irq(unsigned int irq)
spin_unlock(&rawhide_irq_lock);
}
-static unsigned int
-rawhide_startup_irq(unsigned int irq)
-{
- rawhide_enable_irq(irq);
- return 0;
-}
-
-static void
-rawhide_end_irq(unsigned int irq)
-{
- if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
- rawhide_enable_irq(irq);
-}
-
static struct irq_chip rawhide_irq_type = {
.name = "RAWHIDE",
- .startup = rawhide_startup_irq,
- .shutdown = rawhide_disable_irq,
- .enable = rawhide_enable_irq,
- .disable = rawhide_disable_irq,
- .ack = rawhide_mask_and_ack_irq,
- .end = rawhide_end_irq,
+ .unmask = rawhide_enable_irq,
+ .mask = rawhide_disable_irq,
+ .mask_ack = rawhide_mask_and_ack_irq,
};
static void
@@ -194,8 +177,8 @@ rawhide_init_irq(void)
}
for (i = 16; i < 128; ++i) {
- irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL;
- irq_desc[i].chip = &rawhide_irq_type;
+ irq_to_desc(i)->status |= IRQ_LEVEL;
+ set_irq_chip_and_handler(i, &rawhide_irq_type, handle_level_irq);
}
init_i8259a_irqs();
diff --git a/arch/alpha/kernel/sys_rx164.c b/arch/alpha/kernel/sys_rx164.c
index be16112..89e7e37e 100644
--- a/arch/alpha/kernel/sys_rx164.c
+++ b/arch/alpha/kernel/sys_rx164.c
@@ -58,28 +58,11 @@ rx164_disable_irq(unsigned int irq)
rx164_update_irq_hw(cached_irq_mask &= ~(1UL << (irq - 16)));
}
-static unsigned int
-rx164_startup_irq(unsigned int irq)
-{
- rx164_enable_irq(irq);
- return 0;
-}
-
-static void
-rx164_end_irq(unsigned int irq)
-{
- if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
- rx164_enable_irq(irq);
-}
-
static struct irq_chip rx164_irq_type = {
.name = "RX164",
- .startup = rx164_startup_irq,
- .shutdown = rx164_disable_irq,
- .enable = rx164_enable_irq,
- .disable = rx164_disable_irq,
- .ack = rx164_disable_irq,
- .end = rx164_end_irq,
+ .unmask = rx164_enable_irq,
+ .mask = rx164_disable_irq,
+ .mask_ack = rx164_disable_irq,
};
static void
@@ -116,8 +99,8 @@ rx164_init_irq(void)
rx164_update_irq_hw(0);
for (i = 16; i < 40; ++i) {
- irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL;
- irq_desc[i].chip = &rx164_irq_type;
+ irq_to_desc(i)->status |= IRQ_LEVEL;
+ set_irq_chip_and_handler(i, &rx164_irq_type, handle_level_irq);
}
init_i8259a_irqs();
diff --git a/arch/alpha/kernel/sys_sable.c b/arch/alpha/kernel/sys_sable.c
index b2abe27..5c4423d 100644
--- a/arch/alpha/kernel/sys_sable.c
+++ b/arch/alpha/kernel/sys_sable.c
@@ -474,20 +474,6 @@ sable_lynx_disable_irq(unsigned int irq)
#endif
}
-static unsigned int
-sable_lynx_startup_irq(unsigned int irq)
-{
- sable_lynx_enable_irq(irq);
- return 0;
-}
-
-static void
-sable_lynx_end_irq(unsigned int irq)
-{
- if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
- sable_lynx_enable_irq(irq);
-}
-
static void
sable_lynx_mask_and_ack_irq(unsigned int irq)
{
@@ -503,12 +489,9 @@ sable_lynx_mask_and_ack_irq(unsigned int irq)
static struct irq_chip sable_lynx_irq_type = {
.name = "SABLE/LYNX",
- .startup = sable_lynx_startup_irq,
- .shutdown = sable_lynx_disable_irq,
- .enable = sable_lynx_enable_irq,
- .disable = sable_lynx_disable_irq,
- .ack = sable_lynx_mask_and_ack_irq,
- .end = sable_lynx_end_irq,
+ .unmask = sable_lynx_enable_irq,
+ .mask = sable_lynx_disable_irq,
+ .mask_ack = sable_lynx_mask_and_ack_irq,
};
static void
@@ -535,8 +518,9 @@ sable_lynx_init_irq(int nr_of_irqs)
long i;
for (i = 0; i < nr_of_irqs; ++i) {
- irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL;
- irq_desc[i].chip = &sable_lynx_irq_type;
+ irq_to_desc(i)->status |= IRQ_LEVEL;
+ set_irq_chip_and_handler(i, &sable_lynx_irq_type,
+ handle_level_irq);
}
common_init_isa_dma();
diff --git a/arch/alpha/kernel/sys_takara.c b/arch/alpha/kernel/sys_takara.c
index 4da596b..f8a1e8a 100644
--- a/arch/alpha/kernel/sys_takara.c
+++ b/arch/alpha/kernel/sys_takara.c
@@ -60,28 +60,11 @@ takara_disable_irq(unsigned int irq)
takara_update_irq_hw(irq, mask);
}
-static unsigned int
-takara_startup_irq(unsigned int irq)
-{
- takara_enable_irq(irq);
- return 0; /* never anything pending */
-}
-
-static void
-takara_end_irq(unsigned int irq)
-{
- if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
- takara_enable_irq(irq);
-}
-
static struct irq_chip takara_irq_type = {
.name = "TAKARA",
- .startup = takara_startup_irq,
- .shutdown = takara_disable_irq,
- .enable = takara_enable_irq,
- .disable = takara_disable_irq,
- .ack = takara_disable_irq,
- .end = takara_end_irq,
+ .unmask = takara_enable_irq,
+ .mask = takara_disable_irq,
+ .mask_ack = takara_disable_irq,
};
static void
@@ -153,8 +136,8 @@ takara_init_irq(void)
takara_update_irq_hw(i, -1);
for (i = 16; i < 128; ++i) {
- irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL;
- irq_desc[i].chip = &takara_irq_type;
+ irq_to_desc(i)->status |= IRQ_LEVEL;
+ set_irq_chip_and_handler(i, &takara_irq_type, handle_level_irq);
}
common_init_isa_dma();
diff --git a/arch/alpha/kernel/sys_titan.c b/arch/alpha/kernel/sys_titan.c
index 9008d0f..e02494b 100644
--- a/arch/alpha/kernel/sys_titan.c
+++ b/arch/alpha/kernel/sys_titan.c
@@ -129,20 +129,6 @@ titan_disable_irq(unsigned int irq)
spin_unlock(&titan_irq_lock);
}
-static unsigned int
-titan_startup_irq(unsigned int irq)
-{
- titan_enable_irq(irq);
- return 0; /* never anything pending */
-}
-
-static void
-titan_end_irq(unsigned int irq)
-{
- if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
- titan_enable_irq(irq);
-}
-
static void
titan_cpu_set_irq_affinity(unsigned int irq, cpumask_t affinity)
{
@@ -189,20 +175,17 @@ init_titan_irqs(struct irq_chip * ops, int imin, int imax)
{
long i;
for (i = imin; i <= imax; ++i) {
- irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL;
- irq_desc[i].chip = ops;
+ irq_to_desc(i)->status |= IRQ_LEVEL;
+ set_irq_chip_and_handler(i, ops, handle_level_irq);
}
}
static struct irq_chip titan_irq_type = {
- .name = "TITAN",
- .startup = titan_startup_irq,
- .shutdown = titan_disable_irq,
- .enable = titan_enable_irq,
- .disable = titan_disable_irq,
- .ack = titan_disable_irq,
- .end = titan_end_irq,
- .set_affinity = titan_set_irq_affinity,
+ .name = "TITAN",
+ .unmask = titan_enable_irq,
+ .mask = titan_disable_irq,
+ .mask_ack = titan_disable_irq,
+ .set_affinity = titan_set_irq_affinity,
};
static irqreturn_t
diff --git a/arch/alpha/kernel/sys_wildfire.c b/arch/alpha/kernel/sys_wildfire.c
index 62fd972..eec5259 100644
--- a/arch/alpha/kernel/sys_wildfire.c
+++ b/arch/alpha/kernel/sys_wildfire.c
@@ -139,32 +139,11 @@ wildfire_mask_and_ack_irq(unsigned int irq)
spin_unlock(&wildfire_irq_lock);
}
-static unsigned int
-wildfire_startup_irq(unsigned int irq)
-{
- wildfire_enable_irq(irq);
- return 0; /* never anything pending */
-}
-
-static void
-wildfire_end_irq(unsigned int irq)
-{
-#if 0
- if (!irq_desc[irq].action)
- printk("got irq %d\n", irq);
-#endif
- if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
- wildfire_enable_irq(irq);
-}
-
static struct irq_chip wildfire_irq_type = {
.name = "WILDFIRE",
- .startup = wildfire_startup_irq,
- .shutdown = wildfire_disable_irq,
- .enable = wildfire_enable_irq,
- .disable = wildfire_disable_irq,
- .ack = wildfire_mask_and_ack_irq,
- .end = wildfire_end_irq,
+ .unmask = wildfire_enable_irq,
+ .mask = wildfire_disable_irq,
+ .mask_ack = wildfire_mask_and_ack_irq,
};
static void __init
@@ -198,15 +177,18 @@ wildfire_init_irq_per_pca(int qbbno, int pcano)
for (i = 0; i < 16; ++i) {
if (i == 2)
continue;
- irq_desc[i+irq_bias].status = IRQ_DISABLED | IRQ_LEVEL;
- irq_desc[i+irq_bias].chip = &wildfire_irq_type;
+ irq_to_desc(i+irq_bias)->status |= IRQ_LEVEL;
+ set_irq_chip_and_handler(i+irq_bias, &wildfire_irq_type,
+ handle_level_irq);
}
- irq_desc[36+irq_bias].status = IRQ_DISABLED | IRQ_LEVEL;
- irq_desc[36+irq_bias].chip = &wildfire_irq_type;
+ irq_to_desc(36+irq_bias)->status |= IRQ_LEVEL;
+ set_irq_chip_and_handler(36+irq_bias, &wildfire_irq_type,
+ handle_level_irq);
for (i = 40; i < 64; ++i) {
- irq_desc[i+irq_bias].status = IRQ_DISABLED | IRQ_LEVEL;
- irq_desc[i+irq_bias].chip = &wildfire_irq_type;
+ irq_to_desc(i+irq_bias)->status |= IRQ_LEVEL;
+ set_irq_chip_and_handler(i+irq_bias, &wildfire_irq_type,
+ handle_level_irq);
}
setup_irq(32+irq_bias, &isa_enable);
diff --git a/arch/alpha/lib/Makefile b/arch/alpha/lib/Makefile
index 9b72c59..c0a83ab 100644
--- a/arch/alpha/lib/Makefile
+++ b/arch/alpha/lib/Makefile
@@ -2,8 +2,8 @@
# Makefile for alpha-specific library files..
#
-EXTRA_AFLAGS := $(KBUILD_CFLAGS)
-EXTRA_CFLAGS := -Werror
+asflags-y := $(KBUILD_CFLAGS)
+ccflags-y := -Werror
# Many of these routines have implementations tuned for ev6.
# Choose them iff we're targeting ev6 specifically.
diff --git a/arch/alpha/math-emu/Makefile b/arch/alpha/math-emu/Makefile
index 359ef08..7f46719 100644
--- a/arch/alpha/math-emu/Makefile
+++ b/arch/alpha/math-emu/Makefile
@@ -2,7 +2,7 @@
# Makefile for the FPU instruction emulation.
#
-EXTRA_CFLAGS := -w
+ccflags-y := -w
obj-$(CONFIG_MATHEMU) += math-emu.o
diff --git a/arch/alpha/mm/Makefile b/arch/alpha/mm/Makefile
index 09399c5..c993d3f 100644
--- a/arch/alpha/mm/Makefile
+++ b/arch/alpha/mm/Makefile
@@ -2,7 +2,7 @@
# Makefile for the linux alpha-specific parts of the memory manager.
#
-EXTRA_CFLAGS := -Werror
+ccflags-y := -Werror
obj-y := init.o fault.o extable.o
diff --git a/arch/alpha/oprofile/Makefile b/arch/alpha/oprofile/Makefile
index 4aa5624..3473de7 100644
--- a/arch/alpha/oprofile/Makefile
+++ b/arch/alpha/oprofile/Makefile
@@ -1,4 +1,4 @@
-EXTRA_CFLAGS := -Werror -Wno-sign-compare
+ccflags-y := -Werror -Wno-sign-compare
obj-$(CONFIG_OPROFILE) += oprofile.o
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index e2f8011..5cff165 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -26,6 +26,8 @@ config ARM
select HAVE_REGS_AND_STACK_ACCESS_API
select HAVE_HW_BREAKPOINT if (PERF_EVENTS && (CPU_V6 || CPU_V7))
select HAVE_C_RECORDMCOUNT
+ select HAVE_GENERIC_HARDIRQS
+ select HAVE_SPARSE_IRQ
help
The ARM series is a line of low-power-consumption RISC chip designs
licensed by ARM Ltd and targeted at embedded applications and
@@ -97,10 +99,6 @@ config MCA
<file:Documentation/mca.txt> (and especially the web page given
there) before attempting to build an MCA bus kernel.
-config GENERIC_HARDIRQS
- bool
- default y
-
config STACKTRACE_SUPPORT
bool
default y
@@ -180,9 +178,6 @@ config FIQ
config ARCH_MTD_XIP
bool
-config GENERIC_HARDIRQS_NO__DO_IRQ
- def_bool y
-
config ARM_L1_CACHE_SHIFT_6
bool
help
@@ -368,7 +363,7 @@ config ARCH_MXS
bool "Freescale MXS-based"
select GENERIC_CLOCKEVENTS
select ARCH_REQUIRE_GPIOLIB
- select COMMON_CLKDEV
+ select CLKDEV_LOOKUP
help
Support for Freescale MXS-based family of processors
@@ -771,6 +766,7 @@ config ARCH_S5PV310
select ARCH_SPARSEMEM_ENABLE
select GENERIC_GPIO
select HAVE_CLK
+ select ARCH_HAS_CPUFREQ
select GENERIC_CLOCKEVENTS
select HAVE_S3C_RTC if RTC_CLASS
select HAVE_S3C2410_I2C if I2C
@@ -1281,7 +1277,7 @@ config SMP
config SMP_ON_UP
bool "Allow booting SMP kernel on uniprocessor systems (EXPERIMENTAL)"
depends on EXPERIMENTAL
- depends on SMP && !XIP
+ depends on SMP && !XIP_KERNEL
default y
help
SMP kernels contain instructions which fail on non-SMP processors.
@@ -1452,15 +1448,6 @@ config HW_PERF_EVENTS
Enable hardware performance counter support for perf events. If
disabled, perf events will use software events only.
-config SPARSE_IRQ
- def_bool n
- help
- This enables support for sparse irqs. This is useful in general
- as most CPUs have a fairly sparse array of IRQ vectors, which
- the irq_desc then maps directly on to. Systems with a high
- number of off-chip IRQs will want to treat this as
- experimental until they have been independently verified.
-
source "mm/Kconfig"
config FORCE_MAX_ZONEORDER
diff --git a/arch/arm/common/gic.c b/arch/arm/common/gic.c
index 0b89ef0..2243772 100644
--- a/arch/arm/common/gic.c
+++ b/arch/arm/common/gic.c
@@ -50,57 +50,56 @@ struct gic_chip_data {
static struct gic_chip_data gic_data[MAX_GIC_NR] __read_mostly;
-static inline void __iomem *gic_dist_base(unsigned int irq)
+static inline void __iomem *gic_dist_base(struct irq_data *d)
{
- struct gic_chip_data *gic_data = get_irq_chip_data(irq);
+ struct gic_chip_data *gic_data = irq_data_get_irq_chip_data(d);
return gic_data->dist_base;
}
-static inline void __iomem *gic_cpu_base(unsigned int irq)
+static inline void __iomem *gic_cpu_base(struct irq_data *d)
{
- struct gic_chip_data *gic_data = get_irq_chip_data(irq);
+ struct gic_chip_data *gic_data = irq_data_get_irq_chip_data(d);
return gic_data->cpu_base;
}
-static inline unsigned int gic_irq(unsigned int irq)
+static inline unsigned int gic_irq(struct irq_data *d)
{
- struct gic_chip_data *gic_data = get_irq_chip_data(irq);
- return irq - gic_data->irq_offset;
+ struct gic_chip_data *gic_data = irq_data_get_irq_chip_data(d);
+ return d->irq - gic_data->irq_offset;
}
/*
* Routines to acknowledge, disable and enable interrupts
*/
-static void gic_ack_irq(unsigned int irq)
+static void gic_ack_irq(struct irq_data *d)
{
-
spin_lock(&irq_controller_lock);
- writel(gic_irq(irq), gic_cpu_base(irq) + GIC_CPU_EOI);
+ writel(gic_irq(d), gic_cpu_base(d) + GIC_CPU_EOI);
spin_unlock(&irq_controller_lock);
}
-static void gic_mask_irq(unsigned int irq)
+static void gic_mask_irq(struct irq_data *d)
{
- u32 mask = 1 << (irq % 32);
+ u32 mask = 1 << (d->irq % 32);
spin_lock(&irq_controller_lock);
- writel(mask, gic_dist_base(irq) + GIC_DIST_ENABLE_CLEAR + (gic_irq(irq) / 32) * 4);
+ writel(mask, gic_dist_base(d) + GIC_DIST_ENABLE_CLEAR + (gic_irq(d) / 32) * 4);
spin_unlock(&irq_controller_lock);
}
-static void gic_unmask_irq(unsigned int irq)
+static void gic_unmask_irq(struct irq_data *d)
{
- u32 mask = 1 << (irq % 32);
+ u32 mask = 1 << (d->irq % 32);
spin_lock(&irq_controller_lock);
- writel(mask, gic_dist_base(irq) + GIC_DIST_ENABLE_SET + (gic_irq(irq) / 32) * 4);
+ writel(mask, gic_dist_base(d) + GIC_DIST_ENABLE_SET + (gic_irq(d) / 32) * 4);
spin_unlock(&irq_controller_lock);
}
-static int gic_set_type(unsigned int irq, unsigned int type)
+static int gic_set_type(struct irq_data *d, unsigned int type)
{
- void __iomem *base = gic_dist_base(irq);
- unsigned int gicirq = gic_irq(irq);
+ void __iomem *base = gic_dist_base(d);
+ unsigned int gicirq = gic_irq(d);
u32 enablemask = 1 << (gicirq % 32);
u32 enableoff = (gicirq / 32) * 4;
u32 confmask = 0x2 << ((gicirq % 16) * 2);
@@ -143,21 +142,22 @@ static int gic_set_type(unsigned int irq, unsigned int type)
}
#ifdef CONFIG_SMP
-static int gic_set_cpu(unsigned int irq, const struct cpumask *mask_val)
+static int
+gic_set_cpu(struct irq_data *d, const struct cpumask *mask_val, bool force)
{
- void __iomem *reg = gic_dist_base(irq) + GIC_DIST_TARGET + (gic_irq(irq) & ~3);
- unsigned int shift = (irq % 4) * 8;
+ void __iomem *reg = gic_dist_base(d) + GIC_DIST_TARGET + (gic_irq(d) & ~3);
+ unsigned int shift = (d->irq % 4) * 8;
unsigned int cpu = cpumask_first(mask_val);
u32 val;
struct irq_desc *desc;
spin_lock(&irq_controller_lock);
- desc = irq_to_desc(irq);
+ desc = irq_to_desc(d->irq);
if (desc == NULL) {
spin_unlock(&irq_controller_lock);
return -EINVAL;
}
- desc->node = cpu;
+ d->node = cpu;
val = readl(reg) & ~(0xff << shift);
val |= 1 << (cpu + shift);
writel(val, reg);
@@ -175,7 +175,7 @@ static void gic_handle_cascade_irq(unsigned int irq, struct irq_desc *desc)
unsigned long status;
/* primary controller ack'ing */
- chip->ack(irq);
+ chip->irq_ack(&desc->irq_data);
spin_lock(&irq_controller_lock);
status = readl(chip_data->cpu_base + GIC_CPU_INTACK);
@@ -193,17 +193,17 @@ static void gic_handle_cascade_irq(unsigned int irq, struct irq_desc *desc)
out:
/* primary controller unmasking */
- chip->unmask(irq);
+ chip->irq_unmask(&desc->irq_data);
}
static struct irq_chip gic_chip = {
- .name = "GIC",
- .ack = gic_ack_irq,
- .mask = gic_mask_irq,
- .unmask = gic_unmask_irq,
- .set_type = gic_set_type,
+ .name = "GIC",
+ .irq_ack = gic_ack_irq,
+ .irq_mask = gic_mask_irq,
+ .irq_unmask = gic_unmask_irq,
+ .irq_set_type = gic_set_type,
#ifdef CONFIG_SMP
- .set_affinity = gic_set_cpu,
+ .irq_set_affinity = gic_set_cpu,
#endif
};
@@ -337,7 +337,7 @@ void __cpuinit gic_enable_ppi(unsigned int irq)
local_irq_save(flags);
irq_to_desc(irq)->status |= IRQ_NOPROBE;
- gic_unmask_irq(irq);
+ gic_unmask_irq(irq_get_irq_data(irq));
local_irq_restore(flags);
}
diff --git a/arch/arm/common/it8152.c b/arch/arm/common/it8152.c
index 665ebf7..fcddd48 100644
--- a/arch/arm/common/it8152.c
+++ b/arch/arm/common/it8152.c
@@ -31,8 +31,10 @@
#define MAX_SLOTS 21
-static void it8152_mask_irq(unsigned int irq)
+static void it8152_mask_irq(struct irq_data *d)
{
+ unsigned int irq = d->irq;
+
if (irq >= IT8152_LD_IRQ(0)) {
__raw_writel((__raw_readl(IT8152_INTC_LDCNIMR) |
(1 << (irq - IT8152_LD_IRQ(0)))),
@@ -48,8 +50,10 @@ static void it8152_mask_irq(unsigned int irq)
}
}
-static void it8152_unmask_irq(unsigned int irq)
+static void it8152_unmask_irq(struct irq_data *d)
{
+ unsigned int irq = d->irq;
+
if (irq >= IT8152_LD_IRQ(0)) {
__raw_writel((__raw_readl(IT8152_INTC_LDCNIMR) &
~(1 << (irq - IT8152_LD_IRQ(0)))),
@@ -67,9 +71,9 @@ static void it8152_unmask_irq(unsigned int irq)
static struct irq_chip it8152_irq_chip = {
.name = "it8152",
- .ack = it8152_mask_irq,
- .mask = it8152_mask_irq,
- .unmask = it8152_unmask_irq,
+ .irq_ack = it8152_mask_irq,
+ .irq_mask = it8152_mask_irq,
+ .irq_unmask = it8152_unmask_irq,
};
void it8152_init_irq(void)
diff --git a/arch/arm/common/locomo.c b/arch/arm/common/locomo.c
index 9dff07c..a026a6b 100644
--- a/arch/arm/common/locomo.c
+++ b/arch/arm/common/locomo.c
@@ -144,7 +144,7 @@ static void locomo_handler(unsigned int irq, struct irq_desc *desc)
int req, i;
/* Acknowledge the parent IRQ */
- desc->chip->ack(irq);
+ desc->irq_data.chip->irq_ack(&desc->irq_data);
/* check why this interrupt was generated */
req = locomo_readl(lchip->base + LOCOMO_ICR) & 0x0f00;
@@ -161,33 +161,33 @@ static void locomo_handler(unsigned int irq, struct irq_desc *desc)
}
}
-static void locomo_ack_irq(unsigned int irq)
+static void locomo_ack_irq(struct irq_data *d)
{
}
-static void locomo_mask_irq(unsigned int irq)
+static void locomo_mask_irq(struct irq_data *d)
{
- struct locomo *lchip = get_irq_chip_data(irq);
+ struct locomo *lchip = irq_data_get_irq_chip_data(d);
unsigned int r;
r = locomo_readl(lchip->base + LOCOMO_ICR);
- r &= ~(0x0010 << (irq - lchip->irq_base));
+ r &= ~(0x0010 << (d->irq - lchip->irq_base));
locomo_writel(r, lchip->base + LOCOMO_ICR);
}
-static void locomo_unmask_irq(unsigned int irq)
+static void locomo_unmask_irq(struct irq_data *d)
{
- struct locomo *lchip = get_irq_chip_data(irq);
+ struct locomo *lchip = irq_data_get_irq_chip_data(d);
unsigned int r;
r = locomo_readl(lchip->base + LOCOMO_ICR);
- r |= (0x0010 << (irq - lchip->irq_base));
+ r |= (0x0010 << (d->irq - lchip->irq_base));
locomo_writel(r, lchip->base + LOCOMO_ICR);
}
static struct irq_chip locomo_chip = {
- .name = "LOCOMO",
- .ack = locomo_ack_irq,
- .mask = locomo_mask_irq,
- .unmask = locomo_unmask_irq,
+ .name = "LOCOMO",
+ .irq_ack = locomo_ack_irq,
+ .irq_mask = locomo_mask_irq,
+ .irq_unmask = locomo_unmask_irq,
};
static void locomo_setup_irq(struct locomo *lchip)
diff --git a/arch/arm/common/sa1111.c b/arch/arm/common/sa1111.c
index c0258a8..eb9796b 100644
--- a/arch/arm/common/sa1111.c
+++ b/arch/arm/common/sa1111.c
@@ -210,7 +210,7 @@ sa1111_irq_handler(unsigned int irq, struct irq_desc *desc)
sa1111_writel(stat0, mapbase + SA1111_INTSTATCLR0);
- desc->chip->ack(irq);
+ desc->irq_data.chip->irq_ack(&desc->irq_data);
sa1111_writel(stat1, mapbase + SA1111_INTSTATCLR1);
@@ -228,35 +228,35 @@ sa1111_irq_handler(unsigned int irq, struct irq_desc *desc)
generic_handle_irq(i + sachip->irq_base);
/* For level-based interrupts */
- desc->chip->unmask(irq);
+ desc->irq_data.chip->irq_unmask(&desc->irq_data);
}
#define SA1111_IRQMASK_LO(x) (1 << (x - sachip->irq_base))
#define SA1111_IRQMASK_HI(x) (1 << (x - sachip->irq_base - 32))
-static void sa1111_ack_irq(unsigned int irq)
+static void sa1111_ack_irq(struct irq_data *d)
{
}
-static void sa1111_mask_lowirq(unsigned int irq)
+static void sa1111_mask_lowirq(struct irq_data *d)
{
- struct sa1111 *sachip = get_irq_chip_data(irq);
+ struct sa1111 *sachip = irq_data_get_irq_chip_data(d);
void __iomem *mapbase = sachip->base + SA1111_INTC;
unsigned long ie0;
ie0 = sa1111_readl(mapbase + SA1111_INTEN0);
- ie0 &= ~SA1111_IRQMASK_LO(irq);
+ ie0 &= ~SA1111_IRQMASK_LO(d->irq);
writel(ie0, mapbase + SA1111_INTEN0);
}
-static void sa1111_unmask_lowirq(unsigned int irq)
+static void sa1111_unmask_lowirq(struct irq_data *d)
{
- struct sa1111 *sachip = get_irq_chip_data(irq);
+ struct sa1111 *sachip = irq_data_get_irq_chip_data(d);
void __iomem *mapbase = sachip->base + SA1111_INTC;
unsigned long ie0;
ie0 = sa1111_readl(mapbase + SA1111_INTEN0);
- ie0 |= SA1111_IRQMASK_LO(irq);
+ ie0 |= SA1111_IRQMASK_LO(d->irq);
sa1111_writel(ie0, mapbase + SA1111_INTEN0);
}
@@ -267,11 +267,11 @@ static void sa1111_unmask_lowirq(unsigned int irq)
* be triggered. In fact, its very difficult, if not impossible to get
* INTSET to re-trigger the interrupt.
*/
-static int sa1111_retrigger_lowirq(unsigned int irq)
+static int sa1111_retrigger_lowirq(struct irq_data *d)
{
- struct sa1111 *sachip = get_irq_chip_data(irq);
+ struct sa1111 *sachip = irq_data_get_irq_chip_data(d);
void __iomem *mapbase = sachip->base + SA1111_INTC;
- unsigned int mask = SA1111_IRQMASK_LO(irq);
+ unsigned int mask = SA1111_IRQMASK_LO(d->irq);
unsigned long ip0;
int i;
@@ -279,21 +279,21 @@ static int sa1111_retrigger_lowirq(unsigned int irq)
for (i = 0; i < 8; i++) {
sa1111_writel(ip0 ^ mask, mapbase + SA1111_INTPOL0);
sa1111_writel(ip0, mapbase + SA1111_INTPOL0);
- if (sa1111_readl(mapbase + SA1111_INTSTATCLR1) & mask)
+ if (sa1111_readl(mapbase + SA1111_INTSTATCLR0) & mask)
break;
}
if (i == 8)
printk(KERN_ERR "Danger Will Robinson: failed to "
- "re-trigger IRQ%d\n", irq);
+ "re-trigger IRQ%d\n", d->irq);
return i == 8 ? -1 : 0;
}
-static int sa1111_type_lowirq(unsigned int irq, unsigned int flags)
+static int sa1111_type_lowirq(struct irq_data *d, unsigned int flags)
{
- struct sa1111 *sachip = get_irq_chip_data(irq);
+ struct sa1111 *sachip = irq_data_get_irq_chip_data(d);
void __iomem *mapbase = sachip->base + SA1111_INTC;
- unsigned int mask = SA1111_IRQMASK_LO(irq);
+ unsigned int mask = SA1111_IRQMASK_LO(d->irq);
unsigned long ip0;
if (flags == IRQ_TYPE_PROBE)
@@ -313,11 +313,11 @@ static int sa1111_type_lowirq(unsigned int irq, unsigned int flags)
return 0;
}
-static int sa1111_wake_lowirq(unsigned int irq, unsigned int on)
+static int sa1111_wake_lowirq(struct irq_data *d, unsigned int on)
{
- struct sa1111 *sachip = get_irq_chip_data(irq);
+ struct sa1111 *sachip = irq_data_get_irq_chip_data(d);
void __iomem *mapbase = sachip->base + SA1111_INTC;
- unsigned int mask = SA1111_IRQMASK_LO(irq);
+ unsigned int mask = SA1111_IRQMASK_LO(d->irq);
unsigned long we0;
we0 = sa1111_readl(mapbase + SA1111_WAKEEN0);
@@ -332,33 +332,33 @@ static int sa1111_wake_lowirq(unsigned int irq, unsigned int on)
static struct irq_chip sa1111_low_chip = {
.name = "SA1111-l",
- .ack = sa1111_ack_irq,
- .mask = sa1111_mask_lowirq,
- .unmask = sa1111_unmask_lowirq,
- .retrigger = sa1111_retrigger_lowirq,
- .set_type = sa1111_type_lowirq,
- .set_wake = sa1111_wake_lowirq,
+ .irq_ack = sa1111_ack_irq,
+ .irq_mask = sa1111_mask_lowirq,
+ .irq_unmask = sa1111_unmask_lowirq,
+ .irq_retrigger = sa1111_retrigger_lowirq,
+ .irq_set_type = sa1111_type_lowirq,
+ .irq_set_wake = sa1111_wake_lowirq,
};
-static void sa1111_mask_highirq(unsigned int irq)
+static void sa1111_mask_highirq(struct irq_data *d)
{
- struct sa1111 *sachip = get_irq_chip_data(irq);
+ struct sa1111 *sachip = irq_data_get_irq_chip_data(d);
void __iomem *mapbase = sachip->base + SA1111_INTC;
unsigned long ie1;
ie1 = sa1111_readl(mapbase + SA1111_INTEN1);
- ie1 &= ~SA1111_IRQMASK_HI(irq);
+ ie1 &= ~SA1111_IRQMASK_HI(d->irq);
sa1111_writel(ie1, mapbase + SA1111_INTEN1);
}
-static void sa1111_unmask_highirq(unsigned int irq)
+static void sa1111_unmask_highirq(struct irq_data *d)
{
- struct sa1111 *sachip = get_irq_chip_data(irq);
+ struct sa1111 *sachip = irq_data_get_irq_chip_data(d);
void __iomem *mapbase = sachip->base + SA1111_INTC;
unsigned long ie1;
ie1 = sa1111_readl(mapbase + SA1111_INTEN1);
- ie1 |= SA1111_IRQMASK_HI(irq);
+ ie1 |= SA1111_IRQMASK_HI(d->irq);
sa1111_writel(ie1, mapbase + SA1111_INTEN1);
}
@@ -369,11 +369,11 @@ static void sa1111_unmask_highirq(unsigned int irq)
* be triggered. In fact, its very difficult, if not impossible to get
* INTSET to re-trigger the interrupt.
*/
-static int sa1111_retrigger_highirq(unsigned int irq)
+static int sa1111_retrigger_highirq(struct irq_data *d)
{
- struct sa1111 *sachip = get_irq_chip_data(irq);
+ struct sa1111 *sachip = irq_data_get_irq_chip_data(d);
void __iomem *mapbase = sachip->base + SA1111_INTC;
- unsigned int mask = SA1111_IRQMASK_HI(irq);
+ unsigned int mask = SA1111_IRQMASK_HI(d->irq);
unsigned long ip1;
int i;
@@ -387,15 +387,15 @@ static int sa1111_retrigger_highirq(unsigned int irq)
if (i == 8)
printk(KERN_ERR "Danger Will Robinson: failed to "
- "re-trigger IRQ%d\n", irq);
+ "re-trigger IRQ%d\n", d->irq);
return i == 8 ? -1 : 0;
}
-static int sa1111_type_highirq(unsigned int irq, unsigned int flags)
+static int sa1111_type_highirq(struct irq_data *d, unsigned int flags)
{
- struct sa1111 *sachip = get_irq_chip_data(irq);
+ struct sa1111 *sachip = irq_data_get_irq_chip_data(d);
void __iomem *mapbase = sachip->base + SA1111_INTC;
- unsigned int mask = SA1111_IRQMASK_HI(irq);
+ unsigned int mask = SA1111_IRQMASK_HI(d->irq);
unsigned long ip1;
if (flags == IRQ_TYPE_PROBE)
@@ -415,11 +415,11 @@ static int sa1111_type_highirq(unsigned int irq, unsigned int flags)
return 0;
}
-static int sa1111_wake_highirq(unsigned int irq, unsigned int on)
+static int sa1111_wake_highirq(struct irq_data *d, unsigned int on)
{
- struct sa1111 *sachip = get_irq_chip_data(irq);
+ struct sa1111 *sachip = irq_data_get_irq_chip_data(d);
void __iomem *mapbase = sachip->base + SA1111_INTC;
- unsigned int mask = SA1111_IRQMASK_HI(irq);
+ unsigned int mask = SA1111_IRQMASK_HI(d->irq);
unsigned long we1;
we1 = sa1111_readl(mapbase + SA1111_WAKEEN1);
@@ -434,12 +434,12 @@ static int sa1111_wake_highirq(unsigned int irq, unsigned int on)
static struct irq_chip sa1111_high_chip = {
.name = "SA1111-h",
- .ack = sa1111_ack_irq,
- .mask = sa1111_mask_highirq,
- .unmask = sa1111_unmask_highirq,
- .retrigger = sa1111_retrigger_highirq,
- .set_type = sa1111_type_highirq,
- .set_wake = sa1111_wake_highirq,
+ .irq_ack = sa1111_ack_irq,
+ .irq_mask = sa1111_mask_highirq,
+ .irq_unmask = sa1111_unmask_highirq,
+ .irq_retrigger = sa1111_retrigger_highirq,
+ .irq_set_type = sa1111_type_highirq,
+ .irq_set_wake = sa1111_wake_highirq,
};
static void sa1111_setup_irq(struct sa1111 *sachip)
diff --git a/arch/arm/common/vic.c b/arch/arm/common/vic.c
index cb660bc..ae5fe72 100644
--- a/arch/arm/common/vic.c
+++ b/arch/arm/common/vic.c
@@ -204,26 +204,26 @@ static void __init vic_pm_register(void __iomem *base, unsigned int irq, u32 res
static inline void vic_pm_register(void __iomem *base, unsigned int irq, u32 arg1) { }
#endif /* CONFIG_PM */
-static void vic_ack_irq(unsigned int irq)
+static void vic_ack_irq(struct irq_data *d)
{
- void __iomem *base = get_irq_chip_data(irq);
- irq &= 31;
+ void __iomem *base = irq_data_get_irq_chip_data(d);
+ unsigned int irq = d->irq & 31;
writel(1 << irq, base + VIC_INT_ENABLE_CLEAR);
/* moreover, clear the soft-triggered, in case it was the reason */
writel(1 << irq, base + VIC_INT_SOFT_CLEAR);
}
-static void vic_mask_irq(unsigned int irq)
+static void vic_mask_irq(struct irq_data *d)
{
- void __iomem *base = get_irq_chip_data(irq);
- irq &= 31;
+ void __iomem *base = irq_data_get_irq_chip_data(d);
+ unsigned int irq = d->irq & 31;
writel(1 << irq, base + VIC_INT_ENABLE_CLEAR);
}
-static void vic_unmask_irq(unsigned int irq)
+static void vic_unmask_irq(struct irq_data *d)
{
- void __iomem *base = get_irq_chip_data(irq);
- irq &= 31;
+ void __iomem *base = irq_data_get_irq_chip_data(d);
+ unsigned int irq = d->irq & 31;
writel(1 << irq, base + VIC_INT_ENABLE);
}
@@ -242,10 +242,10 @@ static struct vic_device *vic_from_irq(unsigned int irq)
return NULL;
}
-static int vic_set_wake(unsigned int irq, unsigned int on)
+static int vic_set_wake(struct irq_data *d, unsigned int on)
{
- struct vic_device *v = vic_from_irq(irq);
- unsigned int off = irq & 31;
+ struct vic_device *v = vic_from_irq(d->irq);
+ unsigned int off = d->irq & 31;
u32 bit = 1 << off;
if (!v)
@@ -267,10 +267,10 @@ static int vic_set_wake(unsigned int irq, unsigned int on)
static struct irq_chip vic_chip = {
.name = "VIC",
- .ack = vic_ack_irq,
- .mask = vic_mask_irq,
- .unmask = vic_unmask_irq,
- .set_wake = vic_set_wake,
+ .irq_ack = vic_ack_irq,
+ .irq_mask = vic_mask_irq,
+ .irq_unmask = vic_unmask_irq,
+ .irq_set_wake = vic_set_wake,
};
static void __init vic_disable(void __iomem *base)
diff --git a/arch/arm/configs/ag5evm_defconfig b/arch/arm/configs/ag5evm_defconfig
index 2b9cf56..212ead3 100644
--- a/arch/arm/configs/ag5evm_defconfig
+++ b/arch/arm/configs/ag5evm_defconfig
@@ -10,7 +10,7 @@ CONFIG_NAMESPACES=y
# CONFIG_PID_NS is not set
CONFIG_BLK_DEV_INITRD=y
CONFIG_INITRAMFS_SOURCE=""
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
CONFIG_SLAB=y
# CONFIG_BLK_DEV_BSG is not set
# CONFIG_IOSCHED_DEADLINE is not set
diff --git a/arch/arm/configs/am200epdkit_defconfig b/arch/arm/configs/am200epdkit_defconfig
index 5536c48..f0dea52 100644
--- a/arch/arm/configs/am200epdkit_defconfig
+++ b/arch/arm/configs/am200epdkit_defconfig
@@ -3,7 +3,7 @@ CONFIG_LOCALVERSION="gum"
# CONFIG_SWAP is not set
CONFIG_SYSVIPC=y
CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_SYSCTL_SYSCALL is not set
# CONFIG_EPOLL is not set
# CONFIG_SHMEM is not set
diff --git a/arch/arm/configs/at572d940hfek_defconfig b/arch/arm/configs/at572d940hfek_defconfig
index 695e32d..1b1158a 100644
--- a/arch/arm/configs/at572d940hfek_defconfig
+++ b/arch/arm/configs/at572d940hfek_defconfig
@@ -17,7 +17,7 @@ CONFIG_SYSFS_DEPRECATED_V2=y
CONFIG_RELAY=y
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
CONFIG_SLAB=y
CONFIG_PROFILING=y
CONFIG_OPROFILE=m
diff --git a/arch/arm/configs/badge4_defconfig b/arch/arm/configs/badge4_defconfig
index 3a1ad15..5b54abb 100644
--- a/arch/arm/configs/badge4_defconfig
+++ b/arch/arm/configs/badge4_defconfig
@@ -1,6 +1,6 @@
CONFIG_EXPERIMENTAL=y
CONFIG_LOG_BUF_SHIFT=14
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
CONFIG_MODULES=y
CONFIG_MODVERSIONS=y
CONFIG_ARCH_SA1100=y
diff --git a/arch/arm/configs/bcmring_defconfig b/arch/arm/configs/bcmring_defconfig
index 75984cd..795374d 100644
--- a/arch/arm/configs/bcmring_defconfig
+++ b/arch/arm/configs/bcmring_defconfig
@@ -2,7 +2,7 @@ CONFIG_EXPERIMENTAL=y
# CONFIG_LOCALVERSION_AUTO is not set
# CONFIG_SWAP is not set
CONFIG_SYSVIPC=y
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
CONFIG_KALLSYMS_EXTRA_PASS=y
# CONFIG_HOTPLUG is not set
# CONFIG_ELF_CORE is not set
diff --git a/arch/arm/configs/cm_x2xx_defconfig b/arch/arm/configs/cm_x2xx_defconfig
index dcfbcf3..a93ff8d 100644
--- a/arch/arm/configs/cm_x2xx_defconfig
+++ b/arch/arm/configs/cm_x2xx_defconfig
@@ -6,7 +6,7 @@ CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_SYSFS_DEPRECATED_V2=y
CONFIG_BLK_DEV_INITRD=y
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_VM_EVENT_COUNTERS is not set
# CONFIG_SLUB_DEBUG is not set
# CONFIG_COMPAT_BRK is not set
diff --git a/arch/arm/configs/colibri_pxa270_defconfig b/arch/arm/configs/colibri_pxa270_defconfig
index f52c64e..2ef2c5e 100644
--- a/arch/arm/configs/colibri_pxa270_defconfig
+++ b/arch/arm/configs/colibri_pxa270_defconfig
@@ -8,7 +8,7 @@ CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_SYSFS_DEPRECATED_V2=y
CONFIG_BLK_DEV_INITRD=y
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
CONFIG_KALLSYMS_EXTRA_PASS=y
CONFIG_SLAB=y
CONFIG_MODULES=y
diff --git a/arch/arm/configs/collie_defconfig b/arch/arm/configs/collie_defconfig
index 310f9a6..6c56ad0 100644
--- a/arch/arm/configs/collie_defconfig
+++ b/arch/arm/configs/collie_defconfig
@@ -4,7 +4,7 @@ CONFIG_SYSVIPC=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_BASE_FULL is not set
# CONFIG_EPOLL is not set
CONFIG_SLOB=y
diff --git a/arch/arm/configs/corgi_defconfig b/arch/arm/configs/corgi_defconfig
index 4a1fa81..e53c475 100644
--- a/arch/arm/configs/corgi_defconfig
+++ b/arch/arm/configs/corgi_defconfig
@@ -4,7 +4,7 @@ CONFIG_BSD_PROCESS_ACCT=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_SYSFS_DEPRECATED_V2=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
CONFIG_PROFILING=y
CONFIG_OPROFILE=m
CONFIG_MODULES=y
diff --git a/arch/arm/configs/da8xx_omapl_defconfig b/arch/arm/configs/da8xx_omapl_defconfig
index cdc40c4..88ccde0 100644
--- a/arch/arm/configs/da8xx_omapl_defconfig
+++ b/arch/arm/configs/da8xx_omapl_defconfig
@@ -6,7 +6,7 @@ CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_BLK_DEV_INITRD=y
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
CONFIG_MODULE_FORCE_UNLOAD=y
diff --git a/arch/arm/configs/davinci_all_defconfig b/arch/arm/configs/davinci_all_defconfig
index 2519cc5..889922a 100644
--- a/arch/arm/configs/davinci_all_defconfig
+++ b/arch/arm/configs/davinci_all_defconfig
@@ -6,7 +6,7 @@ CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_BLK_DEV_INITRD=y
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
CONFIG_MODULE_FORCE_UNLOAD=y
diff --git a/arch/arm/configs/dove_defconfig b/arch/arm/configs/dove_defconfig
index 9359e1b..54bf5ee 100644
--- a/arch/arm/configs/dove_defconfig
+++ b/arch/arm/configs/dove_defconfig
@@ -1,7 +1,7 @@
CONFIG_EXPERIMENTAL=y
CONFIG_SYSVIPC=y
CONFIG_LOG_BUF_SHIFT=14
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
CONFIG_SLAB=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
diff --git a/arch/arm/configs/ebsa110_defconfig b/arch/arm/configs/ebsa110_defconfig
index c319418..14559db 100644
--- a/arch/arm/configs/ebsa110_defconfig
+++ b/arch/arm/configs/ebsa110_defconfig
@@ -2,7 +2,7 @@ CONFIG_EXPERIMENTAL=y
CONFIG_SYSVIPC=y
CONFIG_BSD_PROCESS_ACCT=y
CONFIG_LOG_BUF_SHIFT=14
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
CONFIG_MODULES=y
CONFIG_ARCH_EBSA110=y
CONFIG_PCCARD=m
diff --git a/arch/arm/configs/edb7211_defconfig b/arch/arm/configs/edb7211_defconfig
index 7b62be1..d52ded35 100644
--- a/arch/arm/configs/edb7211_defconfig
+++ b/arch/arm/configs/edb7211_defconfig
@@ -2,7 +2,7 @@ CONFIG_EXPERIMENTAL=y
CONFIG_SYSVIPC=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_BLK_DEV_INITRD=y
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_HOTPLUG is not set
CONFIG_ARCH_CLPS711X=y
CONFIG_ARCH_EDB7211=y
diff --git a/arch/arm/configs/em_x270_defconfig b/arch/arm/configs/em_x270_defconfig
index d7db34f..60a21e0 100644
--- a/arch/arm/configs/em_x270_defconfig
+++ b/arch/arm/configs/em_x270_defconfig
@@ -6,7 +6,7 @@ CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_SYSFS_DEPRECATED_V2=y
CONFIG_BLK_DEV_INITRD=y
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_VM_EVENT_COUNTERS is not set
# CONFIG_SLUB_DEBUG is not set
# CONFIG_COMPAT_BRK is not set
diff --git a/arch/arm/configs/ep93xx_defconfig b/arch/arm/configs/ep93xx_defconfig
index 6d6689c..8e97b2f 100644
--- a/arch/arm/configs/ep93xx_defconfig
+++ b/arch/arm/configs/ep93xx_defconfig
@@ -4,7 +4,7 @@ CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
CONFIG_SLAB=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
diff --git a/arch/arm/configs/eseries_pxa_defconfig b/arch/arm/configs/eseries_pxa_defconfig
index 1691dea..d68ac67 100644
--- a/arch/arm/configs/eseries_pxa_defconfig
+++ b/arch/arm/configs/eseries_pxa_defconfig
@@ -2,7 +2,7 @@ CONFIG_EXPERIMENTAL=y
CONFIG_SYSVIPC=y
CONFIG_LOG_BUF_SHIFT=14
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_KALLSYMS is not set
# CONFIG_COMPAT_BRK is not set
CONFIG_SLAB=y
diff --git a/arch/arm/configs/ezx_defconfig b/arch/arm/configs/ezx_defconfig
index c4eeb6d..227a477 100644
--- a/arch/arm/configs/ezx_defconfig
+++ b/arch/arm/configs/ezx_defconfig
@@ -7,7 +7,7 @@ CONFIG_SYSFS_DEPRECATED_V2=y
CONFIG_BLK_DEV_INITRD=y
CONFIG_RD_BZIP2=y
CONFIG_RD_LZMA=y
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_COMPAT_BRK is not set
CONFIG_SLAB=y
CONFIG_MODULES=y
diff --git a/arch/arm/configs/footbridge_defconfig b/arch/arm/configs/footbridge_defconfig
index 4f925ea..038518a 100644
--- a/arch/arm/configs/footbridge_defconfig
+++ b/arch/arm/configs/footbridge_defconfig
@@ -3,7 +3,7 @@ CONFIG_SYSVIPC=y
CONFIG_BSD_PROCESS_ACCT=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_BLK_DEV_INITRD=y
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_HOTPLUG is not set
CONFIG_MODULES=y
CONFIG_ARCH_FOOTBRIDGE=y
diff --git a/arch/arm/configs/fortunet_defconfig b/arch/arm/configs/fortunet_defconfig
index e11c7ea..840fced 100644
--- a/arch/arm/configs/fortunet_defconfig
+++ b/arch/arm/configs/fortunet_defconfig
@@ -2,7 +2,7 @@ CONFIG_EXPERIMENTAL=y
CONFIG_SYSVIPC=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_BLK_DEV_INITRD=y
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_HOTPLUG is not set
CONFIG_ARCH_CLPS711X=y
CONFIG_ARCH_FORTUNET=y
diff --git a/arch/arm/configs/h5000_defconfig b/arch/arm/configs/h5000_defconfig
index ac336f1..37903e3 100644
--- a/arch/arm/configs/h5000_defconfig
+++ b/arch/arm/configs/h5000_defconfig
@@ -4,7 +4,7 @@ CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=16
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_UID16 is not set
CONFIG_SLAB=y
CONFIG_MODULES=y
diff --git a/arch/arm/configs/imote2_defconfig b/arch/arm/configs/imote2_defconfig
index ade55c8..176ec22 100644
--- a/arch/arm/configs/imote2_defconfig
+++ b/arch/arm/configs/imote2_defconfig
@@ -6,7 +6,7 @@ CONFIG_SYSFS_DEPRECATED_V2=y
CONFIG_BLK_DEV_INITRD=y
CONFIG_RD_BZIP2=y
CONFIG_RD_LZMA=y
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_COMPAT_BRK is not set
CONFIG_SLAB=y
CONFIG_MODULES=y
diff --git a/arch/arm/configs/ixp2000_defconfig b/arch/arm/configs/ixp2000_defconfig
index 9083246..8405ade 100644
--- a/arch/arm/configs/ixp2000_defconfig
+++ b/arch/arm/configs/ixp2000_defconfig
@@ -3,7 +3,7 @@ CONFIG_SYSVIPC=y
CONFIG_BSD_PROCESS_ACCT=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_BLK_DEV_INITRD=y
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_HOTPLUG is not set
CONFIG_SLAB=y
CONFIG_MODULES=y
diff --git a/arch/arm/configs/ixp23xx_defconfig b/arch/arm/configs/ixp23xx_defconfig
index 7fc056a..6887176 100644
--- a/arch/arm/configs/ixp23xx_defconfig
+++ b/arch/arm/configs/ixp23xx_defconfig
@@ -3,7 +3,7 @@ CONFIG_SYSVIPC=y
CONFIG_BSD_PROCESS_ACCT=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_BLK_DEV_INITRD=y
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
CONFIG_SLAB=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
diff --git a/arch/arm/configs/ixp4xx_defconfig b/arch/arm/configs/ixp4xx_defconfig
index 5c50239..063e2ab 100644
--- a/arch/arm/configs/ixp4xx_defconfig
+++ b/arch/arm/configs/ixp4xx_defconfig
@@ -3,7 +3,7 @@ CONFIG_SYSVIPC=y
CONFIG_BSD_PROCESS_ACCT=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_BLK_DEV_INITRD=y
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
CONFIG_MODULES=y
CONFIG_MODVERSIONS=y
# CONFIG_BLK_DEV_BSG is not set
diff --git a/arch/arm/configs/loki_defconfig b/arch/arm/configs/loki_defconfig
index e1eaff7..1ba752b 100644
--- a/arch/arm/configs/loki_defconfig
+++ b/arch/arm/configs/loki_defconfig
@@ -1,7 +1,7 @@
CONFIG_EXPERIMENTAL=y
CONFIG_SYSVIPC=y
CONFIG_LOG_BUF_SHIFT=14
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
CONFIG_SLAB=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
diff --git a/arch/arm/configs/lpd7a400_defconfig b/arch/arm/configs/lpd7a400_defconfig
index 20caaab..5a48f17 100644
--- a/arch/arm/configs/lpd7a400_defconfig
+++ b/arch/arm/configs/lpd7a400_defconfig
@@ -3,7 +3,7 @@ CONFIG_EXPERIMENTAL=y
CONFIG_SYSVIPC=y
CONFIG_IKCONFIG=y
CONFIG_LOG_BUF_SHIFT=14
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_HOTPLUG is not set
# CONFIG_EPOLL is not set
# CONFIG_IOSCHED_DEADLINE is not set
diff --git a/arch/arm/configs/lpd7a404_defconfig b/arch/arm/configs/lpd7a404_defconfig
index 1efcce9..22d0631 100644
--- a/arch/arm/configs/lpd7a404_defconfig
+++ b/arch/arm/configs/lpd7a404_defconfig
@@ -3,7 +3,7 @@ CONFIG_EXPERIMENTAL=y
CONFIG_SYSVIPC=y
CONFIG_IKCONFIG=y
CONFIG_LOG_BUF_SHIFT=16
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_HOTPLUG is not set
# CONFIG_EPOLL is not set
CONFIG_SLAB=y
diff --git a/arch/arm/configs/magician_defconfig b/arch/arm/configs/magician_defconfig
index af805e8..a88e64d 100644
--- a/arch/arm/configs/magician_defconfig
+++ b/arch/arm/configs/magician_defconfig
@@ -4,7 +4,7 @@ CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=16
CONFIG_BLK_DEV_INITRD=y
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_UID16 is not set
CONFIG_SLAB=y
CONFIG_MODULES=y
diff --git a/arch/arm/configs/mv78xx0_defconfig b/arch/arm/configs/mv78xx0_defconfig
index b0d0824..7305ebd 100644
--- a/arch/arm/configs/mv78xx0_defconfig
+++ b/arch/arm/configs/mv78xx0_defconfig
@@ -2,7 +2,7 @@ CONFIG_EXPERIMENTAL=y
CONFIG_SYSVIPC=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
CONFIG_KALLSYMS_ALL=y
# CONFIG_SLUB_DEBUG is not set
CONFIG_PROFILING=y
diff --git a/arch/arm/configs/mx1_defconfig b/arch/arm/configs/mx1_defconfig
index 2f38d97..b39b5ce 100644
--- a/arch/arm/configs/mx1_defconfig
+++ b/arch/arm/configs/mx1_defconfig
@@ -4,7 +4,7 @@ CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
CONFIG_SLAB=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
diff --git a/arch/arm/configs/mx21_defconfig b/arch/arm/configs/mx21_defconfig
index 6454e18..411f88d 100644
--- a/arch/arm/configs/mx21_defconfig
+++ b/arch/arm/configs/mx21_defconfig
@@ -4,7 +4,7 @@ CONFIG_SYSVIPC=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_SYSFS_DEPRECATED_V2=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
CONFIG_KALLSYMS_EXTRA_PASS=y
CONFIG_SLAB=y
CONFIG_MODULES=y
diff --git a/arch/arm/configs/mx27_defconfig b/arch/arm/configs/mx27_defconfig
index 813cfb3..9ad4c656 100644
--- a/arch/arm/configs/mx27_defconfig
+++ b/arch/arm/configs/mx27_defconfig
@@ -4,7 +4,7 @@ CONFIG_SYSVIPC=y
CONFIG_POSIX_MQUEUE=y
CONFIG_LOG_BUF_SHIFT=14
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
CONFIG_KALLSYMS_EXTRA_PASS=y
# CONFIG_COMPAT_BRK is not set
CONFIG_SLAB=y
diff --git a/arch/arm/configs/mx3_defconfig b/arch/arm/configs/mx3_defconfig
index e648ea3..7c4b30b 100644
--- a/arch/arm/configs/mx3_defconfig
+++ b/arch/arm/configs/mx3_defconfig
@@ -4,7 +4,7 @@ CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
CONFIG_SLAB=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
diff --git a/arch/arm/configs/mx51_defconfig b/arch/arm/configs/mx51_defconfig
index 5c7a872..9cba68c 100644
--- a/arch/arm/configs/mx51_defconfig
+++ b/arch/arm/configs/mx51_defconfig
@@ -3,7 +3,7 @@ CONFIG_EXPERIMENTAL=y
CONFIG_SYSVIPC=y
CONFIG_LOG_BUF_SHIFT=18
CONFIG_RELAY=y
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_SLUB_DEBUG is not set
# CONFIG_COMPAT_BRK is not set
CONFIG_MODULES=y
diff --git a/arch/arm/configs/nhk8815_defconfig b/arch/arm/configs/nhk8815_defconfig
index 0e2dc26..37207d1 100644
--- a/arch/arm/configs/nhk8815_defconfig
+++ b/arch/arm/configs/nhk8815_defconfig
@@ -7,7 +7,7 @@ CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_SYSFS_DEPRECATED_V2=y
CONFIG_BLK_DEV_INITRD=y
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
CONFIG_KALLSYMS_ALL=y
CONFIG_SLAB=y
CONFIG_MODULES=y
diff --git a/arch/arm/configs/omap1_defconfig b/arch/arm/configs/omap1_defconfig
index a350cc6..7b63462 100644
--- a/arch/arm/configs/omap1_defconfig
+++ b/arch/arm/configs/omap1_defconfig
@@ -6,7 +6,7 @@ CONFIG_BSD_PROCESS_ACCT=y
CONFIG_IKCONFIG=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_BLK_DEV_INITRD=y
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_KALLSYMS is not set
# CONFIG_ELF_CORE is not set
# CONFIG_BASE_FULL is not set
diff --git a/arch/arm/configs/omap2plus_defconfig b/arch/arm/configs/omap2plus_defconfig
index ccedde1..ae890ca 100644
--- a/arch/arm/configs/omap2plus_defconfig
+++ b/arch/arm/configs/omap2plus_defconfig
@@ -6,7 +6,7 @@ CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=16
CONFIG_BLK_DEV_INITRD=y
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_SYSCTL_SYSCALL is not set
CONFIG_KALLSYMS_EXTRA_PASS=y
CONFIG_SLAB=y
diff --git a/arch/arm/configs/orion5x_defconfig b/arch/arm/configs/orion5x_defconfig
index 439323b..a288d70 100644
--- a/arch/arm/configs/orion5x_defconfig
+++ b/arch/arm/configs/orion5x_defconfig
@@ -2,7 +2,7 @@ CONFIG_EXPERIMENTAL=y
CONFIG_SYSVIPC=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_SLUB_DEBUG is not set
CONFIG_PROFILING=y
CONFIG_OPROFILE=y
diff --git a/arch/arm/configs/pcm027_defconfig b/arch/arm/configs/pcm027_defconfig
index 583a061..2f136c3 100644
--- a/arch/arm/configs/pcm027_defconfig
+++ b/arch/arm/configs/pcm027_defconfig
@@ -7,7 +7,7 @@ CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=14
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_KALLSYMS is not set
CONFIG_SLAB=y
CONFIG_MODULES=y
diff --git a/arch/arm/configs/pcontrol_g20_defconfig b/arch/arm/configs/pcontrol_g20_defconfig
index b42ee62..c75c9fc 100644
--- a/arch/arm/configs/pcontrol_g20_defconfig
+++ b/arch/arm/configs/pcontrol_g20_defconfig
@@ -10,7 +10,7 @@ CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_NAMESPACES=y
CONFIG_BLK_DEV_INITRD=y
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_SYSCTL_SYSCALL is not set
# CONFIG_KALLSYMS is not set
# CONFIG_VM_EVENT_COUNTERS is not set
diff --git a/arch/arm/configs/pleb_defconfig b/arch/arm/configs/pleb_defconfig
index d1efbdc..cb08cc5 100644
--- a/arch/arm/configs/pleb_defconfig
+++ b/arch/arm/configs/pleb_defconfig
@@ -3,7 +3,7 @@ CONFIG_EXPERIMENTAL=y
CONFIG_SYSVIPC=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_BLK_DEV_INITRD=y
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_HOTPLUG is not set
# CONFIG_SHMEM is not set
CONFIG_MODULES=y
diff --git a/arch/arm/configs/pnx4008_defconfig b/arch/arm/configs/pnx4008_defconfig
index bd481f0..35a31cc 100644
--- a/arch/arm/configs/pnx4008_defconfig
+++ b/arch/arm/configs/pnx4008_defconfig
@@ -5,7 +5,7 @@ CONFIG_BSD_PROCESS_ACCT=y
CONFIG_AUDIT=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_BLK_DEV_INITRD=y
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
CONFIG_SLAB=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
diff --git a/arch/arm/configs/simpad_defconfig b/arch/arm/configs/simpad_defconfig
index af3b12e..d335815 100644
--- a/arch/arm/configs/simpad_defconfig
+++ b/arch/arm/configs/simpad_defconfig
@@ -2,7 +2,7 @@ CONFIG_EXPERIMENTAL=y
CONFIG_LOCALVERSION="oe1"
CONFIG_SYSVIPC=y
CONFIG_LOG_BUF_SHIFT=14
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
CONFIG_KALLSYMS_ALL=y
CONFIG_KALLSYMS_EXTRA_PASS=y
CONFIG_MODULES=y
diff --git a/arch/arm/configs/spitz_defconfig b/arch/arm/configs/spitz_defconfig
index aebd4bb..7015827 100644
--- a/arch/arm/configs/spitz_defconfig
+++ b/arch/arm/configs/spitz_defconfig
@@ -4,7 +4,7 @@ CONFIG_BSD_PROCESS_ACCT=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_SYSFS_DEPRECATED_V2=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
CONFIG_PROFILING=y
CONFIG_OPROFILE=m
CONFIG_MODULES=y
diff --git a/arch/arm/configs/stmp378x_defconfig b/arch/arm/configs/stmp378x_defconfig
index 94a2d90..1079c2b 100644
--- a/arch/arm/configs/stmp378x_defconfig
+++ b/arch/arm/configs/stmp378x_defconfig
@@ -5,7 +5,7 @@ CONFIG_POSIX_MQUEUE=y
CONFIG_BSD_PROCESS_ACCT=y
CONFIG_SYSFS_DEPRECATED_V2=y
CONFIG_BLK_DEV_INITRD=y
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
CONFIG_SLAB=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
diff --git a/arch/arm/configs/stmp37xx_defconfig b/arch/arm/configs/stmp37xx_defconfig
index d8ee58c..564a5cc 100644
--- a/arch/arm/configs/stmp37xx_defconfig
+++ b/arch/arm/configs/stmp37xx_defconfig
@@ -5,7 +5,7 @@ CONFIG_POSIX_MQUEUE=y
CONFIG_BSD_PROCESS_ACCT=y
CONFIG_SYSFS_DEPRECATED_V2=y
CONFIG_BLK_DEV_INITRD=y
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
CONFIG_SLAB=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
diff --git a/arch/arm/configs/tct_hammer_defconfig b/arch/arm/configs/tct_hammer_defconfig
index e89ca19..95c0f0d 100644
--- a/arch/arm/configs/tct_hammer_defconfig
+++ b/arch/arm/configs/tct_hammer_defconfig
@@ -5,7 +5,7 @@ CONFIG_SYSVIPC=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_SYSFS_DEPRECATED_V2=y
CONFIG_BLK_DEV_INITRD=y
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_KALLSYMS is not set
# CONFIG_BUG is not set
# CONFIG_ELF_CORE is not set
diff --git a/arch/arm/configs/trizeps4_defconfig b/arch/arm/configs/trizeps4_defconfig
index 37f4834..3162173 100644
--- a/arch/arm/configs/trizeps4_defconfig
+++ b/arch/arm/configs/trizeps4_defconfig
@@ -7,7 +7,7 @@ CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_BLK_DEV_INITRD=y
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
CONFIG_KALLSYMS_EXTRA_PASS=y
CONFIG_SLAB=y
CONFIG_MODULES=y
diff --git a/arch/arm/configs/u300_defconfig b/arch/arm/configs/u300_defconfig
index c1c252c..4a5a126 100644
--- a/arch/arm/configs/u300_defconfig
+++ b/arch/arm/configs/u300_defconfig
@@ -3,7 +3,7 @@ CONFIG_EXPERIMENTAL=y
# CONFIG_SWAP is not set
CONFIG_SYSVIPC=y
CONFIG_LOG_BUF_SHIFT=14
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_AIO is not set
# CONFIG_VM_EVENT_COUNTERS is not set
CONFIG_MODULES=y
diff --git a/arch/arm/configs/viper_defconfig b/arch/arm/configs/viper_defconfig
index 9d7bf5e..8b0c717 100644
--- a/arch/arm/configs/viper_defconfig
+++ b/arch/arm/configs/viper_defconfig
@@ -3,7 +3,7 @@ CONFIG_EXPERIMENTAL=y
CONFIG_SYSVIPC=y
CONFIG_LOG_BUF_SHIFT=13
CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_ELF_CORE is not set
# CONFIG_SHMEM is not set
CONFIG_SLAB=y
diff --git a/arch/arm/configs/xcep_defconfig b/arch/arm/configs/xcep_defconfig
index 70d47db..5b55041 100644
--- a/arch/arm/configs/xcep_defconfig
+++ b/arch/arm/configs/xcep_defconfig
@@ -8,7 +8,7 @@ CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=16
CONFIG_SYSFS_DEPRECATED_V2=y
CONFIG_BLK_DEV_INITRD=y
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_UID16 is not set
# CONFIG_SHMEM is not set
# CONFIG_VM_EVENT_COUNTERS is not set
diff --git a/arch/arm/include/asm/bitops.h b/arch/arm/include/asm/bitops.h
index 338ff19..7b1bb2b 100644
--- a/arch/arm/include/asm/bitops.h
+++ b/arch/arm/include/asm/bitops.h
@@ -285,7 +285,7 @@ static inline int fls(int x)
if (__builtin_constant_p(x))
return constant_fls(x);
- asm("clz\t%0, %1" : "=r" (ret) : "r" (x) : "cc");
+ asm("clz\t%0, %1" : "=r" (ret) : "r" (x));
ret = 32 - ret;
return ret;
}
diff --git a/arch/arm/include/asm/sched_clock.h b/arch/arm/include/asm/sched_clock.h
index a84628b..c8e6ddf 100644
--- a/arch/arm/include/asm/sched_clock.h
+++ b/arch/arm/include/asm/sched_clock.h
@@ -115,4 +115,6 @@ static inline void init_fixed_sched_clock(struct clock_data *cd,
}
}
+extern void sched_clock_postinit(void);
+
#endif
diff --git a/arch/arm/kernel/ecard.c b/arch/arm/kernel/ecard.c
index eed2f79..2ad62df 100644
--- a/arch/arm/kernel/ecard.c
+++ b/arch/arm/kernel/ecard.c
@@ -443,40 +443,40 @@ static expansioncard_ops_t ecard_default_ops = {
*
* They are not meant to be called directly, but via enable/disable_irq.
*/
-static void ecard_irq_unmask(unsigned int irqnr)
+static void ecard_irq_unmask(struct irq_data *d)
{
- ecard_t *ec = slot_to_ecard(irqnr - 32);
+ ecard_t *ec = slot_to_ecard(d->irq - 32);
if (ec) {
if (!ec->ops)
ec->ops = &ecard_default_ops;
if (ec->claimed && ec->ops->irqenable)
- ec->ops->irqenable(ec, irqnr);
+ ec->ops->irqenable(ec, d->irq);
else
printk(KERN_ERR "ecard: rejecting request to "
- "enable IRQs for %d\n", irqnr);
+ "enable IRQs for %d\n", d->irq);
}
}
-static void ecard_irq_mask(unsigned int irqnr)
+static void ecard_irq_mask(struct irq_data *d)
{
- ecard_t *ec = slot_to_ecard(irqnr - 32);
+ ecard_t *ec = slot_to_ecard(d->irq - 32);
if (ec) {
if (!ec->ops)
ec->ops = &ecard_default_ops;
if (ec->ops && ec->ops->irqdisable)
- ec->ops->irqdisable(ec, irqnr);
+ ec->ops->irqdisable(ec, d->irq);
}
}
static struct irq_chip ecard_chip = {
- .name = "ECARD",
- .ack = ecard_irq_mask,
- .mask = ecard_irq_mask,
- .unmask = ecard_irq_unmask,
+ .name = "ECARD",
+ .irq_ack = ecard_irq_mask,
+ .irq_mask = ecard_irq_mask,
+ .irq_unmask = ecard_irq_unmask,
};
void ecard_enablefiq(unsigned int fiqnr)
@@ -551,7 +551,7 @@ static void ecard_check_lockup(struct irq_desc *desc)
printk(KERN_ERR "\nInterrupt lockup detected - "
"disabling all expansion card interrupts\n");
- desc->chip->mask(IRQ_EXPANSIONCARD);
+ desc->irq_data.chip->irq_mask(&desc->irq_data);
ecard_dump_irq_state();
}
} else
@@ -574,7 +574,7 @@ ecard_irq_handler(unsigned int irq, struct irq_desc *desc)
ecard_t *ec;
int called = 0;
- desc->chip->mask(irq);
+ desc->irq_data.chip->irq_mask(&desc->irq_data);
for (ec = cards; ec; ec = ec->next) {
int pending;
@@ -591,7 +591,7 @@ ecard_irq_handler(unsigned int irq, struct irq_desc *desc)
called ++;
}
}
- desc->chip->unmask(irq);
+ desc->irq_data.chip->irq_unmask(&desc->irq_data);
if (called == 0)
ecard_check_lockup(desc);
diff --git a/arch/arm/kernel/head-common.S b/arch/arm/kernel/head-common.S
index bbecaac..8f57515 100644
--- a/arch/arm/kernel/head-common.S
+++ b/arch/arm/kernel/head-common.S
@@ -60,6 +60,8 @@ str_a1: .asciz "\nError: unrecognized/unsupported machine ID (r1 = 0x"
str_a2: .asciz ").\n\nAvailable machine support:\n\nID (hex)\tNAME\n"
str_a3: .asciz "\nPlease check your kernel config and/or bootloader.\n"
.align
+#else
+ b __error
#endif
/*
diff --git a/arch/arm/kernel/irq.c b/arch/arm/kernel/irq.c
index 8135438..28536e3 100644
--- a/arch/arm/kernel/irq.c
+++ b/arch/arm/kernel/irq.c
@@ -88,7 +88,7 @@ int show_interrupts(struct seq_file *p, void *v)
seq_printf(p, "%*d: ", prec, i);
for_each_present_cpu(cpu)
seq_printf(p, "%10u ", kstat_irqs_cpu(i, cpu));
- seq_printf(p, " %10s", desc->chip->name ? : "-");
+ seq_printf(p, " %10s", desc->irq_data.chip->name ? : "-");
seq_printf(p, " %s", action->name);
for (action = action->next; action; action = action->next)
seq_printf(p, ", %s", action->name);
@@ -181,10 +181,11 @@ int __init arch_probe_nr_irqs(void)
static void route_irq(struct irq_desc *desc, unsigned int irq, unsigned int cpu)
{
- pr_debug("IRQ%u: moving from cpu%u to cpu%u\n", irq, desc->node, cpu);
+ pr_debug("IRQ%u: moving from cpu%u to cpu%u\n", irq, desc->irq_data.node, cpu);
raw_spin_lock_irq(&desc->lock);
- desc->chip->set_affinity(irq, cpumask_of(cpu));
+ desc->irq_data.chip->irq_set_affinity(&desc->irq_data,
+ cpumask_of(cpu), false);
raw_spin_unlock_irq(&desc->lock);
}
@@ -199,16 +200,18 @@ void migrate_irqs(void)
struct irq_desc *desc;
for_each_irq_desc(i, desc) {
- if (desc->node == cpu) {
- unsigned int newcpu = cpumask_any_and(desc->affinity,
+ struct irq_data *d = &desc->irq_data;
+
+ if (d->node == cpu) {
+ unsigned int newcpu = cpumask_any_and(d->affinity,
cpu_online_mask);
if (newcpu >= nr_cpu_ids) {
if (printk_ratelimit())
printk(KERN_INFO "IRQ%u no longer affine to CPU%u\n",
i, cpu);
- cpumask_setall(desc->affinity);
- newcpu = cpumask_any_and(desc->affinity,
+ cpumask_setall(d->affinity);
+ newcpu = cpumask_any_and(d->affinity,
cpu_online_mask);
}
diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c
index e76fcaa..94bbedb 100644
--- a/arch/arm/kernel/process.c
+++ b/arch/arm/kernel/process.c
@@ -483,6 +483,7 @@ unsigned long arch_randomize_brk(struct mm_struct *mm)
return randomize_range(mm->brk, range_end, 0) ? : mm->brk;
}
+#ifdef CONFIG_MMU
/*
* The vectors page is always readable from user space for the
* atomic helpers and the signal restart code. Let's declare a mapping
@@ -503,3 +504,4 @@ const char *arch_vma_name(struct vm_area_struct *vma)
{
return (vma->vm_start == 0xffff0000) ? "[vectors]" : NULL;
}
+#endif
diff --git a/arch/arm/kernel/sched_clock.c b/arch/arm/kernel/sched_clock.c
index 2cdcc92..9a46370 100644
--- a/arch/arm/kernel/sched_clock.c
+++ b/arch/arm/kernel/sched_clock.c
@@ -34,7 +34,7 @@ void __init init_sched_clock(struct clock_data *cd, void (*update)(void),
sched_clock_update_fn = update;
/* calculate the mult/shift to convert counter ticks to ns. */
- clocks_calc_mult_shift(&cd->mult, &cd->shift, rate, NSEC_PER_SEC, 60);
+ clocks_calc_mult_shift(&cd->mult, &cd->shift, rate, NSEC_PER_SEC, 0);
r = rate;
if (r >= 4000000) {
@@ -60,10 +60,15 @@ void __init init_sched_clock(struct clock_data *cd, void (*update)(void),
* sets the initial epoch.
*/
sched_clock_timer.data = msecs_to_jiffies(w - (w / 10));
- sched_clock_poll(sched_clock_timer.data);
+ update();
/*
* Ensure that sched_clock() starts off at 0ns
*/
cd->epoch_ns = 0;
}
+
+void __init sched_clock_postinit(void)
+{
+ sched_clock_poll(sched_clock_timer.data);
+}
diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
index 3455ad3..420b8d6 100644
--- a/arch/arm/kernel/setup.c
+++ b/arch/arm/kernel/setup.c
@@ -518,25 +518,21 @@ setup_ramdisk(int doload, int prompt, int image_start, unsigned int rd_sz)
#endif
}
-static void __init
-request_standard_resources(struct meminfo *mi, struct machine_desc *mdesc)
+static void __init request_standard_resources(struct machine_desc *mdesc)
{
+ struct memblock_region *region;
struct resource *res;
- int i;
kernel_code.start = virt_to_phys(_text);
kernel_code.end = virt_to_phys(_etext - 1);
kernel_data.start = virt_to_phys(_sdata);
kernel_data.end = virt_to_phys(_end - 1);
- for (i = 0; i < mi->nr_banks; i++) {
- if (mi->bank[i].size == 0)
- continue;
-
+ for_each_memblock(memory, region) {
res = alloc_bootmem_low(sizeof(*res));
res->name = "System RAM";
- res->start = mi->bank[i].start;
- res->end = mi->bank[i].start + mi->bank[i].size - 1;
+ res->start = __pfn_to_phys(memblock_region_memory_base_pfn(region));
+ res->end = __pfn_to_phys(memblock_region_memory_end_pfn(region)) - 1;
res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
request_resource(&iomem_resource, res);
@@ -650,15 +646,17 @@ static int __init parse_tag_revision(const struct tag *tag)
__tagtable(ATAG_REVISION, parse_tag_revision);
-#ifndef CONFIG_CMDLINE_FORCE
static int __init parse_tag_cmdline(const struct tag *tag)
{
+#ifndef CONFIG_CMDLINE_FORCE
strlcpy(default_command_line, tag->u.cmdline.cmdline, COMMAND_LINE_SIZE);
+#else
+ pr_warning("Ignoring tag cmdline (using the default kernel command line)\n");
+#endif /* CONFIG_CMDLINE_FORCE */
return 0;
}
__tagtable(ATAG_CMDLINE, parse_tag_cmdline);
-#endif /* CONFIG_CMDLINE_FORCE */
/*
* Scan the tag table for this tag, and call its parse function.
@@ -857,7 +855,7 @@ void __init setup_arch(char **cmdline_p)
arm_memblock_init(&meminfo, mdesc);
paging_init(mdesc);
- request_standard_resources(&meminfo, mdesc);
+ request_standard_resources(mdesc);
#ifdef CONFIG_SMP
if (is_smp())
diff --git a/arch/arm/kernel/smp_twd.c b/arch/arm/kernel/smp_twd.c
index dd79074..fd91566 100644
--- a/arch/arm/kernel/smp_twd.c
+++ b/arch/arm/kernel/smp_twd.c
@@ -114,7 +114,7 @@ static void __cpuinit twd_calibrate_rate(void)
twd_timer_rate = (0xFFFFFFFFU - count) * (HZ / 5);
printk("%lu.%02luMHz.\n", twd_timer_rate / 1000000,
- (twd_timer_rate / 100000) % 100);
+ (twd_timer_rate / 1000000) % 100);
}
load = twd_timer_rate / HZ;
diff --git a/arch/arm/kernel/stacktrace.c b/arch/arm/kernel/stacktrace.c
index c2e112e..381d23a 100644
--- a/arch/arm/kernel/stacktrace.c
+++ b/arch/arm/kernel/stacktrace.c
@@ -94,10 +94,13 @@ void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace)
if (tsk != current) {
#ifdef CONFIG_SMP
/*
- * What guarantees do we have here that 'tsk'
- * is not running on another CPU?
+ * What guarantees do we have here that 'tsk' is not
+ * running on another CPU? For now, ignore it as we
+ * can't guarantee we won't explode.
*/
- BUG();
+ if (trace->nr_entries < trace->max_entries)
+ trace->entries[trace->nr_entries++] = ULONG_MAX;
+ return;
#else
data.no_sched_functions = 1;
frame.fp = thread_saved_fp(tsk);
diff --git a/arch/arm/kernel/time.c b/arch/arm/kernel/time.c
index f1e2eb1..3d76bf2 100644
--- a/arch/arm/kernel/time.c
+++ b/arch/arm/kernel/time.c
@@ -29,6 +29,7 @@
#include <asm/leds.h>
#include <asm/thread_info.h>
+#include <asm/sched_clock.h>
#include <asm/stacktrace.h>
#include <asm/mach/arch.h>
#include <asm/mach/time.h>
@@ -163,5 +164,8 @@ void __init time_init(void)
{
system_timer = machine_desc->timer;
system_timer->init();
+#ifdef CONFIG_HAVE_SCHED_CLOCK
+ sched_clock_postinit();
+#endif
}
diff --git a/arch/arm/lib/delay.S b/arch/arm/lib/delay.S
index 8d6a876..3c9a05c 100644
--- a/arch/arm/lib/delay.S
+++ b/arch/arm/lib/delay.S
@@ -25,11 +25,15 @@ ENTRY(__udelay)
ldr r2, .LC1
mul r0, r2, r0
ENTRY(__const_udelay) @ 0 <= r0 <= 0x7fffff06
+ mov r1, #-1
ldr r2, .LC0
ldr r2, [r2] @ max = 0x01ffffff
+ add r0, r0, r1, lsr #32-14
mov r0, r0, lsr #14 @ max = 0x0001ffff
+ add r2, r2, r1, lsr #32-10
mov r2, r2, lsr #10 @ max = 0x00007fff
mul r0, r2, r0 @ max = 2^32-1
+ add r0, r0, r1, lsr #32-6
movs r0, r0, lsr #6
moveq pc, lr
diff --git a/arch/arm/mach-aaec2000/core.c b/arch/arm/mach-aaec2000/core.c
index 3ef6833..f8465bd 100644
--- a/arch/arm/mach-aaec2000/core.c
+++ b/arch/arm/mach-aaec2000/core.c
@@ -68,25 +68,25 @@ void __init aaec2000_map_io(void)
/*
* Interrupt handling routines
*/
-static void aaec2000_int_ack(unsigned int irq)
+static void aaec2000_int_ack(struct irq_data *d)
{
- IRQ_INTSR = 1 << irq;
+ IRQ_INTSR = 1 << d->irq;
}
-static void aaec2000_int_mask(unsigned int irq)
+static void aaec2000_int_mask(struct irq_data *d)
{
- IRQ_INTENC |= (1 << irq);
+ IRQ_INTENC |= (1 << d->irq);
}
-static void aaec2000_int_unmask(unsigned int irq)
+static void aaec2000_int_unmask(struct irq_data *d)
{
- IRQ_INTENS |= (1 << irq);
+ IRQ_INTENS |= (1 << d->irq);
}
static struct irq_chip aaec2000_irq_chip = {
- .ack = aaec2000_int_ack,
- .mask = aaec2000_int_mask,
- .unmask = aaec2000_int_unmask,
+ .irq_ack = aaec2000_int_ack,
+ .irq_mask = aaec2000_int_mask,
+ .irq_unmask = aaec2000_int_unmask,
};
void __init aaec2000_init_irq(void)
diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig
index c015b68..1939023 100644
--- a/arch/arm/mach-at91/Kconfig
+++ b/arch/arm/mach-at91/Kconfig
@@ -362,6 +362,12 @@ config MACH_CPU9G20
Select this if you are using a Eukrea Electromatique's
CPU9G20 Board <http://www.eukrea.com/>
+config MACH_ACMENETUSFOXG20
+ bool "Acme Systems srl FOX Board G20"
+ help
+ Select this if you are using Acme Systems
+ FOX Board G20 <http://www.acmesystems.it>
+
config MACH_PORTUXG20
bool "taskit PortuxG20"
help
@@ -381,6 +387,13 @@ config MACH_PCONTROL_G20
Select this if you are using taskit's Stamp9G20 CPU module on this
carrier board, beeing the decentralized unit of a building automation
system; featuring nvram, eth-switch, iso-rs485, display, io
+
+config MACH_GSIA18S
+ bool "GS_IA18_S board"
+ help
+ This enables support for the GS_IA18_S board
+ produced by GeoSIG Ltd company. This is an internet accelerograph.
+ <http://www.geosig.com>
endif
if (ARCH_AT91SAM9260 || ARCH_AT91SAM9G20)
diff --git a/arch/arm/mach-at91/Makefile b/arch/arm/mach-at91/Makefile
index d13add7..a83835e 100644
--- a/arch/arm/mach-at91/Makefile
+++ b/arch/arm/mach-at91/Makefile
@@ -63,9 +63,11 @@ obj-$(CONFIG_MACH_AT91SAM9RLEK) += board-sam9rlek.o
# AT91SAM9G20 board-specific support
obj-$(CONFIG_MACH_AT91SAM9G20EK) += board-sam9g20ek.o
obj-$(CONFIG_MACH_CPU9G20) += board-cpu9krea.o
+obj-$(CONFIG_MACH_ACMENETUSFOXG20) += board-foxg20.o
obj-$(CONFIG_MACH_STAMP9G20) += board-stamp9g20.o
obj-$(CONFIG_MACH_PORTUXG20) += board-stamp9g20.o
obj-$(CONFIG_MACH_PCONTROL_G20) += board-pcontrol-g20.o board-stamp9g20.o
+obj-$(CONFIG_MACH_GSIA18S) += board-gsia18s.o board-stamp9g20.o
# AT91SAM9260/AT91SAM9G20 board-specific support
obj-$(CONFIG_MACH_SNAPPER_9260) += board-snapper9260.o
diff --git a/arch/arm/mach-at91/board-foxg20.c b/arch/arm/mach-at91/board-foxg20.c
new file mode 100644
index 0000000..dfc7dfe
--- /dev/null
+++ b/arch/arm/mach-at91/board-foxg20.c
@@ -0,0 +1,274 @@
+/*
+ * Copyright (C) 2005 SAN People
+ * Copyright (C) 2008 Atmel
+ * Copyright (C) 2010 Lee McLoughlin - lee@lmmrtech.com
+ * Copyright (C) 2010 Sergio Tanzilli - tanzilli@acmesystems.it
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/at73c213.h>
+#include <linux/gpio.h>
+#include <linux/gpio_keys.h>
+#include <linux/input.h>
+#include <linux/clk.h>
+#include <linux/w1-gpio.h>
+
+#include <mach/hardware.h>
+#include <asm/setup.h>
+#include <asm/mach-types.h>
+#include <asm/irq.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+
+#include <mach/board.h>
+#include <mach/at91sam9_smc.h>
+
+#include "sam9_smc.h"
+#include "generic.h"
+
+/*
+ * The FOX Board G20 hardware comes as the "Netus G20" board with
+ * just the cpu, ram, dataflash and two header connectors.
+ * This is plugged into the FOX Board which provides the ethernet,
+ * usb, rtc, leds, switch, ...
+ *
+ * For more info visit: http://www.acmesystems.it/foxg20
+ */
+
+
+static void __init foxg20_map_io(void)
+{
+ /* Initialize processor: 18.432 MHz crystal */
+ at91sam9260_initialize(18432000);
+
+ /* DBGU on ttyS0. (Rx & Tx only) */
+ at91_register_uart(0, 0, 0);
+
+ /* USART0 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
+ at91_register_uart(AT91SAM9260_ID_US0, 1,
+ ATMEL_UART_CTS
+ | ATMEL_UART_RTS
+ | ATMEL_UART_DTR
+ | ATMEL_UART_DSR
+ | ATMEL_UART_DCD
+ | ATMEL_UART_RI);
+
+ /* USART1 on ttyS2. (Rx, Tx, RTS, CTS) */
+ at91_register_uart(AT91SAM9260_ID_US1, 2,
+ ATMEL_UART_CTS
+ | ATMEL_UART_RTS);
+
+ /* USART2 on ttyS3. (Rx & Tx only) */
+ at91_register_uart(AT91SAM9260_ID_US2, 3, 0);
+
+ /* USART3 on ttyS4. (Rx, Tx, RTS, CTS) */
+ at91_register_uart(AT91SAM9260_ID_US3, 4,
+ ATMEL_UART_CTS
+ | ATMEL_UART_RTS);
+
+ /* USART4 on ttyS5. (Rx & Tx only) */
+ at91_register_uart(AT91SAM9260_ID_US4, 5, 0);
+
+ /* USART5 on ttyS6. (Rx & Tx only) */
+ at91_register_uart(AT91SAM9260_ID_US5, 6, 0);
+
+ /* set serial console to ttyS0 (ie, DBGU) */
+ at91_set_serial_console(0);
+
+ /* Set the internal pull-up resistor on DRXD */
+ at91_set_A_periph(AT91_PIN_PB14, 1);
+
+}
+
+static void __init foxg20_init_irq(void)
+{
+ at91sam9260_init_interrupts(NULL);
+}
+
+
+/*
+ * USB Host port
+ */
+static struct at91_usbh_data __initdata foxg20_usbh_data = {
+ .ports = 2,
+};
+
+/*
+ * USB Device port
+ */
+static struct at91_udc_data __initdata foxg20_udc_data = {
+ .vbus_pin = AT91_PIN_PC6,
+ .pullup_pin = 0, /* pull-up driven by UDC */
+};
+
+
+/*
+ * SPI devices.
+ */
+static struct spi_board_info foxg20_spi_devices[] = {
+#if !defined(CONFIG_MMC_AT91)
+ {
+ .modalias = "mtd_dataflash",
+ .chip_select = 1,
+ .max_speed_hz = 15 * 1000 * 1000,
+ .bus_num = 0,
+ },
+#endif
+};
+
+
+/*
+ * MACB Ethernet device
+ */
+static struct at91_eth_data __initdata foxg20_macb_data = {
+ .phy_irq_pin = AT91_PIN_PA7,
+ .is_rmii = 1,
+};
+
+/*
+ * MCI (SD/MMC)
+ * det_pin, wp_pin and vcc_pin are not connected
+ */
+static struct at91_mmc_data __initdata foxg20_mmc_data = {
+ .slot_b = 1,
+ .wire4 = 1,
+};
+
+
+/*
+ * LEDs
+ */
+static struct gpio_led foxg20_leds[] = {
+ { /* user led, red */
+ .name = "user_led",
+ .gpio = AT91_PIN_PC7,
+ .active_low = 0,
+ .default_trigger = "heartbeat",
+ },
+};
+
+
+/*
+ * GPIO Buttons
+ */
+#if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE)
+static struct gpio_keys_button foxg20_buttons[] = {
+ {
+ .gpio = AT91_PIN_PC4,
+ .code = BTN_1,
+ .desc = "Button 1",
+ .active_low = 1,
+ .wakeup = 1,
+ },
+};
+
+static struct gpio_keys_platform_data foxg20_button_data = {
+ .buttons = foxg20_buttons,
+ .nbuttons = ARRAY_SIZE(foxg20_buttons),
+};
+
+static struct platform_device foxg20_button_device = {
+ .name = "gpio-keys",
+ .id = -1,
+ .num_resources = 0,
+ .dev = {
+ .platform_data = &foxg20_button_data,
+ }
+};
+
+static void __init foxg20_add_device_buttons(void)
+{
+ at91_set_gpio_input(AT91_PIN_PC4, 1); /* btn1 */
+ at91_set_deglitch(AT91_PIN_PC4, 1);
+
+ platform_device_register(&foxg20_button_device);
+}
+#else
+static void __init foxg20_add_device_buttons(void) {}
+#endif
+
+
+#if defined(CONFIG_W1_MASTER_GPIO) || defined(CONFIG_W1_MASTER_GPIO_MODULE)
+static struct w1_gpio_platform_data w1_gpio_pdata = {
+ /* If you choose to use a pin other than PB16 it needs to be 3.3V */
+ .pin = AT91_PIN_PB16,
+ .is_open_drain = 1,
+};
+
+static struct platform_device w1_device = {
+ .name = "w1-gpio",
+ .id = -1,
+ .dev.platform_data = &w1_gpio_pdata,
+};
+
+static void __init at91_add_device_w1(void)
+{
+ at91_set_GPIO_periph(w1_gpio_pdata.pin, 1);
+ at91_set_multi_drive(w1_gpio_pdata.pin, 1);
+ platform_device_register(&w1_device);
+}
+
+#endif
+
+
+static struct i2c_board_info __initdata foxg20_i2c_devices[] = {
+ {
+ I2C_BOARD_INFO("24c512", 0x50),
+ },
+};
+
+
+static void __init foxg20_board_init(void)
+{
+ /* Serial */
+ at91_add_device_serial();
+ /* USB Host */
+ at91_add_device_usbh(&foxg20_usbh_data);
+ /* USB Device */
+ at91_add_device_udc(&foxg20_udc_data);
+ /* SPI */
+ at91_add_device_spi(foxg20_spi_devices, ARRAY_SIZE(foxg20_spi_devices));
+ /* Ethernet */
+ at91_add_device_eth(&foxg20_macb_data);
+ /* MMC */
+ at91_add_device_mmc(0, &foxg20_mmc_data);
+ /* I2C */
+ at91_add_device_i2c(foxg20_i2c_devices, ARRAY_SIZE(foxg20_i2c_devices));
+ /* LEDs */
+ at91_gpio_leds(foxg20_leds, ARRAY_SIZE(foxg20_leds));
+ /* Push Buttons */
+ foxg20_add_device_buttons();
+#if defined(CONFIG_W1_MASTER_GPIO) || defined(CONFIG_W1_MASTER_GPIO_MODULE)
+ at91_add_device_w1();
+#endif
+}
+
+MACHINE_START(ACMENETUSFOXG20, "Acme Systems srl FOX Board G20")
+ /* Maintainer: Sergio Tanzilli */
+ .boot_params = AT91_SDRAM_BASE + 0x100,
+ .timer = &at91sam926x_timer,
+ .map_io = foxg20_map_io,
+ .init_irq = foxg20_init_irq,
+ .init_machine = foxg20_board_init,
+MACHINE_END
diff --git a/arch/arm/mach-at91/board-gsia18s.c b/arch/arm/mach-at91/board-gsia18s.c
new file mode 100644
index 0000000..bc28136
--- /dev/null
+++ b/arch/arm/mach-at91/board-gsia18s.c
@@ -0,0 +1,584 @@
+/*
+ * Copyright (C) 2010 Christian Glindkamp <christian.glindkamp@taskit.de>
+ * taskit GmbH
+ * 2010 Igor Plyatov <plyatov@gmail.com>
+ * GeoSIG Ltd
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/w1-gpio.h>
+#include <linux/i2c.h>
+#include <linux/i2c/pcf857x.h>
+#include <linux/gpio_keys.h>
+#include <linux/input.h>
+
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+
+#include <mach/board.h>
+#include <mach/at91sam9_smc.h>
+#include <mach/gsia18s.h>
+#include <mach/stamp9g20.h>
+
+#include "sam9_smc.h"
+#include "generic.h"
+
+static void __init gsia18s_map_io(void)
+{
+ stamp9g20_map_io();
+
+ /*
+ * USART0 on ttyS1 (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI).
+ * Used for Internal Analog Modem.
+ */
+ at91_register_uart(AT91SAM9260_ID_US0, 1,
+ ATMEL_UART_CTS | ATMEL_UART_RTS |
+ ATMEL_UART_DTR | ATMEL_UART_DSR |
+ ATMEL_UART_DCD | ATMEL_UART_RI);
+ /*
+ * USART1 on ttyS2 (Rx, Tx, CTS, RTS).
+ * Used for GPS or WiFi or Data stream.
+ */
+ at91_register_uart(AT91SAM9260_ID_US1, 2,
+ ATMEL_UART_CTS | ATMEL_UART_RTS);
+ /*
+ * USART2 on ttyS3 (Rx, Tx, CTS, RTS).
+ * Used for External Modem.
+ */
+ at91_register_uart(AT91SAM9260_ID_US2, 3,
+ ATMEL_UART_CTS | ATMEL_UART_RTS);
+ /*
+ * USART3 on ttyS4 (Rx, Tx, RTS).
+ * Used for RS-485.
+ */
+ at91_register_uart(AT91SAM9260_ID_US3, 4, ATMEL_UART_RTS);
+
+ /*
+ * USART4 on ttyS5 (Rx, Tx).
+ * Used for TRX433 Radio Module.
+ */
+ at91_register_uart(AT91SAM9260_ID_US4, 5, 0);
+}
+
+static void __init init_irq(void)
+{
+ at91sam9260_init_interrupts(NULL);
+}
+
+/*
+ * Two USB Host ports
+ */
+static struct at91_usbh_data __initdata usbh_data = {
+ .ports = 2,
+};
+
+/*
+ * USB Device port
+ */
+static struct at91_udc_data __initdata udc_data = {
+ .vbus_pin = AT91_PIN_PA22,
+ .pullup_pin = 0, /* pull-up driven by UDC */
+};
+
+/*
+ * MACB Ethernet device
+ */
+static struct at91_eth_data __initdata macb_data = {
+ .phy_irq_pin = AT91_PIN_PA28,
+ .is_rmii = 1,
+};
+
+/*
+ * LEDs and GPOs
+ */
+static struct gpio_led gpio_leds[] = {
+ {
+ .name = "gpo:spi1reset",
+ .gpio = AT91_PIN_PC1,
+ .active_low = 0,
+ .default_trigger = "none",
+ .default_state = LEDS_GPIO_DEFSTATE_OFF,
+ },
+ {
+ .name = "gpo:trig_net_out",
+ .gpio = AT91_PIN_PB20,
+ .active_low = 0,
+ .default_trigger = "none",
+ .default_state = LEDS_GPIO_DEFSTATE_OFF,
+ },
+ {
+ .name = "gpo:trig_net_dir",
+ .gpio = AT91_PIN_PB19,
+ .active_low = 0,
+ .default_trigger = "none",
+ .default_state = LEDS_GPIO_DEFSTATE_OFF,
+ },
+ {
+ .name = "gpo:charge_dis",
+ .gpio = AT91_PIN_PC2,
+ .active_low = 0,
+ .default_trigger = "none",
+ .default_state = LEDS_GPIO_DEFSTATE_OFF,
+ },
+ {
+ .name = "led:event",
+ .gpio = AT91_PIN_PB17,
+ .active_low = 1,
+ .default_trigger = "none",
+ .default_state = LEDS_GPIO_DEFSTATE_OFF,
+ },
+ {
+ .name = "led:lan",
+ .gpio = AT91_PIN_PB18,
+ .active_low = 1,
+ .default_trigger = "none",
+ .default_state = LEDS_GPIO_DEFSTATE_OFF,
+ },
+ {
+ .name = "led:error",
+ .gpio = AT91_PIN_PB16,
+ .active_low = 1,
+ .default_trigger = "none",
+ .default_state = LEDS_GPIO_DEFSTATE_ON,
+ }
+};
+
+static struct gpio_led_platform_data gpio_led_info = {
+ .leds = gpio_leds,
+ .num_leds = ARRAY_SIZE(gpio_leds),
+};
+
+static struct platform_device leds = {
+ .name = "leds-gpio",
+ .id = 0,
+ .dev = {
+ .platform_data = &gpio_led_info,
+ }
+};
+
+static void __init gsia18s_leds_init(void)
+{
+ platform_device_register(&leds);
+}
+
+/* PCF8574 0x20 GPIO - U1 on the GS_IA18-CB_V3 board */
+static struct gpio_led pcf_gpio_leds1[] = {
+ { /* bit 0 */
+ .name = "gpo:hdc_power",
+ .gpio = PCF_GPIO_HDC_POWER,
+ .active_low = 0,
+ .default_trigger = "none",
+ .default_state = LEDS_GPIO_DEFSTATE_OFF,
+ },
+ { /* bit 1 */
+ .name = "gpo:wifi_setup",
+ .gpio = PCF_GPIO_WIFI_SETUP,
+ .active_low = 1,
+ .default_trigger = "none",
+ .default_state = LEDS_GPIO_DEFSTATE_OFF,
+ },
+ { /* bit 2 */
+ .name = "gpo:wifi_enable",
+ .gpio = PCF_GPIO_WIFI_ENABLE,
+ .active_low = 1,
+ .default_trigger = "none",
+ .default_state = LEDS_GPIO_DEFSTATE_OFF,
+ },
+ { /* bit 3 */
+ .name = "gpo:wifi_reset",
+ .gpio = PCF_GPIO_WIFI_RESET,
+ .active_low = 1,
+ .default_trigger = "none",
+ .default_state = LEDS_GPIO_DEFSTATE_ON,
+ },
+ /* bit 4 used as GPI */
+ { /* bit 5 */
+ .name = "gpo:gps_setup",
+ .gpio = PCF_GPIO_GPS_SETUP,
+ .active_low = 1,
+ .default_trigger = "none",
+ .default_state = LEDS_GPIO_DEFSTATE_OFF,
+ },
+ { /* bit 6 */
+ .name = "gpo:gps_standby",
+ .gpio = PCF_GPIO_GPS_STANDBY,
+ .active_low = 0,
+ .default_trigger = "none",
+ .default_state = LEDS_GPIO_DEFSTATE_ON,
+ },
+ { /* bit 7 */
+ .name = "gpo:gps_power",
+ .gpio = PCF_GPIO_GPS_POWER,
+ .active_low = 0,
+ .default_trigger = "none",
+ .default_state = LEDS_GPIO_DEFSTATE_OFF,
+ }
+};
+
+static struct gpio_led_platform_data pcf_gpio_led_info1 = {
+ .leds = pcf_gpio_leds1,
+ .num_leds = ARRAY_SIZE(pcf_gpio_leds1),
+};
+
+static struct platform_device pcf_leds1 = {
+ .name = "leds-gpio", /* GS_IA18-CB_board */
+ .id = 1,
+ .dev = {
+ .platform_data = &pcf_gpio_led_info1,
+ }
+};
+
+/* PCF8574 0x22 GPIO - U1 on the GS_2G_OPT1-A_V0 board (Alarm) */
+static struct gpio_led pcf_gpio_leds2[] = {
+ { /* bit 0 */
+ .name = "gpo:alarm_1",
+ .gpio = PCF_GPIO_ALARM1,
+ .active_low = 1,
+ .default_trigger = "none",
+ .default_state = LEDS_GPIO_DEFSTATE_OFF,
+ },
+ { /* bit 1 */
+ .name = "gpo:alarm_2",
+ .gpio = PCF_GPIO_ALARM2,
+ .active_low = 1,
+ .default_trigger = "none",
+ .default_state = LEDS_GPIO_DEFSTATE_OFF,
+ },
+ { /* bit 2 */
+ .name = "gpo:alarm_3",
+ .gpio = PCF_GPIO_ALARM3,
+ .active_low = 1,
+ .default_trigger = "none",
+ .default_state = LEDS_GPIO_DEFSTATE_OFF,
+ },
+ { /* bit 3 */
+ .name = "gpo:alarm_4",
+ .gpio = PCF_GPIO_ALARM4,
+ .active_low = 1,
+ .default_trigger = "none",
+ .default_state = LEDS_GPIO_DEFSTATE_OFF,
+ },
+ /* bits 4, 5, 6 not used */
+ { /* bit 7 */
+ .name = "gpo:alarm_v_relay_on",
+ .gpio = PCF_GPIO_ALARM_V_RELAY_ON,
+ .active_low = 0,
+ .default_trigger = "none",
+ .default_state = LEDS_GPIO_DEFSTATE_OFF,
+ },
+};
+
+static struct gpio_led_platform_data pcf_gpio_led_info2 = {
+ .leds = pcf_gpio_leds2,
+ .num_leds = ARRAY_SIZE(pcf_gpio_leds2),
+};
+
+static struct platform_device pcf_leds2 = {
+ .name = "leds-gpio",
+ .id = 2,
+ .dev = {
+ .platform_data = &pcf_gpio_led_info2,
+ }
+};
+
+/* PCF8574 0x24 GPIO U1 on the GS_2G-OPT23-A_V0 board (Modem) */
+static struct gpio_led pcf_gpio_leds3[] = {
+ { /* bit 0 */
+ .name = "gpo:modem_power",
+ .gpio = PCF_GPIO_MODEM_POWER,
+ .active_low = 1,
+ .default_trigger = "none",
+ .default_state = LEDS_GPIO_DEFSTATE_OFF,
+ },
+ /* bits 1 and 2 not used */
+ { /* bit 3 */
+ .name = "gpo:modem_reset",
+ .gpio = PCF_GPIO_MODEM_RESET,
+ .active_low = 1,
+ .default_trigger = "none",
+ .default_state = LEDS_GPIO_DEFSTATE_ON,
+ },
+ /* bits 4, 5 and 6 not used */
+ { /* bit 7 */
+ .name = "gpo:trx_reset",
+ .gpio = PCF_GPIO_TRX_RESET,
+ .active_low = 1,
+ .default_trigger = "none",
+ .default_state = LEDS_GPIO_DEFSTATE_ON,
+ }
+};
+
+static struct gpio_led_platform_data pcf_gpio_led_info3 = {
+ .leds = pcf_gpio_leds3,
+ .num_leds = ARRAY_SIZE(pcf_gpio_leds3),
+};
+
+static struct platform_device pcf_leds3 = {
+ .name = "leds-gpio",
+ .id = 3,
+ .dev = {
+ .platform_data = &pcf_gpio_led_info3,
+ }
+};
+
+static void __init gsia18s_pcf_leds_init(void)
+{
+ platform_device_register(&pcf_leds1);
+ platform_device_register(&pcf_leds2);
+ platform_device_register(&pcf_leds3);
+}
+
+/*
+ * SPI busses.
+ */
+static struct spi_board_info gsia18s_spi_devices[] = {
+ { /* User accessible spi0, cs0 used for communication with MSP RTC */
+ .modalias = "spidev",
+ .bus_num = 0,
+ .chip_select = 0,
+ .max_speed_hz = 580000,
+ .mode = SPI_MODE_1,
+ },
+ { /* User accessible spi1, cs0 used for communication with int. DSP */
+ .modalias = "spidev",
+ .bus_num = 1,
+ .chip_select = 0,
+ .max_speed_hz = 5600000,
+ .mode = SPI_MODE_0,
+ },
+ { /* User accessible spi1, cs1 used for communication with ext. DSP */
+ .modalias = "spidev",
+ .bus_num = 1,
+ .chip_select = 1,
+ .max_speed_hz = 5600000,
+ .mode = SPI_MODE_0,
+ },
+ { /* User accessible spi1, cs2 used for communication with ext. DSP */
+ .modalias = "spidev",
+ .bus_num = 1,
+ .chip_select = 2,
+ .max_speed_hz = 5600000,
+ .mode = SPI_MODE_0,
+ },
+ { /* User accessible spi1, cs3 used for communication with ext. DSP */
+ .modalias = "spidev",
+ .bus_num = 1,
+ .chip_select = 3,
+ .max_speed_hz = 5600000,
+ .mode = SPI_MODE_0,
+ }
+};
+
+/*
+ * GPI Buttons
+ */
+static struct gpio_keys_button buttons[] = {
+ {
+ .gpio = GPIO_TRIG_NET_IN,
+ .code = BTN_1,
+ .desc = "TRIG_NET_IN",
+ .type = EV_KEY,
+ .active_low = 0,
+ .wakeup = 1,
+ },
+ { /* SW80 on the GS_IA18_S-MN board*/
+ .gpio = GPIO_CARD_UNMOUNT_0,
+ .code = BTN_2,
+ .desc = "Card umount 0",
+ .type = EV_KEY,
+ .active_low = 1,
+ .wakeup = 1,
+ },
+ { /* SW79 on the GS_IA18_S-MN board*/
+ .gpio = GPIO_CARD_UNMOUNT_1,
+ .code = BTN_3,
+ .desc = "Card umount 1",
+ .type = EV_KEY,
+ .active_low = 1,
+ .wakeup = 1,
+ },
+ { /* SW280 on the GS_IA18-CB board*/
+ .gpio = GPIO_KEY_POWER,
+ .code = KEY_POWER,
+ .desc = "Power Off Button",
+ .type = EV_KEY,
+ .active_low = 0,
+ .wakeup = 1,
+ }
+};
+
+static struct gpio_keys_platform_data button_data = {
+ .buttons = buttons,
+ .nbuttons = ARRAY_SIZE(buttons),
+};
+
+static struct platform_device button_device = {
+ .name = "gpio-keys",
+ .id = -1,
+ .num_resources = 0,
+ .dev = {
+ .platform_data = &button_data,
+ }
+};
+
+static void __init gsia18s_add_device_buttons(void)
+{
+ at91_set_gpio_input(GPIO_TRIG_NET_IN, 1);
+ at91_set_deglitch(GPIO_TRIG_NET_IN, 1);
+ at91_set_gpio_input(GPIO_CARD_UNMOUNT_0, 1);
+ at91_set_deglitch(GPIO_CARD_UNMOUNT_0, 1);
+ at91_set_gpio_input(GPIO_CARD_UNMOUNT_1, 1);
+ at91_set_deglitch(GPIO_CARD_UNMOUNT_1, 1);
+ at91_set_gpio_input(GPIO_KEY_POWER, 0);
+ at91_set_deglitch(GPIO_KEY_POWER, 1);
+
+ platform_device_register(&button_device);
+}
+
+/*
+ * I2C
+ */
+static int pcf8574x_0x20_setup(struct i2c_client *client, int gpio,
+ unsigned int ngpio, void *context)
+{
+ int status;
+
+ status = gpio_request(gpio + PCF_GPIO_ETH_DETECT, "eth_det");
+ if (status < 0) {
+ pr_err("error: can't request GPIO%d\n",
+ gpio + PCF_GPIO_ETH_DETECT);
+ return status;
+ }
+ status = gpio_direction_input(gpio + PCF_GPIO_ETH_DETECT);
+ if (status < 0) {
+ pr_err("error: can't setup GPIO%d as input\n",
+ gpio + PCF_GPIO_ETH_DETECT);
+ return status;
+ }
+ status = gpio_export(gpio + PCF_GPIO_ETH_DETECT, false);
+ if (status < 0) {
+ pr_err("error: can't export GPIO%d\n",
+ gpio + PCF_GPIO_ETH_DETECT);
+ return status;
+ }
+ status = gpio_sysfs_set_active_low(gpio + PCF_GPIO_ETH_DETECT, 1);
+ if (status < 0) {
+ pr_err("error: gpio_sysfs_set active_low(GPIO%d, 1)\n",
+ gpio + PCF_GPIO_ETH_DETECT);
+ return status;
+ }
+
+ return 0;
+}
+
+static int pcf8574x_0x20_teardown(struct i2c_client *client, int gpio,
+ unsigned ngpio, void *context)
+{
+ gpio_free(gpio + PCF_GPIO_ETH_DETECT);
+ return 0;
+}
+
+static struct pcf857x_platform_data pcf20_pdata = {
+ .gpio_base = GS_IA18_S_PCF_GPIO_BASE0,
+ .n_latch = (1 << 4),
+ .setup = pcf8574x_0x20_setup,
+ .teardown = pcf8574x_0x20_teardown,
+};
+
+static struct pcf857x_platform_data pcf22_pdata = {
+ .gpio_base = GS_IA18_S_PCF_GPIO_BASE1,
+};
+
+static struct pcf857x_platform_data pcf24_pdata = {
+ .gpio_base = GS_IA18_S_PCF_GPIO_BASE2,
+};
+
+static struct i2c_board_info __initdata gsia18s_i2c_devices[] = {
+ { /* U1 on the GS_IA18-CB_V3 board */
+ I2C_BOARD_INFO("pcf8574", 0x20),
+ .platform_data = &pcf20_pdata,
+ },
+ { /* U1 on the GS_2G_OPT1-A_V0 board (Alarm) */
+ I2C_BOARD_INFO("pcf8574", 0x22),
+ .platform_data = &pcf22_pdata,
+ },
+ { /* U1 on the GS_2G-OPT23-A_V0 board (Modem) */
+ I2C_BOARD_INFO("pcf8574", 0x24),
+ .platform_data = &pcf24_pdata,
+ },
+ { /* U161 on the GS_IA18_S-MN board */
+ I2C_BOARD_INFO("24c1024", 0x50),
+ },
+ { /* U162 on the GS_IA18_S-MN board */
+ I2C_BOARD_INFO("24c01", 0x53),
+ },
+};
+
+/*
+ * Compact Flash
+ */
+static struct at91_cf_data __initdata gsia18s_cf1_data = {
+ .irq_pin = AT91_PIN_PA27,
+ .det_pin = AT91_PIN_PB30,
+ .rst_pin = AT91_PIN_PB31,
+ .chipselect = 5,
+ .flags = AT91_CF_TRUE_IDE,
+};
+
+/* Power Off by RTC */
+static void gsia18s_power_off(void)
+{
+ pr_notice("Power supply will be switched off automatically now or after 60 seconds without ArmDAS.\n");
+ at91_set_gpio_output(AT91_PIN_PA25, 1);
+ /* Spin to death... */
+ while (1)
+ ;
+}
+
+static int __init gsia18s_power_off_init(void)
+{
+ pm_power_off = gsia18s_power_off;
+ return 0;
+}
+
+/* ---------------------------------------------------------------------------*/
+
+static void __init gsia18s_board_init(void)
+{
+ stamp9g20_board_init();
+ at91_add_device_usbh(&usbh_data);
+ at91_add_device_udc(&udc_data);
+ at91_add_device_eth(&macb_data);
+ gsia18s_leds_init();
+ gsia18s_pcf_leds_init();
+ gsia18s_add_device_buttons();
+ at91_add_device_i2c(gsia18s_i2c_devices,
+ ARRAY_SIZE(gsia18s_i2c_devices));
+ at91_add_device_cf(&gsia18s_cf1_data);
+ at91_add_device_spi(gsia18s_spi_devices,
+ ARRAY_SIZE(gsia18s_spi_devices));
+ gsia18s_power_off_init();
+}
+
+MACHINE_START(GSIA18S, "GS_IA18_S")
+ .boot_params = AT91_SDRAM_BASE + 0x100,
+ .timer = &at91sam926x_timer,
+ .map_io = gsia18s_map_io,
+ .init_irq = init_irq,
+ .init_machine = gsia18s_board_init,
+MACHINE_END
diff --git a/arch/arm/mach-at91/board-sam9m10g45ek.c b/arch/arm/mach-at91/board-sam9m10g45ek.c
index 86ff4b5..6c999db 100644
--- a/arch/arm/mach-at91/board-sam9m10g45ek.c
+++ b/arch/arm/mach-at91/board-sam9m10g45ek.c
@@ -37,7 +37,6 @@
#include <asm/mach/map.h>
#include <asm/mach/irq.h>
-#include <mach/hardware.h>
#include <mach/board.h>
#include <mach/gpio.h>
#include <mach/at91sam9_smc.h>
diff --git a/arch/arm/mach-at91/gpio.c b/arch/arm/mach-at91/gpio.c
index ae4772e..af818a2 100644
--- a/arch/arm/mach-at91/gpio.c
+++ b/arch/arm/mach-at91/gpio.c
@@ -274,10 +274,10 @@ EXPORT_SYMBOL(at91_get_gpio_value);
static u32 wakeups[MAX_GPIO_BANKS];
static u32 backups[MAX_GPIO_BANKS];
-static int gpio_irq_set_wake(unsigned pin, unsigned state)
+static int gpio_irq_set_wake(struct irq_data *d, unsigned state)
{
- unsigned mask = pin_to_mask(pin);
- unsigned bank = (pin - PIN_BASE) / 32;
+ unsigned mask = pin_to_mask(d->irq);
+ unsigned bank = (d->irq - PIN_BASE) / 32;
if (unlikely(bank >= MAX_GPIO_BANKS))
return -EINVAL;
@@ -344,25 +344,25 @@ void at91_gpio_resume(void)
* IRQ0..IRQ6 should be configurable, e.g. level vs edge triggering.
*/
-static void gpio_irq_mask(unsigned pin)
+static void gpio_irq_mask(struct irq_data *d)
{
- void __iomem *pio = pin_to_controller(pin);
- unsigned mask = pin_to_mask(pin);
+ void __iomem *pio = pin_to_controller(d->irq);
+ unsigned mask = pin_to_mask(d->irq);
if (pio)
__raw_writel(mask, pio + PIO_IDR);
}
-static void gpio_irq_unmask(unsigned pin)
+static void gpio_irq_unmask(struct irq_data *d)
{
- void __iomem *pio = pin_to_controller(pin);
- unsigned mask = pin_to_mask(pin);
+ void __iomem *pio = pin_to_controller(d->irq);
+ unsigned mask = pin_to_mask(d->irq);
if (pio)
__raw_writel(mask, pio + PIO_IER);
}
-static int gpio_irq_type(unsigned pin, unsigned type)
+static int gpio_irq_type(struct irq_data *d, unsigned type)
{
switch (type) {
case IRQ_TYPE_NONE:
@@ -375,10 +375,10 @@ static int gpio_irq_type(unsigned pin, unsigned type)
static struct irq_chip gpio_irqchip = {
.name = "GPIO",
- .mask = gpio_irq_mask,
- .unmask = gpio_irq_unmask,
- .set_type = gpio_irq_type,
- .set_wake = gpio_irq_set_wake,
+ .irq_mask = gpio_irq_mask,
+ .irq_unmask = gpio_irq_unmask,
+ .irq_set_type = gpio_irq_type,
+ .irq_set_wake = gpio_irq_set_wake,
};
static void gpio_irq_handler(unsigned irq, struct irq_desc *desc)
@@ -393,7 +393,7 @@ static void gpio_irq_handler(unsigned irq, struct irq_desc *desc)
pio = at91_gpio->regbase;
/* temporarily mask (level sensitive) parent IRQ */
- desc->chip->ack(irq);
+ desc->irq_data.chip->irq_ack(&desc->irq_data);
for (;;) {
/* Reading ISR acks pending (edge triggered) GPIO interrupts.
* When there none are pending, we're finished unless we need
@@ -419,7 +419,7 @@ static void gpio_irq_handler(unsigned irq, struct irq_desc *desc)
* another IRQ must be generated before it actually gets
* here to be disabled on the GPIO controller.
*/
- gpio_irq_mask(pin);
+ gpio_irq_mask(irq_get_irq_data(pin));
}
else
generic_handle_irq(pin);
@@ -429,7 +429,7 @@ static void gpio_irq_handler(unsigned irq, struct irq_desc *desc)
isr >>= 1;
}
}
- desc->chip->unmask(irq);
+ desc->irq_data.chip->irq_unmask(&desc->irq_data);
/* now it may re-trigger */
}
diff --git a/arch/arm/mach-at91/include/mach/gsia18s.h b/arch/arm/mach-at91/include/mach/gsia18s.h
new file mode 100644
index 0000000..307c194
--- /dev/null
+++ b/arch/arm/mach-at91/include/mach/gsia18s.h
@@ -0,0 +1,33 @@
+/* Buttons */
+#define GPIO_TRIG_NET_IN AT91_PIN_PB21
+#define GPIO_CARD_UNMOUNT_0 AT91_PIN_PB13
+#define GPIO_CARD_UNMOUNT_1 AT91_PIN_PB12
+#define GPIO_KEY_POWER AT91_PIN_PA25
+
+/* PCF8574 0x20 GPIO - U1 on the GS_IA18-CB_V3 board */
+#define GS_IA18_S_PCF_GPIO_BASE0 NR_BUILTIN_GPIO
+#define PCF_GPIO_HDC_POWER (GS_IA18_S_PCF_GPIO_BASE0 + 0)
+#define PCF_GPIO_WIFI_SETUP (GS_IA18_S_PCF_GPIO_BASE0 + 1)
+#define PCF_GPIO_WIFI_ENABLE (GS_IA18_S_PCF_GPIO_BASE0 + 2)
+#define PCF_GPIO_WIFI_RESET (GS_IA18_S_PCF_GPIO_BASE0 + 3)
+#define PCF_GPIO_ETH_DETECT 4 /* this is a GPI */
+#define PCF_GPIO_GPS_SETUP (GS_IA18_S_PCF_GPIO_BASE0 + 5)
+#define PCF_GPIO_GPS_STANDBY (GS_IA18_S_PCF_GPIO_BASE0 + 6)
+#define PCF_GPIO_GPS_POWER (GS_IA18_S_PCF_GPIO_BASE0 + 7)
+
+/* PCF8574 0x22 GPIO - U1 on the GS_2G_OPT1-A_V0 board (Alarm) */
+#define GS_IA18_S_PCF_GPIO_BASE1 (GS_IA18_S_PCF_GPIO_BASE0 + 8)
+#define PCF_GPIO_ALARM1 (GS_IA18_S_PCF_GPIO_BASE1 + 0)
+#define PCF_GPIO_ALARM2 (GS_IA18_S_PCF_GPIO_BASE1 + 1)
+#define PCF_GPIO_ALARM3 (GS_IA18_S_PCF_GPIO_BASE1 + 2)
+#define PCF_GPIO_ALARM4 (GS_IA18_S_PCF_GPIO_BASE1 + 3)
+/* bits 4, 5, 6 not used */
+#define PCF_GPIO_ALARM_V_RELAY_ON (GS_IA18_S_PCF_GPIO_BASE1 + 7)
+
+/* PCF8574 0x24 GPIO U1 on the GS_2G-OPT23-A_V0 board (Modem) */
+#define GS_IA18_S_PCF_GPIO_BASE2 (GS_IA18_S_PCF_GPIO_BASE1 + 8)
+#define PCF_GPIO_MODEM_POWER (GS_IA18_S_PCF_GPIO_BASE2 + 0)
+#define PCF_GPIO_MODEM_RESET (GS_IA18_S_PCF_GPIO_BASE2 + 3)
+/* bits 1, 2, 4, 5 not used */
+#define PCF_GPIO_TRX_RESET (GS_IA18_S_PCF_GPIO_BASE2 + 6)
+/* bit 7 not used */
diff --git a/arch/arm/mach-at91/irq.c b/arch/arm/mach-at91/irq.c
index da3494a..b56d6b3a 100644
--- a/arch/arm/mach-at91/irq.c
+++ b/arch/arm/mach-at91/irq.c
@@ -34,23 +34,23 @@
#include <asm/mach/map.h>
-static void at91_aic_mask_irq(unsigned int irq)
+static void at91_aic_mask_irq(struct irq_data *d)
{
/* Disable interrupt on AIC */
- at91_sys_write(AT91_AIC_IDCR, 1 << irq);
+ at91_sys_write(AT91_AIC_IDCR, 1 << d->irq);
}
-static void at91_aic_unmask_irq(unsigned int irq)
+static void at91_aic_unmask_irq(struct irq_data *d)
{
/* Enable interrupt on AIC */
- at91_sys_write(AT91_AIC_IECR, 1 << irq);
+ at91_sys_write(AT91_AIC_IECR, 1 << d->irq);
}
unsigned int at91_extern_irq;
#define is_extern_irq(irq) ((1 << (irq)) & at91_extern_irq)
-static int at91_aic_set_type(unsigned irq, unsigned type)
+static int at91_aic_set_type(struct irq_data *d, unsigned type)
{
unsigned int smr, srctype;
@@ -62,13 +62,13 @@ static int at91_aic_set_type(unsigned irq, unsigned type)
srctype = AT91_AIC_SRCTYPE_RISING;
break;
case IRQ_TYPE_LEVEL_LOW:
- if ((irq == AT91_ID_FIQ) || is_extern_irq(irq)) /* only supported on external interrupts */
+ if ((d->irq == AT91_ID_FIQ) || is_extern_irq(d->irq)) /* only supported on external interrupts */
srctype = AT91_AIC_SRCTYPE_LOW;
else
return -EINVAL;
break;
case IRQ_TYPE_EDGE_FALLING:
- if ((irq == AT91_ID_FIQ) || is_extern_irq(irq)) /* only supported on external interrupts */
+ if ((d->irq == AT91_ID_FIQ) || is_extern_irq(d->irq)) /* only supported on external interrupts */
srctype = AT91_AIC_SRCTYPE_FALLING;
else
return -EINVAL;
@@ -77,8 +77,8 @@ static int at91_aic_set_type(unsigned irq, unsigned type)
return -EINVAL;
}
- smr = at91_sys_read(AT91_AIC_SMR(irq)) & ~AT91_AIC_SRCTYPE;
- at91_sys_write(AT91_AIC_SMR(irq), smr | srctype);
+ smr = at91_sys_read(AT91_AIC_SMR(d->irq)) & ~AT91_AIC_SRCTYPE;
+ at91_sys_write(AT91_AIC_SMR(d->irq), smr | srctype);
return 0;
}
@@ -87,15 +87,15 @@ static int at91_aic_set_type(unsigned irq, unsigned type)
static u32 wakeups;
static u32 backups;
-static int at91_aic_set_wake(unsigned irq, unsigned value)
+static int at91_aic_set_wake(struct irq_data *d, unsigned value)
{
- if (unlikely(irq >= 32))
+ if (unlikely(d->irq >= 32))
return -EINVAL;
if (value)
- wakeups |= (1 << irq);
+ wakeups |= (1 << d->irq);
else
- wakeups &= ~(1 << irq);
+ wakeups &= ~(1 << d->irq);
return 0;
}
@@ -119,11 +119,11 @@ void at91_irq_resume(void)
static struct irq_chip at91_aic_chip = {
.name = "AIC",
- .ack = at91_aic_mask_irq,
- .mask = at91_aic_mask_irq,
- .unmask = at91_aic_unmask_irq,
- .set_type = at91_aic_set_type,
- .set_wake = at91_aic_set_wake,
+ .irq_ack = at91_aic_mask_irq,
+ .irq_mask = at91_aic_mask_irq,
+ .irq_unmask = at91_aic_unmask_irq,
+ .irq_set_type = at91_aic_set_type,
+ .irq_set_wake = at91_aic_set_wake,
};
/*
diff --git a/arch/arm/mach-bcmring/irq.c b/arch/arm/mach-bcmring/irq.c
index e315263..84dcda0 100644
--- a/arch/arm/mach-bcmring/irq.c
+++ b/arch/arm/mach-bcmring/irq.c
@@ -30,61 +30,61 @@
#include <mach/csp/intcHw_reg.h>
#include <mach/csp/mm_io.h>
-static void bcmring_mask_irq0(unsigned int irq)
+static void bcmring_mask_irq0(struct irq_data *d)
{
- writel(1 << (irq - IRQ_INTC0_START),
+ writel(1 << (d->irq - IRQ_INTC0_START),
MM_IO_BASE_INTC0 + INTCHW_INTENCLEAR);
}
-static void bcmring_unmask_irq0(unsigned int irq)
+static void bcmring_unmask_irq0(struct irq_data *d)
{
- writel(1 << (irq - IRQ_INTC0_START),
+ writel(1 << (d->irq - IRQ_INTC0_START),
MM_IO_BASE_INTC0 + INTCHW_INTENABLE);
}
-static void bcmring_mask_irq1(unsigned int irq)
+static void bcmring_mask_irq1(struct irq_data *d)
{
- writel(1 << (irq - IRQ_INTC1_START),
+ writel(1 << (d->irq - IRQ_INTC1_START),
MM_IO_BASE_INTC1 + INTCHW_INTENCLEAR);
}
-static void bcmring_unmask_irq1(unsigned int irq)
+static void bcmring_unmask_irq1(struct irq_data *d)
{
- writel(1 << (irq - IRQ_INTC1_START),
+ writel(1 << (d->irq - IRQ_INTC1_START),
MM_IO_BASE_INTC1 + INTCHW_INTENABLE);
}
-static void bcmring_mask_irq2(unsigned int irq)
+static void bcmring_mask_irq2(struct irq_data *d)
{
- writel(1 << (irq - IRQ_SINTC_START),
+ writel(1 << (d->irq - IRQ_SINTC_START),
MM_IO_BASE_SINTC + INTCHW_INTENCLEAR);
}
-static void bcmring_unmask_irq2(unsigned int irq)
+static void bcmring_unmask_irq2(struct irq_data *d)
{
- writel(1 << (irq - IRQ_SINTC_START),
+ writel(1 << (d->irq - IRQ_SINTC_START),
MM_IO_BASE_SINTC + INTCHW_INTENABLE);
}
static struct irq_chip bcmring_irq0_chip = {
.name = "ARM-INTC0",
- .ack = bcmring_mask_irq0,
- .mask = bcmring_mask_irq0, /* mask a specific interrupt, blocking its delivery. */
- .unmask = bcmring_unmask_irq0, /* unmaks an interrupt */
+ .irq_ack = bcmring_mask_irq0,
+ .irq_mask = bcmring_mask_irq0, /* mask a specific interrupt, blocking its delivery. */
+ .irq_unmask = bcmring_unmask_irq0, /* unmaks an interrupt */
};
static struct irq_chip bcmring_irq1_chip = {
.name = "ARM-INTC1",
- .ack = bcmring_mask_irq1,
- .mask = bcmring_mask_irq1,
- .unmask = bcmring_unmask_irq1,
+ .irq_ack = bcmring_mask_irq1,
+ .irq_mask = bcmring_mask_irq1,
+ .irq_unmask = bcmring_unmask_irq1,
};
static struct irq_chip bcmring_irq2_chip = {
.name = "ARM-SINTC",
- .ack = bcmring_mask_irq2,
- .mask = bcmring_mask_irq2,
- .unmask = bcmring_unmask_irq2,
+ .irq_ack = bcmring_mask_irq2,
+ .irq_mask = bcmring_mask_irq2,
+ .irq_unmask = bcmring_unmask_irq2,
};
static void vic_init(void __iomem *base, struct irq_chip *chip,
diff --git a/arch/arm/mach-clps711x/irq.c b/arch/arm/mach-clps711x/irq.c
index 9a12d85..86da7a1 100644
--- a/arch/arm/mach-clps711x/irq.c
+++ b/arch/arm/mach-clps711x/irq.c
@@ -27,24 +27,24 @@
#include <asm/hardware/clps7111.h>
-static void int1_mask(unsigned int irq)
+static void int1_mask(struct irq_data *d)
{
u32 intmr1;
intmr1 = clps_readl(INTMR1);
- intmr1 &= ~(1 << irq);
+ intmr1 &= ~(1 << d->irq);
clps_writel(intmr1, INTMR1);
}
-static void int1_ack(unsigned int irq)
+static void int1_ack(struct irq_data *d)
{
u32 intmr1;
intmr1 = clps_readl(INTMR1);
- intmr1 &= ~(1 << irq);
+ intmr1 &= ~(1 << d->irq);
clps_writel(intmr1, INTMR1);
- switch (irq) {
+ switch (d->irq) {
case IRQ_CSINT: clps_writel(0, COEOI); break;
case IRQ_TC1OI: clps_writel(0, TC1EOI); break;
case IRQ_TC2OI: clps_writel(0, TC2EOI); break;
@@ -54,56 +54,56 @@ static void int1_ack(unsigned int irq)
}
}
-static void int1_unmask(unsigned int irq)
+static void int1_unmask(struct irq_data *d)
{
u32 intmr1;
intmr1 = clps_readl(INTMR1);
- intmr1 |= 1 << irq;
+ intmr1 |= 1 << d->irq;
clps_writel(intmr1, INTMR1);
}
static struct irq_chip int1_chip = {
- .ack = int1_ack,
- .mask = int1_mask,
- .unmask = int1_unmask,
+ .irq_ack = int1_ack,
+ .irq_mask = int1_mask,
+ .irq_unmask = int1_unmask,
};
-static void int2_mask(unsigned int irq)
+static void int2_mask(struct irq_data *d)
{
u32 intmr2;
intmr2 = clps_readl(INTMR2);
- intmr2 &= ~(1 << (irq - 16));
+ intmr2 &= ~(1 << (d->irq - 16));
clps_writel(intmr2, INTMR2);
}
-static void int2_ack(unsigned int irq)
+static void int2_ack(struct irq_data *d)
{
u32 intmr2;
intmr2 = clps_readl(INTMR2);
- intmr2 &= ~(1 << (irq - 16));
+ intmr2 &= ~(1 << (d->irq - 16));
clps_writel(intmr2, INTMR2);
- switch (irq) {
+ switch (d->irq) {
case IRQ_KBDINT: clps_writel(0, KBDEOI); break;
}
}
-static void int2_unmask(unsigned int irq)
+static void int2_unmask(struct irq_data *d)
{
u32 intmr2;
intmr2 = clps_readl(INTMR2);
- intmr2 |= 1 << (irq - 16);
+ intmr2 |= 1 << (d->irq - 16);
clps_writel(intmr2, INTMR2);
}
static struct irq_chip int2_chip = {
- .ack = int2_ack,
- .mask = int2_mask,
- .unmask = int2_unmask,
+ .irq_ack = int2_ack,
+ .irq_mask = int2_mask,
+ .irq_unmask = int2_unmask,
};
void __init clps711x_init_irq(void)
diff --git a/arch/arm/mach-davinci/cp_intc.c b/arch/arm/mach-davinci/cp_intc.c
index bb4c40e..9abc80a 100644
--- a/arch/arm/mach-davinci/cp_intc.c
+++ b/arch/arm/mach-davinci/cp_intc.c
@@ -26,30 +26,30 @@ static inline void cp_intc_write(unsigned long value, unsigned offset)
__raw_writel(value, davinci_intc_base + offset);
}
-static void cp_intc_ack_irq(unsigned int irq)
+static void cp_intc_ack_irq(struct irq_data *d)
{
- cp_intc_write(irq, CP_INTC_SYS_STAT_IDX_CLR);
+ cp_intc_write(d->irq, CP_INTC_SYS_STAT_IDX_CLR);
}
/* Disable interrupt */
-static void cp_intc_mask_irq(unsigned int irq)
+static void cp_intc_mask_irq(struct irq_data *d)
{
/* XXX don't know why we need to disable nIRQ here... */
cp_intc_write(1, CP_INTC_HOST_ENABLE_IDX_CLR);
- cp_intc_write(irq, CP_INTC_SYS_ENABLE_IDX_CLR);
+ cp_intc_write(d->irq, CP_INTC_SYS_ENABLE_IDX_CLR);
cp_intc_write(1, CP_INTC_HOST_ENABLE_IDX_SET);
}
/* Enable interrupt */
-static void cp_intc_unmask_irq(unsigned int irq)
+static void cp_intc_unmask_irq(struct irq_data *d)
{
- cp_intc_write(irq, CP_INTC_SYS_ENABLE_IDX_SET);
+ cp_intc_write(d->irq, CP_INTC_SYS_ENABLE_IDX_SET);
}
-static int cp_intc_set_irq_type(unsigned int irq, unsigned int flow_type)
+static int cp_intc_set_irq_type(struct irq_data *d, unsigned int flow_type)
{
- unsigned reg = BIT_WORD(irq);
- unsigned mask = BIT_MASK(irq);
+ unsigned reg = BIT_WORD(d->irq);
+ unsigned mask = BIT_MASK(d->irq);
unsigned polarity = cp_intc_read(CP_INTC_SYS_POLARITY(reg));
unsigned type = cp_intc_read(CP_INTC_SYS_TYPE(reg));
@@ -85,18 +85,18 @@ static int cp_intc_set_irq_type(unsigned int irq, unsigned int flow_type)
* generic drivers which call {enable|disable}_irq_wake for
* wake up interrupt sources (eg RTC on DA850).
*/
-static int cp_intc_set_wake(unsigned int irq, unsigned int on)
+static int cp_intc_set_wake(struct irq_data *d, unsigned int on)
{
return 0;
}
static struct irq_chip cp_intc_irq_chip = {
.name = "cp_intc",
- .ack = cp_intc_ack_irq,
- .mask = cp_intc_mask_irq,
- .unmask = cp_intc_unmask_irq,
- .set_type = cp_intc_set_irq_type,
- .set_wake = cp_intc_set_wake,
+ .irq_ack = cp_intc_ack_irq,
+ .irq_mask = cp_intc_mask_irq,
+ .irq_unmask = cp_intc_unmask_irq,
+ .irq_set_type = cp_intc_set_irq_type,
+ .irq_set_wake = cp_intc_set_wake,
};
void __init cp_intc_init(void)
diff --git a/arch/arm/mach-davinci/gpio.c b/arch/arm/mach-davinci/gpio.c
index bf0ff58..20d66e5 100644
--- a/arch/arm/mach-davinci/gpio.c
+++ b/arch/arm/mach-davinci/gpio.c
@@ -205,20 +205,20 @@ pure_initcall(davinci_gpio_setup);
* serve as EDMA event triggers.
*/
-static void gpio_irq_disable(unsigned irq)
+static void gpio_irq_disable(struct irq_data *d)
{
- struct davinci_gpio_regs __iomem *g = irq2regs(irq);
- u32 mask = (u32) get_irq_data(irq);
+ struct davinci_gpio_regs __iomem *g = irq2regs(d->irq);
+ u32 mask = (u32) irq_data_get_irq_data(d);
__raw_writel(mask, &g->clr_falling);
__raw_writel(mask, &g->clr_rising);
}
-static void gpio_irq_enable(unsigned irq)
+static void gpio_irq_enable(struct irq_data *d)
{
- struct davinci_gpio_regs __iomem *g = irq2regs(irq);
- u32 mask = (u32) get_irq_data(irq);
- unsigned status = irq_desc[irq].status;
+ struct davinci_gpio_regs __iomem *g = irq2regs(d->irq);
+ u32 mask = (u32) irq_data_get_irq_data(d);
+ unsigned status = irq_desc[d->irq].status;
status &= IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING;
if (!status)
@@ -230,19 +230,19 @@ static void gpio_irq_enable(unsigned irq)
__raw_writel(mask, &g->set_rising);
}
-static int gpio_irq_type(unsigned irq, unsigned trigger)
+static int gpio_irq_type(struct irq_data *d, unsigned trigger)
{
- struct davinci_gpio_regs __iomem *g = irq2regs(irq);
- u32 mask = (u32) get_irq_data(irq);
+ struct davinci_gpio_regs __iomem *g = irq2regs(d->irq);
+ u32 mask = (u32) irq_data_get_irq_data(d);
if (trigger & ~(IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING))
return -EINVAL;
- irq_desc[irq].status &= ~IRQ_TYPE_SENSE_MASK;
- irq_desc[irq].status |= trigger;
+ irq_desc[d->irq].status &= ~IRQ_TYPE_SENSE_MASK;
+ irq_desc[d->irq].status |= trigger;
/* don't enable the IRQ if it's currently disabled */
- if (irq_desc[irq].depth == 0) {
+ if (irq_desc[d->irq].depth == 0) {
__raw_writel(mask, (trigger & IRQ_TYPE_EDGE_FALLING)
? &g->set_falling : &g->clr_falling);
__raw_writel(mask, (trigger & IRQ_TYPE_EDGE_RISING)
@@ -253,9 +253,9 @@ static int gpio_irq_type(unsigned irq, unsigned trigger)
static struct irq_chip gpio_irqchip = {
.name = "GPIO",
- .enable = gpio_irq_enable,
- .disable = gpio_irq_disable,
- .set_type = gpio_irq_type,
+ .irq_enable = gpio_irq_enable,
+ .irq_disable = gpio_irq_disable,
+ .irq_set_type = gpio_irq_type,
};
static void
@@ -269,8 +269,8 @@ gpio_irq_handler(unsigned irq, struct irq_desc *desc)
mask <<= 16;
/* temporarily mask (level sensitive) parent IRQ */
- desc->chip->mask(irq);
- desc->chip->ack(irq);
+ desc->irq_data.chip->irq_mask(&desc->irq_data);
+ desc->irq_data.chip->irq_ack(&desc->irq_data);
while (1) {
u32 status;
int n;
@@ -293,7 +293,7 @@ gpio_irq_handler(unsigned irq, struct irq_desc *desc)
status >>= res;
}
}
- desc->chip->unmask(irq);
+ desc->irq_data.chip->irq_unmask(&desc->irq_data);
/* now it may re-trigger */
}
@@ -320,10 +320,10 @@ static int gpio_to_irq_unbanked(struct gpio_chip *chip, unsigned offset)
return -ENODEV;
}
-static int gpio_irq_type_unbanked(unsigned irq, unsigned trigger)
+static int gpio_irq_type_unbanked(struct irq_data *d, unsigned trigger)
{
- struct davinci_gpio_regs __iomem *g = irq2regs(irq);
- u32 mask = (u32) get_irq_data(irq);
+ struct davinci_gpio_regs __iomem *g = irq2regs(d->irq);
+ u32 mask = (u32) irq_data_get_irq_data(d);
if (trigger & ~(IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING))
return -EINVAL;
@@ -397,7 +397,7 @@ static int __init davinci_gpio_irq_setup(void)
irq = bank_irq;
gpio_irqchip_unbanked = *get_irq_desc_chip(irq_to_desc(irq));
gpio_irqchip_unbanked.name = "GPIO-AINTC";
- gpio_irqchip_unbanked.set_type = gpio_irq_type_unbanked;
+ gpio_irqchip_unbanked.irq_set_type = gpio_irq_type_unbanked;
/* default trigger: both edges */
g = gpio2regs(0);
diff --git a/arch/arm/mach-davinci/irq.c b/arch/arm/mach-davinci/irq.c
index 784ddf3..5e05c9b 100644
--- a/arch/arm/mach-davinci/irq.c
+++ b/arch/arm/mach-davinci/irq.c
@@ -53,14 +53,14 @@ static inline void davinci_irq_writel(unsigned long value, int offset)
}
/* Disable interrupt */
-static void davinci_mask_irq(unsigned int irq)
+static void davinci_mask_irq(struct irq_data *d)
{
unsigned int mask;
u32 l;
- mask = 1 << IRQ_BIT(irq);
+ mask = 1 << IRQ_BIT(d->irq);
- if (irq > 31) {
+ if (d->irq > 31) {
l = davinci_irq_readl(IRQ_ENT_REG1_OFFSET);
l &= ~mask;
davinci_irq_writel(l, IRQ_ENT_REG1_OFFSET);
@@ -72,14 +72,14 @@ static void davinci_mask_irq(unsigned int irq)
}
/* Enable interrupt */
-static void davinci_unmask_irq(unsigned int irq)
+static void davinci_unmask_irq(struct irq_data *d)
{
unsigned int mask;
u32 l;
- mask = 1 << IRQ_BIT(irq);
+ mask = 1 << IRQ_BIT(d->irq);
- if (irq > 31) {
+ if (d->irq > 31) {
l = davinci_irq_readl(IRQ_ENT_REG1_OFFSET);
l |= mask;
davinci_irq_writel(l, IRQ_ENT_REG1_OFFSET);
@@ -91,23 +91,23 @@ static void davinci_unmask_irq(unsigned int irq)
}
/* EOI interrupt */
-static void davinci_ack_irq(unsigned int irq)
+static void davinci_ack_irq(struct irq_data *d)
{
unsigned int mask;
- mask = 1 << IRQ_BIT(irq);
+ mask = 1 << IRQ_BIT(d->irq);
- if (irq > 31)
+ if (d->irq > 31)
davinci_irq_writel(mask, IRQ_REG1_OFFSET);
else
davinci_irq_writel(mask, IRQ_REG0_OFFSET);
}
static struct irq_chip davinci_irq_chip_0 = {
- .name = "AINTC",
- .ack = davinci_ack_irq,
- .mask = davinci_mask_irq,
- .unmask = davinci_unmask_irq,
+ .name = "AINTC",
+ .irq_ack = davinci_ack_irq,
+ .irq_mask = davinci_mask_irq,
+ .irq_unmask = davinci_unmask_irq,
};
/* ARM Interrupt Controller Initialization */
diff --git a/arch/arm/mach-dove/irq.c b/arch/arm/mach-dove/irq.c
index 61bfcb3..9317f05 100644
--- a/arch/arm/mach-dove/irq.c
+++ b/arch/arm/mach-dove/irq.c
@@ -36,9 +36,9 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
}
}
-static void pmu_irq_mask(unsigned int irq)
+static void pmu_irq_mask(struct irq_data *d)
{
- int pin = irq_to_pmu(irq);
+ int pin = irq_to_pmu(d->irq);
u32 u;
u = readl(PMU_INTERRUPT_MASK);
@@ -46,9 +46,9 @@ static void pmu_irq_mask(unsigned int irq)
writel(u, PMU_INTERRUPT_MASK);
}
-static void pmu_irq_unmask(unsigned int irq)
+static void pmu_irq_unmask(struct irq_data *d)
{
- int pin = irq_to_pmu(irq);
+ int pin = irq_to_pmu(d->irq);
u32 u;
u = readl(PMU_INTERRUPT_MASK);
@@ -56,9 +56,9 @@ static void pmu_irq_unmask(unsigned int irq)
writel(u, PMU_INTERRUPT_MASK);
}
-static void pmu_irq_ack(unsigned int irq)
+static void pmu_irq_ack(struct irq_data *d)
{
- int pin = irq_to_pmu(irq);
+ int pin = irq_to_pmu(d->irq);
u32 u;
u = ~(1 << (pin & 31));
@@ -67,9 +67,9 @@ static void pmu_irq_ack(unsigned int irq)
static struct irq_chip pmu_irq_chip = {
.name = "pmu_irq",
- .mask = pmu_irq_mask,
- .unmask = pmu_irq_unmask,
- .ack = pmu_irq_ack,
+ .irq_mask = pmu_irq_mask,
+ .irq_unmask = pmu_irq_unmask,
+ .irq_ack = pmu_irq_ack,
};
static void pmu_irq_handler(unsigned int irq, struct irq_desc *desc)
diff --git a/arch/arm/mach-ebsa110/core.c b/arch/arm/mach-ebsa110/core.c
index 5df4099..7df083f 100644
--- a/arch/arm/mach-ebsa110/core.c
+++ b/arch/arm/mach-ebsa110/core.c
@@ -35,20 +35,20 @@
#define IRQ_STAT 0xff000000 /* read */
#define IRQ_MCLR 0xff000000 /* write */
-static void ebsa110_mask_irq(unsigned int irq)
+static void ebsa110_mask_irq(struct irq_data *d)
{
- __raw_writeb(1 << irq, IRQ_MCLR);
+ __raw_writeb(1 << d->irq, IRQ_MCLR);
}
-static void ebsa110_unmask_irq(unsigned int irq)
+static void ebsa110_unmask_irq(struct irq_data *d)
{
- __raw_writeb(1 << irq, IRQ_MSET);
+ __raw_writeb(1 << d->irq, IRQ_MSET);
}
static struct irq_chip ebsa110_irq_chip = {
- .ack = ebsa110_mask_irq,
- .mask = ebsa110_mask_irq,
- .unmask = ebsa110_unmask_irq,
+ .irq_ack = ebsa110_mask_irq,
+ .irq_mask = ebsa110_mask_irq,
+ .irq_unmask = ebsa110_unmask_irq,
};
static void __init ebsa110_init_irq(void)
diff --git a/arch/arm/mach-ep93xx/gpio.c b/arch/arm/mach-ep93xx/gpio.c
index cf547ad..f3dc76f 100644
--- a/arch/arm/mach-ep93xx/gpio.c
+++ b/arch/arm/mach-ep93xx/gpio.c
@@ -112,13 +112,13 @@ static void ep93xx_gpio_f_irq_handler(unsigned int irq, struct irq_desc *desc)
generic_handle_irq(gpio_irq);
}
-static void ep93xx_gpio_irq_ack(unsigned int irq)
+static void ep93xx_gpio_irq_ack(struct irq_data *d)
{
- int line = irq_to_gpio(irq);
+ int line = irq_to_gpio(d->irq);
int port = line >> 3;
int port_mask = 1 << (line & 7);
- if ((irq_desc[irq].status & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_BOTH) {
+ if ((irq_desc[d->irq].status & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_BOTH) {
gpio_int_type2[port] ^= port_mask; /* switch edge direction */
ep93xx_gpio_update_int_params(port);
}
@@ -126,13 +126,13 @@ static void ep93xx_gpio_irq_ack(unsigned int irq)
__raw_writeb(port_mask, EP93XX_GPIO_REG(eoi_register_offset[port]));
}
-static void ep93xx_gpio_irq_mask_ack(unsigned int irq)
+static void ep93xx_gpio_irq_mask_ack(struct irq_data *d)
{
- int line = irq_to_gpio(irq);
+ int line = irq_to_gpio(d->irq);
int port = line >> 3;
int port_mask = 1 << (line & 7);
- if ((irq_desc[irq].status & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_BOTH)
+ if ((irq_desc[d->irq].status & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_BOTH)
gpio_int_type2[port] ^= port_mask; /* switch edge direction */
gpio_int_unmasked[port] &= ~port_mask;
@@ -141,18 +141,18 @@ static void ep93xx_gpio_irq_mask_ack(unsigned int irq)
__raw_writeb(port_mask, EP93XX_GPIO_REG(eoi_register_offset[port]));
}
-static void ep93xx_gpio_irq_mask(unsigned int irq)
+static void ep93xx_gpio_irq_mask(struct irq_data *d)
{
- int line = irq_to_gpio(irq);
+ int line = irq_to_gpio(d->irq);
int port = line >> 3;
gpio_int_unmasked[port] &= ~(1 << (line & 7));
ep93xx_gpio_update_int_params(port);
}
-static void ep93xx_gpio_irq_unmask(unsigned int irq)
+static void ep93xx_gpio_irq_unmask(struct irq_data *d)
{
- int line = irq_to_gpio(irq);
+ int line = irq_to_gpio(d->irq);
int port = line >> 3;
gpio_int_unmasked[port] |= 1 << (line & 7);
@@ -164,10 +164,10 @@ static void ep93xx_gpio_irq_unmask(unsigned int irq)
* edge (1) triggered, while gpio_int_type2 controls whether it
* triggers on low/falling (0) or high/rising (1).
*/
-static int ep93xx_gpio_irq_type(unsigned int irq, unsigned int type)
+static int ep93xx_gpio_irq_type(struct irq_data *d, unsigned int type)
{
- struct irq_desc *desc = irq_desc + irq;
- const int gpio = irq_to_gpio(irq);
+ struct irq_desc *desc = irq_desc + d->irq;
+ const int gpio = irq_to_gpio(d->irq);
const int port = gpio >> 3;
const int port_mask = 1 << (gpio & 7);
@@ -220,11 +220,11 @@ static int ep93xx_gpio_irq_type(unsigned int irq, unsigned int type)
static struct irq_chip ep93xx_gpio_irq_chip = {
.name = "GPIO",
- .ack = ep93xx_gpio_irq_ack,
- .mask_ack = ep93xx_gpio_irq_mask_ack,
- .mask = ep93xx_gpio_irq_mask,
- .unmask = ep93xx_gpio_irq_unmask,
- .set_type = ep93xx_gpio_irq_type,
+ .irq_ack = ep93xx_gpio_irq_ack,
+ .irq_mask_ack = ep93xx_gpio_irq_mask_ack,
+ .irq_mask = ep93xx_gpio_irq_mask,
+ .irq_unmask = ep93xx_gpio_irq_unmask,
+ .irq_set_type = ep93xx_gpio_irq_type,
};
void __init ep93xx_gpio_init_irq(void)
diff --git a/arch/arm/mach-footbridge/common.c b/arch/arm/mach-footbridge/common.c
index 88b3dd8..84c5f25 100644
--- a/arch/arm/mach-footbridge/common.c
+++ b/arch/arm/mach-footbridge/common.c
@@ -75,20 +75,20 @@ static const int fb_irq_mask[] = {
IRQ_MASK_PCI_PERR, /* 19 */
};
-static void fb_mask_irq(unsigned int irq)
+static void fb_mask_irq(struct irq_data *d)
{
- *CSR_IRQ_DISABLE = fb_irq_mask[_DC21285_INR(irq)];
+ *CSR_IRQ_DISABLE = fb_irq_mask[_DC21285_INR(d->irq)];
}
-static void fb_unmask_irq(unsigned int irq)
+static void fb_unmask_irq(struct irq_data *d)
{
- *CSR_IRQ_ENABLE = fb_irq_mask[_DC21285_INR(irq)];
+ *CSR_IRQ_ENABLE = fb_irq_mask[_DC21285_INR(d->irq)];
}
static struct irq_chip fb_chip = {
- .ack = fb_mask_irq,
- .mask = fb_mask_irq,
- .unmask = fb_unmask_irq,
+ .irq_ack = fb_mask_irq,
+ .irq_mask = fb_mask_irq,
+ .irq_unmask = fb_unmask_irq,
};
static void __init __fb_init_irq(void)
diff --git a/arch/arm/mach-footbridge/isa-irq.c b/arch/arm/mach-footbridge/isa-irq.c
index 8bfd06a..de7a5cb 100644
--- a/arch/arm/mach-footbridge/isa-irq.c
+++ b/arch/arm/mach-footbridge/isa-irq.c
@@ -30,61 +30,61 @@
#include "common.h"
-static void isa_mask_pic_lo_irq(unsigned int irq)
+static void isa_mask_pic_lo_irq(struct irq_data *d)
{
- unsigned int mask = 1 << (irq & 7);
+ unsigned int mask = 1 << (d->irq & 7);
outb(inb(PIC_MASK_LO) | mask, PIC_MASK_LO);
}
-static void isa_ack_pic_lo_irq(unsigned int irq)
+static void isa_ack_pic_lo_irq(struct irq_data *d)
{
- unsigned int mask = 1 << (irq & 7);
+ unsigned int mask = 1 << (d->irq & 7);
outb(inb(PIC_MASK_LO) | mask, PIC_MASK_LO);
outb(0x20, PIC_LO);
}
-static void isa_unmask_pic_lo_irq(unsigned int irq)
+static void isa_unmask_pic_lo_irq(struct irq_data *d)
{
- unsigned int mask = 1 << (irq & 7);
+ unsigned int mask = 1 << (d->irq & 7);
outb(inb(PIC_MASK_LO) & ~mask, PIC_MASK_LO);
}
static struct irq_chip isa_lo_chip = {
- .ack = isa_ack_pic_lo_irq,
- .mask = isa_mask_pic_lo_irq,
- .unmask = isa_unmask_pic_lo_irq,
+ .irq_ack = isa_ack_pic_lo_irq,
+ .irq_mask = isa_mask_pic_lo_irq,
+ .irq_unmask = isa_unmask_pic_lo_irq,
};
-static void isa_mask_pic_hi_irq(unsigned int irq)
+static void isa_mask_pic_hi_irq(struct irq_data *d)
{
- unsigned int mask = 1 << (irq & 7);
+ unsigned int mask = 1 << (d->irq & 7);
outb(inb(PIC_MASK_HI) | mask, PIC_MASK_HI);
}
-static void isa_ack_pic_hi_irq(unsigned int irq)
+static void isa_ack_pic_hi_irq(struct irq_data *d)
{
- unsigned int mask = 1 << (irq & 7);
+ unsigned int mask = 1 << (d->irq & 7);
outb(inb(PIC_MASK_HI) | mask, PIC_MASK_HI);
outb(0x62, PIC_LO);
outb(0x20, PIC_HI);
}
-static void isa_unmask_pic_hi_irq(unsigned int irq)
+static void isa_unmask_pic_hi_irq(struct irq_data *d)
{
- unsigned int mask = 1 << (irq & 7);
+ unsigned int mask = 1 << (d->irq & 7);
outb(inb(PIC_MASK_HI) & ~mask, PIC_MASK_HI);
}
static struct irq_chip isa_hi_chip = {
- .ack = isa_ack_pic_hi_irq,
- .mask = isa_mask_pic_hi_irq,
- .unmask = isa_unmask_pic_hi_irq,
+ .irq_ack = isa_ack_pic_hi_irq,
+ .irq_mask = isa_mask_pic_hi_irq,
+ .irq_unmask = isa_unmask_pic_hi_irq,
};
static void
diff --git a/arch/arm/mach-gemini/gpio.c b/arch/arm/mach-gemini/gpio.c
index fe3bd5a..fa3d333 100644
--- a/arch/arm/mach-gemini/gpio.c
+++ b/arch/arm/mach-gemini/gpio.c
@@ -54,33 +54,33 @@ static void _set_gpio_irqenable(unsigned int base, unsigned int index,
__raw_writel(reg, base + GPIO_INT_EN);
}
-static void gpio_ack_irq(unsigned int irq)
+static void gpio_ack_irq(struct irq_data *d)
{
- unsigned int gpio = irq_to_gpio(irq);
+ unsigned int gpio = irq_to_gpio(d->irq);
unsigned int base = GPIO_BASE(gpio / 32);
__raw_writel(1 << (gpio % 32), base + GPIO_INT_CLR);
}
-static void gpio_mask_irq(unsigned int irq)
+static void gpio_mask_irq(struct irq_data *d)
{
- unsigned int gpio = irq_to_gpio(irq);
+ unsigned int gpio = irq_to_gpio(d->irq);
unsigned int base = GPIO_BASE(gpio / 32);
_set_gpio_irqenable(base, gpio % 32, 0);
}
-static void gpio_unmask_irq(unsigned int irq)
+static void gpio_unmask_irq(struct irq_data *d)
{
- unsigned int gpio = irq_to_gpio(irq);
+ unsigned int gpio = irq_to_gpio(d->irq);
unsigned int base = GPIO_BASE(gpio / 32);
_set_gpio_irqenable(base, gpio % 32, 1);
}
-static int gpio_set_irq_type(unsigned int irq, unsigned int type)
+static int gpio_set_irq_type(struct irq_data *d, unsigned int type)
{
- unsigned int gpio = irq_to_gpio(irq);
+ unsigned int gpio = irq_to_gpio(d->irq);
unsigned int gpio_mask = 1 << (gpio % 32);
unsigned int base = GPIO_BASE(gpio / 32);
unsigned int reg_both, reg_level, reg_type;
@@ -120,7 +120,7 @@ static int gpio_set_irq_type(unsigned int irq, unsigned int type)
__raw_writel(reg_level, base + GPIO_INT_LEVEL);
__raw_writel(reg_both, base + GPIO_INT_BOTH_EDGE);
- gpio_ack_irq(irq);
+ gpio_ack_irq(d->irq);
return 0;
}
@@ -146,10 +146,10 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
static struct irq_chip gpio_irq_chip = {
.name = "GPIO",
- .ack = gpio_ack_irq,
- .mask = gpio_mask_irq,
- .unmask = gpio_unmask_irq,
- .set_type = gpio_set_irq_type,
+ .irq_ack = gpio_ack_irq,
+ .irq_mask = gpio_mask_irq,
+ .irq_unmask = gpio_unmask_irq,
+ .irq_set_type = gpio_set_irq_type,
};
static void _set_gpio_direction(struct gpio_chip *chip, unsigned offset,
diff --git a/arch/arm/mach-gemini/irq.c b/arch/arm/mach-gemini/irq.c
index 9e613ca..96bc227 100644
--- a/arch/arm/mach-gemini/irq.c
+++ b/arch/arm/mach-gemini/irq.c
@@ -32,34 +32,34 @@
#define FIQ_LEVEL(base_addr) (base_addr + 0x30)
#define FIQ_STATUS(base_addr) (base_addr + 0x34)
-static void gemini_ack_irq(unsigned int irq)
+static void gemini_ack_irq(struct irq_data *d)
{
- __raw_writel(1 << irq, IRQ_CLEAR(IO_ADDRESS(GEMINI_INTERRUPT_BASE)));
+ __raw_writel(1 << d->irq, IRQ_CLEAR(IO_ADDRESS(GEMINI_INTERRUPT_BASE)));
}
-static void gemini_mask_irq(unsigned int irq)
+static void gemini_mask_irq(struct irq_data *d)
{
unsigned int mask;
mask = __raw_readl(IRQ_MASK(IO_ADDRESS(GEMINI_INTERRUPT_BASE)));
- mask &= ~(1 << irq);
+ mask &= ~(1 << d->irq);
__raw_writel(mask, IRQ_MASK(IO_ADDRESS(GEMINI_INTERRUPT_BASE)));
}
-static void gemini_unmask_irq(unsigned int irq)
+static void gemini_unmask_irq(struct irq_data *d)
{
unsigned int mask;
mask = __raw_readl(IRQ_MASK(IO_ADDRESS(GEMINI_INTERRUPT_BASE)));
- mask |= (1 << irq);
+ mask |= (1 << d->irq);
__raw_writel(mask, IRQ_MASK(IO_ADDRESS(GEMINI_INTERRUPT_BASE)));
}
static struct irq_chip gemini_irq_chip = {
- .name = "INTC",
- .ack = gemini_ack_irq,
- .mask = gemini_mask_irq,
- .unmask = gemini_unmask_irq,
+ .name = "INTC",
+ .irq_ack = gemini_ack_irq,
+ .irq_mask = gemini_mask_irq,
+ .irq_unmask = gemini_unmask_irq,
};
static struct resource irq_resource = {
diff --git a/arch/arm/mach-h720x/common.c b/arch/arm/mach-h720x/common.c
index bdb3f67..1f28c90 100644
--- a/arch/arm/mach-h720x/common.c
+++ b/arch/arm/mach-h720x/common.c
@@ -52,17 +52,17 @@ unsigned long h720x_gettimeoffset(void)
/*
* mask Global irq's
*/
-static void mask_global_irq (unsigned int irq )
+static void mask_global_irq(struct irq_data *d)
{
- CPU_REG (IRQC_VIRT, IRQC_IER) &= ~(1 << irq);
+ CPU_REG (IRQC_VIRT, IRQC_IER) &= ~(1 << d->irq);
}
/*
* unmask Global irq's
*/
-static void unmask_global_irq (unsigned int irq )
+static void unmask_global_irq(struct irq_data *d)
{
- CPU_REG (IRQC_VIRT, IRQC_IER) |= (1 << irq);
+ CPU_REG (IRQC_VIRT, IRQC_IER) |= (1 << d->irq);
}
@@ -70,10 +70,10 @@ static void unmask_global_irq (unsigned int irq )
* ack GPIO irq's
* Ack only for edge triggered int's valid
*/
-static void inline ack_gpio_irq(u32 irq)
+static void inline ack_gpio_irq(struct irq_data *d)
{
- u32 reg_base = GPIO_VIRT(IRQ_TO_REGNO(irq));
- u32 bit = IRQ_TO_BIT(irq);
+ u32 reg_base = GPIO_VIRT(IRQ_TO_REGNO(d->irq));
+ u32 bit = IRQ_TO_BIT(d->irq);
if ( (CPU_REG (reg_base, GPIO_EDGE) & bit))
CPU_REG (reg_base, GPIO_CLR) = bit;
}
@@ -81,20 +81,20 @@ static void inline ack_gpio_irq(u32 irq)
/*
* mask GPIO irq's
*/
-static void inline mask_gpio_irq(u32 irq)
+static void inline mask_gpio_irq(struct irq_data *d)
{
- u32 reg_base = GPIO_VIRT(IRQ_TO_REGNO(irq));
- u32 bit = IRQ_TO_BIT(irq);
+ u32 reg_base = GPIO_VIRT(IRQ_TO_REGNO(d->irq));
+ u32 bit = IRQ_TO_BIT(d->irq);
CPU_REG (reg_base, GPIO_MASK) &= ~bit;
}
/*
* unmask GPIO irq's
*/
-static void inline unmask_gpio_irq(u32 irq)
+static void inline unmask_gpio_irq(struct irq_data *d)
{
- u32 reg_base = GPIO_VIRT(IRQ_TO_REGNO(irq));
- u32 bit = IRQ_TO_BIT(irq);
+ u32 reg_base = GPIO_VIRT(IRQ_TO_REGNO(d->irq));
+ u32 bit = IRQ_TO_BIT(d->irq);
CPU_REG (reg_base, GPIO_MASK) |= bit;
}
@@ -170,15 +170,15 @@ h720x_gpioe_demux_handler(unsigned int irq_unused, struct irq_desc *desc)
#endif
static struct irq_chip h720x_global_chip = {
- .ack = mask_global_irq,
- .mask = mask_global_irq,
- .unmask = unmask_global_irq,
+ .irq_ack = mask_global_irq,
+ .irq_mask = mask_global_irq,
+ .irq_unmask = unmask_global_irq,
};
static struct irq_chip h720x_gpio_chip = {
- .ack = ack_gpio_irq,
- .mask = mask_gpio_irq,
- .unmask = unmask_gpio_irq,
+ .irq_ack = ack_gpio_irq,
+ .irq_mask = mask_gpio_irq,
+ .irq_unmask = unmask_gpio_irq,
};
/*
diff --git a/arch/arm/mach-h720x/cpu-h7202.c b/arch/arm/mach-h720x/cpu-h7202.c
index fd33a19..ac3f914 100644
--- a/arch/arm/mach-h720x/cpu-h7202.c
+++ b/arch/arm/mach-h720x/cpu-h7202.c
@@ -141,27 +141,27 @@ h7202_timer_interrupt(int irq, void *dev_id)
/*
* mask multiplexed timer IRQs
*/
-static void inline mask_timerx_irq (u32 irq)
+static void inline mask_timerx_irq(struct irq_data *d)
{
unsigned int bit;
- bit = 2 << ((irq == IRQ_TIMER64B) ? 4 : (irq - IRQ_TIMER1));
+ bit = 2 << ((d->irq == IRQ_TIMER64B) ? 4 : (d->irq - IRQ_TIMER1));
CPU_REG (TIMER_VIRT, TIMER_TOPCTRL) &= ~bit;
}
/*
* unmask multiplexed timer IRQs
*/
-static void inline unmask_timerx_irq (u32 irq)
+static void inline unmask_timerx_irq(struct irq_data *d)
{
unsigned int bit;
- bit = 2 << ((irq == IRQ_TIMER64B) ? 4 : (irq - IRQ_TIMER1));
+ bit = 2 << ((d->irq == IRQ_TIMER64B) ? 4 : (d->irq - IRQ_TIMER1));
CPU_REG (TIMER_VIRT, TIMER_TOPCTRL) |= bit;
}
static struct irq_chip h7202_timerx_chip = {
- .ack = mask_timerx_irq,
- .mask = mask_timerx_irq,
- .unmask = unmask_timerx_irq,
+ .irq_ack = mask_timerx_irq,
+ .irq_mask = mask_timerx_irq,
+ .irq_unmask = unmask_timerx_irq,
};
static struct irqaction h7202_timer_irq = {
diff --git a/arch/arm/mach-h720x/h7201-eval.c b/arch/arm/mach-h720x/h7201-eval.c
index 79f0b89..629454d 100644
--- a/arch/arm/mach-h720x/h7201-eval.c
+++ b/arch/arm/mach-h720x/h7201-eval.c
@@ -23,7 +23,6 @@
#include <asm/types.h>
#include <asm/mach-types.h>
#include <asm/page.h>
-#include <asm/pgtable.h>
#include <asm/mach/arch.h>
#include <mach/hardware.h>
#include "common.h"
diff --git a/arch/arm/mach-h720x/h7202-eval.c b/arch/arm/mach-h720x/h7202-eval.c
index cc28b1e..e9f46b6 100644
--- a/arch/arm/mach-h720x/h7202-eval.c
+++ b/arch/arm/mach-h720x/h7202-eval.c
@@ -23,7 +23,6 @@
#include <asm/types.h>
#include <asm/mach-types.h>
#include <asm/page.h>
-#include <asm/pgtable.h>
#include <asm/mach/arch.h>
#include <mach/irqs.h>
#include <mach/hardware.h>
diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig
index 17d2e60..56684b5 100644
--- a/arch/arm/mach-imx/Kconfig
+++ b/arch/arm/mach-imx/Kconfig
@@ -243,6 +243,7 @@ config MACH_MX27_3DS
select IMX_HAVE_PLATFORM_MXC_EHCI
select IMX_HAVE_PLATFORM_MXC_MMC
select IMX_HAVE_PLATFORM_SPI_IMX
+ select MXC_DEBUG_BOARD
select MXC_ULPI if USB_ULPI
help
Include support for MX27PDK platform. This includes specific
diff --git a/arch/arm/mach-imx/mach-mx27_3ds.c b/arch/arm/mach-imx/mach-mx27_3ds.c
index 6fd0f8f..1643315 100644
--- a/arch/arm/mach-imx/mach-mx27_3ds.c
+++ b/arch/arm/mach-imx/mach-mx27_3ds.c
@@ -37,12 +37,15 @@
#include <mach/common.h>
#include <mach/iomux-mx27.h>
#include <mach/ulpi.h>
+#include <mach/irqs.h>
+#include <mach/3ds_debugboard.h>
#include "devices-imx27.h"
#define SD1_EN_GPIO (GPIO_PORTB + 25)
#define OTG_PHY_RESET_GPIO (GPIO_PORTB + 23)
#define SPI2_SS0 (GPIO_PORTD + 21)
+#define EXPIO_PARENT_INT (MXC_INTERNAL_IRQS + GPIO_PORTC + 28)
static const int mx27pdk_pins[] __initconst = {
/* UART1 */
@@ -215,10 +218,10 @@ static struct regulator_init_data vgen_init = {
static struct mc13783_regulator_init_data mx27_3ds_regulators[] = {
{
- .id = MC13783_REGU_VMMC1,
+ .id = MC13783_REG_VMMC1,
.init_data = &vmmc1_init,
}, {
- .id = MC13783_REGU_VGEN,
+ .id = MC13783_REG_VGEN,
.init_data = &vgen_init,
},
};
@@ -276,6 +279,9 @@ static void __init mx27pdk_init(void)
imx27_add_spi_imx1(&spi2_pdata);
spi_register_board_info(mx27_3ds_spi_devs,
ARRAY_SIZE(mx27_3ds_spi_devs));
+
+ if (mxc_expio_init(MX27_CS5_BASE_ADDR, EXPIO_PARENT_INT))
+ pr_warn("Init of the debugboard failed, all devices on the debugboard are unusable.\n");
}
static void __init mx27pdk_timer_init(void)
diff --git a/arch/arm/mach-integrator/cpu.c b/arch/arm/mach-integrator/cpu.c
index a3fbcb3a..fbb4577 100644
--- a/arch/arm/mach-integrator/cpu.c
+++ b/arch/arm/mach-integrator/cpu.c
@@ -173,7 +173,7 @@ static unsigned int integrator_get(unsigned int cpu)
if (machine_is_integrator()) {
vco.s = (cm_osc >> 8) & 7;
- } else if (machine_is_cintegrator()) {
+ } else {
vco.s = 1;
}
vco.v = cm_osc & 255;
diff --git a/arch/arm/mach-integrator/integrator_ap.c b/arch/arm/mach-integrator/integrator_ap.c
index 2774df8..b666443 100644
--- a/arch/arm/mach-integrator/integrator_ap.c
+++ b/arch/arm/mach-integrator/integrator_ap.c
@@ -156,21 +156,21 @@ static void __init ap_map_io(void)
#define INTEGRATOR_SC_VALID_INT 0x003fffff
-static void sc_mask_irq(unsigned int irq)
+static void sc_mask_irq(struct irq_data *d)
{
- writel(1 << irq, VA_IC_BASE + IRQ_ENABLE_CLEAR);
+ writel(1 << d->irq, VA_IC_BASE + IRQ_ENABLE_CLEAR);
}
-static void sc_unmask_irq(unsigned int irq)
+static void sc_unmask_irq(struct irq_data *d)
{
- writel(1 << irq, VA_IC_BASE + IRQ_ENABLE_SET);
+ writel(1 << d->irq, VA_IC_BASE + IRQ_ENABLE_SET);
}
static struct irq_chip sc_chip = {
- .name = "SC",
- .ack = sc_mask_irq,
- .mask = sc_mask_irq,
- .unmask = sc_unmask_irq,
+ .name = "SC",
+ .irq_ack = sc_mask_irq,
+ .irq_mask = sc_mask_irq,
+ .irq_unmask = sc_unmask_irq,
};
static void __init ap_init_irq(void)
diff --git a/arch/arm/mach-integrator/integrator_cp.c b/arch/arm/mach-integrator/integrator_cp.c
index 85e48a5..e9327da 100644
--- a/arch/arm/mach-integrator/integrator_cp.c
+++ b/arch/arm/mach-integrator/integrator_cp.c
@@ -146,61 +146,61 @@ static void __init intcp_map_io(void)
#define sic_writel __raw_writel
#define sic_readl __raw_readl
-static void cic_mask_irq(unsigned int irq)
+static void cic_mask_irq(struct irq_data *d)
{
- irq -= IRQ_CIC_START;
+ unsigned int irq = d->irq - IRQ_CIC_START;
cic_writel(1 << irq, INTCP_VA_CIC_BASE + IRQ_ENABLE_CLEAR);
}
-static void cic_unmask_irq(unsigned int irq)
+static void cic_unmask_irq(struct irq_data *d)
{
- irq -= IRQ_CIC_START;
+ unsigned int irq = d->irq - IRQ_CIC_START;
cic_writel(1 << irq, INTCP_VA_CIC_BASE + IRQ_ENABLE_SET);
}
static struct irq_chip cic_chip = {
- .name = "CIC",
- .ack = cic_mask_irq,
- .mask = cic_mask_irq,
- .unmask = cic_unmask_irq,
+ .name = "CIC",
+ .irq_ack = cic_mask_irq,
+ .irq_mask = cic_mask_irq,
+ .irq_unmask = cic_unmask_irq,
};
-static void pic_mask_irq(unsigned int irq)
+static void pic_mask_irq(struct irq_data *d)
{
- irq -= IRQ_PIC_START;
+ unsigned int irq = d->irq - IRQ_PIC_START;
pic_writel(1 << irq, INTCP_VA_PIC_BASE + IRQ_ENABLE_CLEAR);
}
-static void pic_unmask_irq(unsigned int irq)
+static void pic_unmask_irq(struct irq_data *d)
{
- irq -= IRQ_PIC_START;
+ unsigned int irq = d->irq - IRQ_PIC_START;
pic_writel(1 << irq, INTCP_VA_PIC_BASE + IRQ_ENABLE_SET);
}
static struct irq_chip pic_chip = {
- .name = "PIC",
- .ack = pic_mask_irq,
- .mask = pic_mask_irq,
- .unmask = pic_unmask_irq,
+ .name = "PIC",
+ .irq_ack = pic_mask_irq,
+ .irq_mask = pic_mask_irq,
+ .irq_unmask = pic_unmask_irq,
};
-static void sic_mask_irq(unsigned int irq)
+static void sic_mask_irq(struct irq_data *d)
{
- irq -= IRQ_SIC_START;
+ unsigned int irq = d->irq - IRQ_SIC_START;
sic_writel(1 << irq, INTCP_VA_SIC_BASE + IRQ_ENABLE_CLEAR);
}
-static void sic_unmask_irq(unsigned int irq)
+static void sic_unmask_irq(struct irq_data *d)
{
- irq -= IRQ_SIC_START;
+ unsigned int irq = d->irq - IRQ_SIC_START;
sic_writel(1 << irq, INTCP_VA_SIC_BASE + IRQ_ENABLE_SET);
}
static struct irq_chip sic_chip = {
- .name = "SIC",
- .ack = sic_mask_irq,
- .mask = sic_mask_irq,
- .unmask = sic_unmask_irq,
+ .name = "SIC",
+ .irq_ack = sic_mask_irq,
+ .irq_mask = sic_mask_irq,
+ .irq_unmask = sic_unmask_irq,
};
static void
diff --git a/arch/arm/mach-iop13xx/irq.c b/arch/arm/mach-iop13xx/irq.c
index 0d099ca..a233470 100644
--- a/arch/arm/mach-iop13xx/irq.c
+++ b/arch/arm/mach-iop13xx/irq.c
@@ -123,79 +123,79 @@ static void write_intsize(u32 val)
/* 0 = Interrupt Masked and 1 = Interrupt not masked */
static void
-iop13xx_irq_mask0 (unsigned int irq)
+iop13xx_irq_mask0 (struct irq_data *d)
{
- write_intctl_0(read_intctl_0() & ~(1 << (irq - 0)));
+ write_intctl_0(read_intctl_0() & ~(1 << (d->irq - 0)));
}
static void
-iop13xx_irq_mask1 (unsigned int irq)
+iop13xx_irq_mask1 (struct irq_data *d)
{
- write_intctl_1(read_intctl_1() & ~(1 << (irq - 32)));
+ write_intctl_1(read_intctl_1() & ~(1 << (d->irq - 32)));
}
static void
-iop13xx_irq_mask2 (unsigned int irq)
+iop13xx_irq_mask2 (struct irq_data *d)
{
- write_intctl_2(read_intctl_2() & ~(1 << (irq - 64)));
+ write_intctl_2(read_intctl_2() & ~(1 << (d->irq - 64)));
}
static void
-iop13xx_irq_mask3 (unsigned int irq)
+iop13xx_irq_mask3 (struct irq_data *d)
{
- write_intctl_3(read_intctl_3() & ~(1 << (irq - 96)));
+ write_intctl_3(read_intctl_3() & ~(1 << (d->irq - 96)));
}
static void
-iop13xx_irq_unmask0(unsigned int irq)
+iop13xx_irq_unmask0(struct irq_data *d)
{
- write_intctl_0(read_intctl_0() | (1 << (irq - 0)));
+ write_intctl_0(read_intctl_0() | (1 << (d->irq - 0)));
}
static void
-iop13xx_irq_unmask1(unsigned int irq)
+iop13xx_irq_unmask1(struct irq_data *d)
{
- write_intctl_1(read_intctl_1() | (1 << (irq - 32)));
+ write_intctl_1(read_intctl_1() | (1 << (d->irq - 32)));
}
static void
-iop13xx_irq_unmask2(unsigned int irq)
+iop13xx_irq_unmask2(struct irq_data *d)
{
- write_intctl_2(read_intctl_2() | (1 << (irq - 64)));
+ write_intctl_2(read_intctl_2() | (1 << (d->irq - 64)));
}
static void
-iop13xx_irq_unmask3(unsigned int irq)
+iop13xx_irq_unmask3(struct irq_data *d)
{
- write_intctl_3(read_intctl_3() | (1 << (irq - 96)));
+ write_intctl_3(read_intctl_3() | (1 << (d->irq - 96)));
}
static struct irq_chip iop13xx_irqchip1 = {
- .name = "IOP13xx-1",
- .ack = iop13xx_irq_mask0,
- .mask = iop13xx_irq_mask0,
- .unmask = iop13xx_irq_unmask0,
+ .name = "IOP13xx-1",
+ .irq_ack = iop13xx_irq_mask0,
+ .irq_mask = iop13xx_irq_mask0,
+ .irq_unmask = iop13xx_irq_unmask0,
};
static struct irq_chip iop13xx_irqchip2 = {
- .name = "IOP13xx-2",
- .ack = iop13xx_irq_mask1,
- .mask = iop13xx_irq_mask1,
- .unmask = iop13xx_irq_unmask1,
+ .name = "IOP13xx-2",
+ .irq_ack = iop13xx_irq_mask1,
+ .irq_mask = iop13xx_irq_mask1,
+ .irq_unmask = iop13xx_irq_unmask1,
};
static struct irq_chip iop13xx_irqchip3 = {
- .name = "IOP13xx-3",
- .ack = iop13xx_irq_mask2,
- .mask = iop13xx_irq_mask2,
- .unmask = iop13xx_irq_unmask2,
+ .name = "IOP13xx-3",
+ .irq_ack = iop13xx_irq_mask2,
+ .irq_mask = iop13xx_irq_mask2,
+ .irq_unmask = iop13xx_irq_unmask2,
};
static struct irq_chip iop13xx_irqchip4 = {
- .name = "IOP13xx-4",
- .ack = iop13xx_irq_mask3,
- .mask = iop13xx_irq_mask3,
- .unmask = iop13xx_irq_unmask3,
+ .name = "IOP13xx-4",
+ .irq_ack = iop13xx_irq_mask3,
+ .irq_mask = iop13xx_irq_mask3,
+ .irq_unmask = iop13xx_irq_unmask3,
};
extern void iop_init_cp6_handler(void);
diff --git a/arch/arm/mach-iop13xx/msi.c b/arch/arm/mach-iop13xx/msi.c
index 7149fcc..c9c02e3 100644
--- a/arch/arm/mach-iop13xx/msi.c
+++ b/arch/arm/mach-iop13xx/msi.c
@@ -156,14 +156,14 @@ void arch_teardown_msi_irq(unsigned int irq)
destroy_irq(irq);
}
-static void iop13xx_msi_nop(unsigned int irq)
+static void iop13xx_msi_nop(struct irq_data *d)
{
return;
}
static struct irq_chip iop13xx_msi_chip = {
.name = "PCI-MSI",
- .ack = iop13xx_msi_nop,
+ .irq_ack = iop13xx_msi_nop,
.irq_enable = unmask_msi_irq,
.irq_disable = mask_msi_irq,
.irq_mask = mask_msi_irq,
diff --git a/arch/arm/mach-iop32x/irq.c b/arch/arm/mach-iop32x/irq.c
index ba59b2d..d3426a1 100644
--- a/arch/arm/mach-iop32x/irq.c
+++ b/arch/arm/mach-iop32x/irq.c
@@ -32,24 +32,24 @@ static void intstr_write(u32 val)
}
static void
-iop32x_irq_mask(unsigned int irq)
+iop32x_irq_mask(struct irq_data *d)
{
- iop32x_mask &= ~(1 << irq);
+ iop32x_mask &= ~(1 << d->irq);
intctl_write(iop32x_mask);
}
static void
-iop32x_irq_unmask(unsigned int irq)
+iop32x_irq_unmask(struct irq_data *d)
{
- iop32x_mask |= 1 << irq;
+ iop32x_mask |= 1 << d->irq;
intctl_write(iop32x_mask);
}
struct irq_chip ext_chip = {
- .name = "IOP32x",
- .ack = iop32x_irq_mask,
- .mask = iop32x_irq_mask,
- .unmask = iop32x_irq_unmask,
+ .name = "IOP32x",
+ .irq_ack = iop32x_irq_mask,
+ .irq_mask = iop32x_irq_mask,
+ .irq_unmask = iop32x_irq_unmask,
};
void __init iop32x_init_irq(void)
diff --git a/arch/arm/mach-iop33x/irq.c b/arch/arm/mach-iop33x/irq.c
index abb4ea2..0ff2f74 100644
--- a/arch/arm/mach-iop33x/irq.c
+++ b/arch/arm/mach-iop33x/irq.c
@@ -53,45 +53,45 @@ static void intsize_write(u32 val)
}
static void
-iop33x_irq_mask1 (unsigned int irq)
+iop33x_irq_mask1 (struct irq_data *d)
{
- iop33x_mask0 &= ~(1 << irq);
+ iop33x_mask0 &= ~(1 << d->irq);
intctl0_write(iop33x_mask0);
}
static void
-iop33x_irq_mask2 (unsigned int irq)
+iop33x_irq_mask2 (struct irq_data *d)
{
- iop33x_mask1 &= ~(1 << (irq - 32));
+ iop33x_mask1 &= ~(1 << (d->irq - 32));
intctl1_write(iop33x_mask1);
}
static void
-iop33x_irq_unmask1(unsigned int irq)
+iop33x_irq_unmask1(struct irq_data *d)
{
- iop33x_mask0 |= 1 << irq;
+ iop33x_mask0 |= 1 << d->irq;
intctl0_write(iop33x_mask0);
}
static void
-iop33x_irq_unmask2(unsigned int irq)
+iop33x_irq_unmask2(struct irq_data *d)
{
- iop33x_mask1 |= (1 << (irq - 32));
+ iop33x_mask1 |= (1 << (d->irq - 32));
intctl1_write(iop33x_mask1);
}
struct irq_chip iop33x_irqchip1 = {
- .name = "IOP33x-1",
- .ack = iop33x_irq_mask1,
- .mask = iop33x_irq_mask1,
- .unmask = iop33x_irq_unmask1,
+ .name = "IOP33x-1",
+ .irq_ack = iop33x_irq_mask1,
+ .irq_mask = iop33x_irq_mask1,
+ .irq_unmask = iop33x_irq_unmask1,
};
struct irq_chip iop33x_irqchip2 = {
- .name = "IOP33x-2",
- .ack = iop33x_irq_mask2,
- .mask = iop33x_irq_mask2,
- .unmask = iop33x_irq_unmask2,
+ .name = "IOP33x-2",
+ .irq_ack = iop33x_irq_mask2,
+ .irq_mask = iop33x_irq_mask2,
+ .irq_unmask = iop33x_irq_unmask2,
};
void __init iop33x_init_irq(void)
diff --git a/arch/arm/mach-ixp2000/core.c b/arch/arm/mach-ixp2000/core.c
index e24e3d0..5fc4e06 100644
--- a/arch/arm/mach-ixp2000/core.c
+++ b/arch/arm/mach-ixp2000/core.c
@@ -309,9 +309,9 @@ static void ixp2000_GPIO_irq_handler(unsigned int irq, struct irq_desc *desc)
}
}
-static int ixp2000_GPIO_irq_type(unsigned int irq, unsigned int type)
+static int ixp2000_GPIO_irq_type(struct irq_data *d, unsigned int type)
{
- int line = irq - IRQ_IXP2000_GPIO0;
+ int line = d->irq - IRQ_IXP2000_GPIO0;
/*
* First, configure this GPIO line as an input.
@@ -342,8 +342,10 @@ static int ixp2000_GPIO_irq_type(unsigned int irq, unsigned int type)
return 0;
}
-static void ixp2000_GPIO_irq_mask_ack(unsigned int irq)
+static void ixp2000_GPIO_irq_mask_ack(struct irq_data *d)
{
+ unsigned int irq = d->irq;
+
ixp2000_reg_write(IXP2000_GPIO_INCR, (1 << (irq - IRQ_IXP2000_GPIO0)));
ixp2000_reg_write(IXP2000_GPIO_EDSR, (1 << (irq - IRQ_IXP2000_GPIO0)));
@@ -351,38 +353,42 @@ static void ixp2000_GPIO_irq_mask_ack(unsigned int irq)
ixp2000_reg_wrb(IXP2000_GPIO_INST, (1 << (irq - IRQ_IXP2000_GPIO0)));
}
-static void ixp2000_GPIO_irq_mask(unsigned int irq)
+static void ixp2000_GPIO_irq_mask(struct irq_data *d)
{
+ unsigned int irq = d->irq;
+
ixp2000_reg_wrb(IXP2000_GPIO_INCR, (1 << (irq - IRQ_IXP2000_GPIO0)));
}
-static void ixp2000_GPIO_irq_unmask(unsigned int irq)
+static void ixp2000_GPIO_irq_unmask(struct irq_data *d)
{
+ unsigned int irq = d->irq;
+
ixp2000_reg_write(IXP2000_GPIO_INSR, (1 << (irq - IRQ_IXP2000_GPIO0)));
}
static struct irq_chip ixp2000_GPIO_irq_chip = {
- .ack = ixp2000_GPIO_irq_mask_ack,
- .mask = ixp2000_GPIO_irq_mask,
- .unmask = ixp2000_GPIO_irq_unmask,
- .set_type = ixp2000_GPIO_irq_type,
+ .irq_ack = ixp2000_GPIO_irq_mask_ack,
+ .irq_mask = ixp2000_GPIO_irq_mask,
+ .irq_unmask = ixp2000_GPIO_irq_unmask,
+ .irq_set_type = ixp2000_GPIO_irq_type,
};
-static void ixp2000_pci_irq_mask(unsigned int irq)
+static void ixp2000_pci_irq_mask(struct irq_data *d)
{
unsigned long temp = *IXP2000_PCI_XSCALE_INT_ENABLE;
- if (irq == IRQ_IXP2000_PCIA)
+ if (d->irq == IRQ_IXP2000_PCIA)
ixp2000_reg_wrb(IXP2000_PCI_XSCALE_INT_ENABLE, (temp & ~(1 << 26)));
- else if (irq == IRQ_IXP2000_PCIB)
+ else if (d->irq == IRQ_IXP2000_PCIB)
ixp2000_reg_wrb(IXP2000_PCI_XSCALE_INT_ENABLE, (temp & ~(1 << 27)));
}
-static void ixp2000_pci_irq_unmask(unsigned int irq)
+static void ixp2000_pci_irq_unmask(struct irq_data *d)
{
unsigned long temp = *IXP2000_PCI_XSCALE_INT_ENABLE;
- if (irq == IRQ_IXP2000_PCIA)
+ if (d->irq == IRQ_IXP2000_PCIA)
ixp2000_reg_write(IXP2000_PCI_XSCALE_INT_ENABLE, (temp | (1 << 26)));
- else if (irq == IRQ_IXP2000_PCIB)
+ else if (d->irq == IRQ_IXP2000_PCIB)
ixp2000_reg_write(IXP2000_PCI_XSCALE_INT_ENABLE, (temp | (1 << 27)));
}
@@ -401,44 +407,44 @@ static void ixp2000_err_irq_handler(unsigned int irq, struct irq_desc *desc)
}
}
-static void ixp2000_err_irq_mask(unsigned int irq)
+static void ixp2000_err_irq_mask(struct irq_data *d)
{
ixp2000_reg_write(IXP2000_IRQ_ERR_ENABLE_CLR,
- (1 << (irq - IRQ_IXP2000_DRAM0_MIN_ERR)));
+ (1 << (d->irq - IRQ_IXP2000_DRAM0_MIN_ERR)));
}
-static void ixp2000_err_irq_unmask(unsigned int irq)
+static void ixp2000_err_irq_unmask(struct irq_data *d)
{
ixp2000_reg_write(IXP2000_IRQ_ERR_ENABLE_SET,
- (1 << (irq - IRQ_IXP2000_DRAM0_MIN_ERR)));
+ (1 << (d->irq - IRQ_IXP2000_DRAM0_MIN_ERR)));
}
static struct irq_chip ixp2000_err_irq_chip = {
- .ack = ixp2000_err_irq_mask,
- .mask = ixp2000_err_irq_mask,
- .unmask = ixp2000_err_irq_unmask
+ .irq_ack = ixp2000_err_irq_mask,
+ .irq_mask = ixp2000_err_irq_mask,
+ .irq_unmask = ixp2000_err_irq_unmask
};
static struct irq_chip ixp2000_pci_irq_chip = {
- .ack = ixp2000_pci_irq_mask,
- .mask = ixp2000_pci_irq_mask,
- .unmask = ixp2000_pci_irq_unmask
+ .irq_ack = ixp2000_pci_irq_mask,
+ .irq_mask = ixp2000_pci_irq_mask,
+ .irq_unmask = ixp2000_pci_irq_unmask
};
-static void ixp2000_irq_mask(unsigned int irq)
+static void ixp2000_irq_mask(struct irq_data *d)
{
- ixp2000_reg_wrb(IXP2000_IRQ_ENABLE_CLR, (1 << irq));
+ ixp2000_reg_wrb(IXP2000_IRQ_ENABLE_CLR, (1 << d->irq));
}
-static void ixp2000_irq_unmask(unsigned int irq)
+static void ixp2000_irq_unmask(struct irq_data *d)
{
- ixp2000_reg_write(IXP2000_IRQ_ENABLE_SET, (1 << irq));
+ ixp2000_reg_write(IXP2000_IRQ_ENABLE_SET, (1 << d->irq));
}
static struct irq_chip ixp2000_irq_chip = {
- .ack = ixp2000_irq_mask,
- .mask = ixp2000_irq_mask,
- .unmask = ixp2000_irq_unmask
+ .irq_ack = ixp2000_irq_mask,
+ .irq_mask = ixp2000_irq_mask,
+ .irq_unmask = ixp2000_irq_unmask
};
void __init ixp2000_init_irq(void)
diff --git a/arch/arm/mach-ixp2000/ixdp2x00.c b/arch/arm/mach-ixp2000/ixdp2x00.c
index 91fffb9..7d90d3f 100644
--- a/arch/arm/mach-ixp2000/ixdp2x00.c
+++ b/arch/arm/mach-ixp2000/ixdp2x00.c
@@ -63,7 +63,7 @@ static struct slowport_cfg slowport_cpld_cfg = {
};
#endif
-static void ixdp2x00_irq_mask(unsigned int irq)
+static void ixdp2x00_irq_mask(struct irq_data *d)
{
unsigned long dummy;
static struct slowport_cfg old_cfg;
@@ -78,7 +78,7 @@ static void ixdp2x00_irq_mask(unsigned int irq)
#endif
dummy = *board_irq_mask;
- dummy |= IXP2000_BOARD_IRQ_MASK(irq);
+ dummy |= IXP2000_BOARD_IRQ_MASK(d->irq);
ixp2000_reg_wrb(board_irq_mask, dummy);
#ifdef CONFIG_ARCH_IXDP2400
@@ -87,7 +87,7 @@ static void ixdp2x00_irq_mask(unsigned int irq)
#endif
}
-static void ixdp2x00_irq_unmask(unsigned int irq)
+static void ixdp2x00_irq_unmask(struct irq_data *d)
{
unsigned long dummy;
static struct slowport_cfg old_cfg;
@@ -98,7 +98,7 @@ static void ixdp2x00_irq_unmask(unsigned int irq)
#endif
dummy = *board_irq_mask;
- dummy &= ~IXP2000_BOARD_IRQ_MASK(irq);
+ dummy &= ~IXP2000_BOARD_IRQ_MASK(d->irq);
ixp2000_reg_wrb(board_irq_mask, dummy);
if (machine_is_ixdp2400())
@@ -111,7 +111,7 @@ static void ixdp2x00_irq_handler(unsigned int irq, struct irq_desc *desc)
static struct slowport_cfg old_cfg;
int i;
- desc->chip->mask(irq);
+ desc->irq_data.chip->irq_mask(&desc->irq_data);
#ifdef CONFIG_ARCH_IXDP2400
if (machine_is_ixdp2400())
@@ -133,13 +133,13 @@ static void ixdp2x00_irq_handler(unsigned int irq, struct irq_desc *desc)
}
}
- desc->chip->unmask(irq);
+ desc->irq_data.chip->irq_unmask(&desc->irq_data);
}
static struct irq_chip ixdp2x00_cpld_irq_chip = {
- .ack = ixdp2x00_irq_mask,
- .mask = ixdp2x00_irq_mask,
- .unmask = ixdp2x00_irq_unmask
+ .irq_ack = ixdp2x00_irq_mask,
+ .irq_mask = ixdp2x00_irq_mask,
+ .irq_unmask = ixdp2x00_irq_unmask
};
void __init ixdp2x00_init_irq(volatile unsigned long *stat_reg, volatile unsigned long *mask_reg, unsigned long nr_of_irqs)
diff --git a/arch/arm/mach-ixp2000/ixdp2x01.c b/arch/arm/mach-ixp2000/ixdp2x01.c
index 6c121bd..34b1b2a 100644
--- a/arch/arm/mach-ixp2000/ixdp2x01.c
+++ b/arch/arm/mach-ixp2000/ixdp2x01.c
@@ -48,16 +48,16 @@
/*************************************************************************
* IXDP2x01 IRQ Handling
*************************************************************************/
-static void ixdp2x01_irq_mask(unsigned int irq)
+static void ixdp2x01_irq_mask(struct irq_data *d)
{
ixp2000_reg_wrb(IXDP2X01_INT_MASK_SET_REG,
- IXP2000_BOARD_IRQ_MASK(irq));
+ IXP2000_BOARD_IRQ_MASK(d->irq));
}
-static void ixdp2x01_irq_unmask(unsigned int irq)
+static void ixdp2x01_irq_unmask(struct irq_data *d)
{
ixp2000_reg_write(IXDP2X01_INT_MASK_CLR_REG,
- IXP2000_BOARD_IRQ_MASK(irq));
+ IXP2000_BOARD_IRQ_MASK(d->irq));
}
static u32 valid_irq_mask;
@@ -67,7 +67,7 @@ static void ixdp2x01_irq_handler(unsigned int irq, struct irq_desc *desc)
u32 ex_interrupt;
int i;
- desc->chip->mask(irq);
+ desc->irq_data.chip->irq_mask(&desc->irq_data);
ex_interrupt = *IXDP2X01_INT_STAT_REG & valid_irq_mask;
@@ -83,13 +83,13 @@ static void ixdp2x01_irq_handler(unsigned int irq, struct irq_desc *desc)
}
}
- desc->chip->unmask(irq);
+ desc->irq_data.chip->irq_unmask(&desc->irq_data);
}
static struct irq_chip ixdp2x01_irq_chip = {
- .mask = ixdp2x01_irq_mask,
- .ack = ixdp2x01_irq_mask,
- .unmask = ixdp2x01_irq_unmask
+ .irq_mask = ixdp2x01_irq_mask,
+ .irq_ack = ixdp2x01_irq_mask,
+ .irq_unmask = ixdp2x01_irq_unmask
};
/*
diff --git a/arch/arm/mach-ixp23xx/core.c b/arch/arm/mach-ixp23xx/core.c
index aa4c442..9c8a339 100644
--- a/arch/arm/mach-ixp23xx/core.c
+++ b/arch/arm/mach-ixp23xx/core.c
@@ -111,9 +111,9 @@ enum ixp23xx_irq_type {
static void ixp23xx_config_irq(unsigned int, enum ixp23xx_irq_type);
-static int ixp23xx_irq_set_type(unsigned int irq, unsigned int type)
+static int ixp23xx_irq_set_type(struct irq_data *d, unsigned int type)
{
- int line = irq - IRQ_IXP23XX_GPIO6 + 6;
+ int line = d->irq - IRQ_IXP23XX_GPIO6 + 6;
u32 int_style;
enum ixp23xx_irq_type irq_type;
volatile u32 *int_reg;
@@ -149,7 +149,7 @@ static int ixp23xx_irq_set_type(unsigned int irq, unsigned int type)
return -EINVAL;
}
- ixp23xx_config_irq(irq, irq_type);
+ ixp23xx_config_irq(d->irq, irq_type);
if (line >= 8) { /* pins 8-15 */
line -= 8;
@@ -173,9 +173,10 @@ static int ixp23xx_irq_set_type(unsigned int irq, unsigned int type)
return 0;
}
-static void ixp23xx_irq_mask(unsigned int irq)
+static void ixp23xx_irq_mask(struct irq_data *d)
{
volatile unsigned long *intr_reg;
+ unsigned int irq = d->irq;
if (irq >= 56)
irq += 8;
@@ -184,9 +185,9 @@ static void ixp23xx_irq_mask(unsigned int irq)
*intr_reg &= ~(1 << (irq % 32));
}
-static void ixp23xx_irq_ack(unsigned int irq)
+static void ixp23xx_irq_ack(struct irq_data *d)
{
- int line = irq - IRQ_IXP23XX_GPIO6 + 6;
+ int line = d->irq - IRQ_IXP23XX_GPIO6 + 6;
if ((line < 6) || (line > 15))
return;
@@ -198,11 +199,12 @@ static void ixp23xx_irq_ack(unsigned int irq)
* Level triggered interrupts on GPIO lines can only be cleared when the
* interrupt condition disappears.
*/
-static void ixp23xx_irq_level_unmask(unsigned int irq)
+static void ixp23xx_irq_level_unmask(struct irq_data *d)
{
volatile unsigned long *intr_reg;
+ unsigned int irq = d->irq;
- ixp23xx_irq_ack(irq);
+ ixp23xx_irq_ack(d);
if (irq >= 56)
irq += 8;
@@ -211,9 +213,10 @@ static void ixp23xx_irq_level_unmask(unsigned int irq)
*intr_reg |= (1 << (irq % 32));
}
-static void ixp23xx_irq_edge_unmask(unsigned int irq)
+static void ixp23xx_irq_edge_unmask(struct irq_data *d)
{
volatile unsigned long *intr_reg;
+ unsigned int irq = d->irq;
if (irq >= 56)
irq += 8;
@@ -223,26 +226,30 @@ static void ixp23xx_irq_edge_unmask(unsigned int irq)
}
static struct irq_chip ixp23xx_irq_level_chip = {
- .ack = ixp23xx_irq_mask,
- .mask = ixp23xx_irq_mask,
- .unmask = ixp23xx_irq_level_unmask,
- .set_type = ixp23xx_irq_set_type
+ .irq_ack = ixp23xx_irq_mask,
+ .irq_mask = ixp23xx_irq_mask,
+ .irq_unmask = ixp23xx_irq_level_unmask,
+ .irq_set_type = ixp23xx_irq_set_type
};
static struct irq_chip ixp23xx_irq_edge_chip = {
- .ack = ixp23xx_irq_ack,
- .mask = ixp23xx_irq_mask,
- .unmask = ixp23xx_irq_edge_unmask,
- .set_type = ixp23xx_irq_set_type
+ .irq_ack = ixp23xx_irq_ack,
+ .irq_mask = ixp23xx_irq_mask,
+ .irq_unmask = ixp23xx_irq_edge_unmask,
+ .irq_set_type = ixp23xx_irq_set_type
};
-static void ixp23xx_pci_irq_mask(unsigned int irq)
+static void ixp23xx_pci_irq_mask(struct irq_data *d)
{
+ unsigned int irq = d->irq;
+
*IXP23XX_PCI_XSCALE_INT_ENABLE &= ~(1 << (IRQ_IXP23XX_INTA + 27 - irq));
}
-static void ixp23xx_pci_irq_unmask(unsigned int irq)
+static void ixp23xx_pci_irq_unmask(struct irq_data *d)
{
+ unsigned int irq = d->irq;
+
*IXP23XX_PCI_XSCALE_INT_ENABLE |= (1 << (IRQ_IXP23XX_INTA + 27 - irq));
}
@@ -256,7 +263,7 @@ static void pci_handler(unsigned int irq, struct irq_desc *desc)
pci_interrupt = *IXP23XX_PCI_XSCALE_INT_STATUS;
- desc->chip->ack(irq);
+ desc->irq_data.chip->irq_ack(&desc->irq_data);
/* See which PCI_INTA, or PCI_INTB interrupted */
if (pci_interrupt & (1 << 26)) {
@@ -269,13 +276,13 @@ static void pci_handler(unsigned int irq, struct irq_desc *desc)
generic_handle_irq(irqno);
- desc->chip->unmask(irq);
+ desc->irq_data.chip->irq_unmask(&desc->irq_data);
}
static struct irq_chip ixp23xx_pci_irq_chip = {
- .ack = ixp23xx_pci_irq_mask,
- .mask = ixp23xx_pci_irq_mask,
- .unmask = ixp23xx_pci_irq_unmask
+ .irq_ack = ixp23xx_pci_irq_mask,
+ .irq_mask = ixp23xx_pci_irq_mask,
+ .irq_unmask = ixp23xx_pci_irq_unmask
};
static void ixp23xx_config_irq(unsigned int irq, enum ixp23xx_irq_type type)
diff --git a/arch/arm/mach-ixp23xx/ixdp2351.c b/arch/arm/mach-ixp23xx/ixdp2351.c
index 664e39c..181116a 100644
--- a/arch/arm/mach-ixp23xx/ixdp2351.c
+++ b/arch/arm/mach-ixp23xx/ixdp2351.c
@@ -48,14 +48,14 @@
/*
* IXDP2351 Interrupt Handling
*/
-static void ixdp2351_inta_mask(unsigned int irq)
+static void ixdp2351_inta_mask(struct irq_data *d)
{
- *IXDP2351_CPLD_INTA_MASK_SET_REG = IXDP2351_INTA_IRQ_MASK(irq);
+ *IXDP2351_CPLD_INTA_MASK_SET_REG = IXDP2351_INTA_IRQ_MASK(d->irq);
}
-static void ixdp2351_inta_unmask(unsigned int irq)
+static void ixdp2351_inta_unmask(struct irq_data *d)
{
- *IXDP2351_CPLD_INTA_MASK_CLR_REG = IXDP2351_INTA_IRQ_MASK(irq);
+ *IXDP2351_CPLD_INTA_MASK_CLR_REG = IXDP2351_INTA_IRQ_MASK(d->irq);
}
static void ixdp2351_inta_handler(unsigned int irq, struct irq_desc *desc)
@@ -64,7 +64,7 @@ static void ixdp2351_inta_handler(unsigned int irq, struct irq_desc *desc)
*IXDP2351_CPLD_INTA_STAT_REG & IXDP2351_INTA_IRQ_VALID;
int i;
- desc->chip->mask(irq);
+ desc->irq_data.chip->irq_mask(&desc->irq_data);
for (i = 0; i < IXDP2351_INTA_IRQ_NUM; i++) {
if (ex_interrupt & (1 << i)) {
@@ -74,23 +74,23 @@ static void ixdp2351_inta_handler(unsigned int irq, struct irq_desc *desc)
}
}
- desc->chip->unmask(irq);
+ desc->irq_data.chip->irq_unmask(&desc->irq_data);
}
static struct irq_chip ixdp2351_inta_chip = {
- .ack = ixdp2351_inta_mask,
- .mask = ixdp2351_inta_mask,
- .unmask = ixdp2351_inta_unmask
+ .irq_ack = ixdp2351_inta_mask,
+ .irq_mask = ixdp2351_inta_mask,
+ .irq_unmask = ixdp2351_inta_unmask
};
-static void ixdp2351_intb_mask(unsigned int irq)
+static void ixdp2351_intb_mask(struct irq_data *d)
{
- *IXDP2351_CPLD_INTB_MASK_SET_REG = IXDP2351_INTB_IRQ_MASK(irq);
+ *IXDP2351_CPLD_INTB_MASK_SET_REG = IXDP2351_INTB_IRQ_MASK(d->irq);
}
-static void ixdp2351_intb_unmask(unsigned int irq)
+static void ixdp2351_intb_unmask(struct irq_data *d)
{
- *IXDP2351_CPLD_INTB_MASK_CLR_REG = IXDP2351_INTB_IRQ_MASK(irq);
+ *IXDP2351_CPLD_INTB_MASK_CLR_REG = IXDP2351_INTB_IRQ_MASK(d->irq);
}
static void ixdp2351_intb_handler(unsigned int irq, struct irq_desc *desc)
@@ -99,7 +99,7 @@ static void ixdp2351_intb_handler(unsigned int irq, struct irq_desc *desc)
*IXDP2351_CPLD_INTB_STAT_REG & IXDP2351_INTB_IRQ_VALID;
int i;
- desc->chip->ack(irq);
+ desc->irq_data.chip->irq_ack(&desc->irq_data);
for (i = 0; i < IXDP2351_INTB_IRQ_NUM; i++) {
if (ex_interrupt & (1 << i)) {
@@ -109,13 +109,13 @@ static void ixdp2351_intb_handler(unsigned int irq, struct irq_desc *desc)
}
}
- desc->chip->unmask(irq);
+ desc->irq_data.chip->irq_unmask(&desc->irq_data);
}
static struct irq_chip ixdp2351_intb_chip = {
- .ack = ixdp2351_intb_mask,
- .mask = ixdp2351_intb_mask,
- .unmask = ixdp2351_intb_unmask
+ .irq_ack = ixdp2351_intb_mask,
+ .irq_mask = ixdp2351_intb_mask,
+ .irq_unmask = ixdp2351_intb_unmask
};
void __init ixdp2351_init_irq(void)
diff --git a/arch/arm/mach-ixp4xx/common.c b/arch/arm/mach-ixp4xx/common.c
index 4dbfcbb..4dc68d6 100644
--- a/arch/arm/mach-ixp4xx/common.c
+++ b/arch/arm/mach-ixp4xx/common.c
@@ -128,9 +128,9 @@ int irq_to_gpio(unsigned int irq)
}
EXPORT_SYMBOL(irq_to_gpio);
-static int ixp4xx_set_irq_type(unsigned int irq, unsigned int type)
+static int ixp4xx_set_irq_type(struct irq_data *d, unsigned int type)
{
- int line = irq2gpio[irq];
+ int line = irq2gpio[d->irq];
u32 int_style;
enum ixp4xx_irq_type irq_type;
volatile u32 *int_reg;
@@ -167,9 +167,9 @@ static int ixp4xx_set_irq_type(unsigned int irq, unsigned int type)
}
if (irq_type == IXP4XX_IRQ_EDGE)
- ixp4xx_irq_edge |= (1 << irq);
+ ixp4xx_irq_edge |= (1 << d->irq);
else
- ixp4xx_irq_edge &= ~(1 << irq);
+ ixp4xx_irq_edge &= ~(1 << d->irq);
if (line >= 8) { /* pins 8-15 */
line -= 8;
@@ -188,22 +188,22 @@ static int ixp4xx_set_irq_type(unsigned int irq, unsigned int type)
*int_reg |= (int_style << (line * IXP4XX_GPIO_STYLE_SIZE));
/* Configure the line as an input */
- gpio_line_config(irq2gpio[irq], IXP4XX_GPIO_IN);
+ gpio_line_config(irq2gpio[d->irq], IXP4XX_GPIO_IN);
return 0;
}
-static void ixp4xx_irq_mask(unsigned int irq)
+static void ixp4xx_irq_mask(struct irq_data *d)
{
- if ((cpu_is_ixp46x() || cpu_is_ixp43x()) && irq >= 32)
- *IXP4XX_ICMR2 &= ~(1 << (irq - 32));
+ if ((cpu_is_ixp46x() || cpu_is_ixp43x()) && d->irq >= 32)
+ *IXP4XX_ICMR2 &= ~(1 << (d->irq - 32));
else
- *IXP4XX_ICMR &= ~(1 << irq);
+ *IXP4XX_ICMR &= ~(1 << d->irq);
}
-static void ixp4xx_irq_ack(unsigned int irq)
+static void ixp4xx_irq_ack(struct irq_data *d)
{
- int line = (irq < 32) ? irq2gpio[irq] : -1;
+ int line = (d->irq < 32) ? irq2gpio[d->irq] : -1;
if (line >= 0)
*IXP4XX_GPIO_GPISR = (1 << line);
@@ -213,23 +213,23 @@ static void ixp4xx_irq_ack(unsigned int irq)
* Level triggered interrupts on GPIO lines can only be cleared when the
* interrupt condition disappears.
*/
-static void ixp4xx_irq_unmask(unsigned int irq)
+static void ixp4xx_irq_unmask(struct irq_data *d)
{
- if (!(ixp4xx_irq_edge & (1 << irq)))
- ixp4xx_irq_ack(irq);
+ if (!(ixp4xx_irq_edge & (1 << d->irq)))
+ ixp4xx_irq_ack(d);
- if ((cpu_is_ixp46x() || cpu_is_ixp43x()) && irq >= 32)
- *IXP4XX_ICMR2 |= (1 << (irq - 32));
+ if ((cpu_is_ixp46x() || cpu_is_ixp43x()) && d->irq >= 32)
+ *IXP4XX_ICMR2 |= (1 << (d->irq - 32));
else
- *IXP4XX_ICMR |= (1 << irq);
+ *IXP4XX_ICMR |= (1 << d->irq);
}
static struct irq_chip ixp4xx_irq_chip = {
.name = "IXP4xx",
- .ack = ixp4xx_irq_ack,
- .mask = ixp4xx_irq_mask,
- .unmask = ixp4xx_irq_unmask,
- .set_type = ixp4xx_set_irq_type,
+ .irq_ack = ixp4xx_irq_ack,
+ .irq_mask = ixp4xx_irq_mask,
+ .irq_unmask = ixp4xx_irq_unmask,
+ .irq_set_type = ixp4xx_set_irq_type,
};
void __init ixp4xx_init_irq(void)
diff --git a/arch/arm/mach-ks8695/irq.c b/arch/arm/mach-ks8695/irq.c
index e375c1d..7998cca 100644
--- a/arch/arm/mach-ks8695/irq.c
+++ b/arch/arm/mach-ks8695/irq.c
@@ -34,29 +34,29 @@
#include <mach/regs-irq.h>
#include <mach/regs-gpio.h>
-static void ks8695_irq_mask(unsigned int irqno)
+static void ks8695_irq_mask(struct irq_data *d)
{
unsigned long inten;
inten = __raw_readl(KS8695_IRQ_VA + KS8695_INTEN);
- inten &= ~(1 << irqno);
+ inten &= ~(1 << d->irq);
__raw_writel(inten, KS8695_IRQ_VA + KS8695_INTEN);
}
-static void ks8695_irq_unmask(unsigned int irqno)
+static void ks8695_irq_unmask(struct irq_data *d)
{
unsigned long inten;
inten = __raw_readl(KS8695_IRQ_VA + KS8695_INTEN);
- inten |= (1 << irqno);
+ inten |= (1 << d->irq);
__raw_writel(inten, KS8695_IRQ_VA + KS8695_INTEN);
}
-static void ks8695_irq_ack(unsigned int irqno)
+static void ks8695_irq_ack(struct irq_data *d)
{
- __raw_writel((1 << irqno), KS8695_IRQ_VA + KS8695_INTST);
+ __raw_writel((1 << d->irq), KS8695_IRQ_VA + KS8695_INTST);
}
@@ -64,7 +64,7 @@ static struct irq_chip ks8695_irq_level_chip;
static struct irq_chip ks8695_irq_edge_chip;
-static int ks8695_irq_set_type(unsigned int irqno, unsigned int type)
+static int ks8695_irq_set_type(struct irq_data *d, unsigned int type)
{
unsigned long ctrl, mode;
unsigned short level_triggered = 0;
@@ -93,7 +93,7 @@ static int ks8695_irq_set_type(unsigned int irqno, unsigned int type)
return -EINVAL;
}
- switch (irqno) {
+ switch (d->irq) {
case KS8695_IRQ_EXTERN0:
ctrl &= ~IOPC_IOEINT0TM;
ctrl |= IOPC_IOEINT0_MODE(mode);
@@ -115,12 +115,12 @@ static int ks8695_irq_set_type(unsigned int irqno, unsigned int type)
}
if (level_triggered) {
- set_irq_chip(irqno, &ks8695_irq_level_chip);
- set_irq_handler(irqno, handle_level_irq);
+ set_irq_chip(d->irq, &ks8695_irq_level_chip);
+ set_irq_handler(d->irq, handle_level_irq);
}
else {
- set_irq_chip(irqno, &ks8695_irq_edge_chip);
- set_irq_handler(irqno, handle_edge_irq);
+ set_irq_chip(d->irq, &ks8695_irq_edge_chip);
+ set_irq_handler(d->irq, handle_edge_irq);
}
__raw_writel(ctrl, KS8695_GPIO_VA + KS8695_IOPC);
@@ -128,17 +128,17 @@ static int ks8695_irq_set_type(unsigned int irqno, unsigned int type)
}
static struct irq_chip ks8695_irq_level_chip = {
- .ack = ks8695_irq_mask,
- .mask = ks8695_irq_mask,
- .unmask = ks8695_irq_unmask,
- .set_type = ks8695_irq_set_type,
+ .irq_ack = ks8695_irq_mask,
+ .irq_mask = ks8695_irq_mask,
+ .irq_unmask = ks8695_irq_unmask,
+ .irq_set_type = ks8695_irq_set_type,
};
static struct irq_chip ks8695_irq_edge_chip = {
- .ack = ks8695_irq_ack,
- .mask = ks8695_irq_mask,
- .unmask = ks8695_irq_unmask,
- .set_type = ks8695_irq_set_type,
+ .irq_ack = ks8695_irq_ack,
+ .irq_mask = ks8695_irq_mask,
+ .irq_unmask = ks8695_irq_unmask,
+ .irq_set_type = ks8695_irq_set_type,
};
void __init ks8695_init_irq(void)
@@ -164,7 +164,8 @@ void __init ks8695_init_irq(void)
/* Edge-triggered interrupts */
default:
- ks8695_irq_ack(irq); /* clear pending bit */
+ /* clear pending bit */
+ ks8695_irq_ack(irq_get_irq_data(irq));
set_irq_chip(irq, &ks8695_irq_edge_chip);
set_irq_handler(irq, handle_edge_irq);
}
diff --git a/arch/arm/mach-lh7a40x/arch-kev7a400.c b/arch/arm/mach-lh7a40x/arch-kev7a400.c
index 9088c166..71129c3 100644
--- a/arch/arm/mach-lh7a40x/arch-kev7a400.c
+++ b/arch/arm/mach-lh7a40x/arch-kev7a400.c
@@ -46,28 +46,28 @@ void __init kev7a400_map_io(void)
static u16 CPLD_IRQ_mask; /* Mask for CPLD IRQs, 1 == unmasked */
-static void kev7a400_ack_cpld_irq (u32 irq)
+static void kev7a400_ack_cpld_irq(struct irq_data *d)
{
- CPLD_CL_INT = 1 << (irq - IRQ_KEV7A400_CPLD);
+ CPLD_CL_INT = 1 << (d->irq - IRQ_KEV7A400_CPLD);
}
-static void kev7a400_mask_cpld_irq (u32 irq)
+static void kev7a400_mask_cpld_irq(struct irq_data *d)
{
- CPLD_IRQ_mask &= ~(1 << (irq - IRQ_KEV7A400_CPLD));
+ CPLD_IRQ_mask &= ~(1 << (d->irq - IRQ_KEV7A400_CPLD));
CPLD_WR_PB_INT_MASK = CPLD_IRQ_mask;
}
-static void kev7a400_unmask_cpld_irq (u32 irq)
+static void kev7a400_unmask_cpld_irq(struct irq_data *d)
{
- CPLD_IRQ_mask |= 1 << (irq - IRQ_KEV7A400_CPLD);
+ CPLD_IRQ_mask |= 1 << (d->irq - IRQ_KEV7A400_CPLD);
CPLD_WR_PB_INT_MASK = CPLD_IRQ_mask;
}
static struct irq_chip kev7a400_cpld_chip = {
- .name = "CPLD",
- .ack = kev7a400_ack_cpld_irq,
- .mask = kev7a400_mask_cpld_irq,
- .unmask = kev7a400_unmask_cpld_irq,
+ .name = "CPLD",
+ .irq_ack = kev7a400_ack_cpld_irq,
+ .irq_mask = kev7a400_mask_cpld_irq,
+ .irq_unmask = kev7a400_unmask_cpld_irq,
};
diff --git a/arch/arm/mach-lh7a40x/arch-lpd7a40x.c b/arch/arm/mach-lh7a40x/arch-lpd7a40x.c
index 7315a56..e735546 100644
--- a/arch/arm/mach-lh7a40x/arch-lpd7a40x.c
+++ b/arch/arm/mach-lh7a40x/arch-lpd7a40x.c
@@ -159,7 +159,7 @@ static void __init lpd7a40x_init (void)
#endif
}
-static void lh7a40x_ack_cpld_irq (u32 irq)
+static void lh7a40x_ack_cpld_irq(struct irq_data *d)
{
/* CPLD doesn't have ack capability, but some devices may */
@@ -167,14 +167,14 @@ static void lh7a40x_ack_cpld_irq (u32 irq)
/* The touch control *must* mask the interrupt because the
* interrupt bit is read by the driver to determine if the pen
* is still down. */
- if (irq == IRQ_TOUCH)
+ if (d->irq == IRQ_TOUCH)
CPLD_INTERRUPTS |= CPLD_INTMASK_TOUCH;
#endif
}
-static void lh7a40x_mask_cpld_irq (u32 irq)
+static void lh7a40x_mask_cpld_irq(struct irq_data *d)
{
- switch (irq) {
+ switch (d->irq) {
case IRQ_LPD7A40X_ETH_INT:
CPLD_INTERRUPTS |= CPLD_INTMASK_ETHERNET;
break;
@@ -186,9 +186,9 @@ static void lh7a40x_mask_cpld_irq (u32 irq)
}
}
-static void lh7a40x_unmask_cpld_irq (u32 irq)
+static void lh7a40x_unmask_cpld_irq(struct irq_data *d)
{
- switch (irq) {
+ switch (d->irq) {
case IRQ_LPD7A40X_ETH_INT:
CPLD_INTERRUPTS &= ~CPLD_INTMASK_ETHERNET;
break;
@@ -201,17 +201,17 @@ static void lh7a40x_unmask_cpld_irq (u32 irq)
}
static struct irq_chip lpd7a40x_cpld_chip = {
- .name = "CPLD",
- .ack = lh7a40x_ack_cpld_irq,
- .mask = lh7a40x_mask_cpld_irq,
- .unmask = lh7a40x_unmask_cpld_irq,
+ .name = "CPLD",
+ .irq_ack = lh7a40x_ack_cpld_irq,
+ .irq_mask = lh7a40x_mask_cpld_irq,
+ .irq_unmask = lh7a40x_unmask_cpld_irq,
};
static void lpd7a40x_cpld_handler (unsigned int irq, struct irq_desc *desc)
{
unsigned int mask = CPLD_INTERRUPTS;
- desc->chip->ack (irq);
+ desc->irq_data.chip->irq_ack(&desc->irq_data);
if ((mask & (1<<0)) == 0) /* WLAN */
generic_handle_irq(IRQ_LPD7A40X_ETH_INT);
@@ -221,7 +221,8 @@ static void lpd7a40x_cpld_handler (unsigned int irq, struct irq_desc *desc)
generic_handle_irq(IRQ_TOUCH);
#endif
- desc->chip->unmask (irq); /* Level-triggered need this */
+ /* Level-triggered need this */
+ desc->irq_data.chip->irq_unmask(&desc->irq_data);
}
diff --git a/arch/arm/mach-lh7a40x/irq-lh7a400.c b/arch/arm/mach-lh7a40x/irq-lh7a400.c
index 1ad3afc..f2e7e65 100644
--- a/arch/arm/mach-lh7a40x/irq-lh7a400.c
+++ b/arch/arm/mach-lh7a40x/irq-lh7a400.c
@@ -21,34 +21,34 @@
/* CPU IRQ handling */
-static void lh7a400_mask_irq (u32 irq)
+static void lh7a400_mask_irq(struct irq_data *d)
{
- INTC_INTENC = (1 << irq);
+ INTC_INTENC = (1 << d->irq);
}
-static void lh7a400_unmask_irq (u32 irq)
+static void lh7a400_unmask_irq(struct irq_data *d)
{
- INTC_INTENS = (1 << irq);
+ INTC_INTENS = (1 << d->irq);
}
-static void lh7a400_ack_gpio_irq (u32 irq)
+static void lh7a400_ack_gpio_irq(struct irq_data *d)
{
- GPIO_GPIOFEOI = (1 << IRQ_TO_GPIO (irq));
- INTC_INTENC = (1 << irq);
+ GPIO_GPIOFEOI = (1 << IRQ_TO_GPIO (d->irq));
+ INTC_INTENC = (1 << d->irq);
}
static struct irq_chip lh7a400_internal_chip = {
- .name = "MPU",
- .ack = lh7a400_mask_irq, /* Level triggering -> mask is ack */
- .mask = lh7a400_mask_irq,
- .unmask = lh7a400_unmask_irq,
+ .name = "MPU",
+ .irq_ack = lh7a400_mask_irq, /* Level triggering -> mask is ack */
+ .irq_mask = lh7a400_mask_irq,
+ .irq_unmask = lh7a400_unmask_irq,
};
static struct irq_chip lh7a400_gpio_chip = {
- .name = "GPIO",
- .ack = lh7a400_ack_gpio_irq,
- .mask = lh7a400_mask_irq,
- .unmask = lh7a400_unmask_irq,
+ .name = "GPIO",
+ .irq_ack = lh7a400_ack_gpio_irq,
+ .irq_mask = lh7a400_mask_irq,
+ .irq_unmask = lh7a400_unmask_irq,
};
diff --git a/arch/arm/mach-lh7a40x/irq-lh7a404.c b/arch/arm/mach-lh7a40x/irq-lh7a404.c
index 12b045b..14b1733 100644
--- a/arch/arm/mach-lh7a40x/irq-lh7a404.c
+++ b/arch/arm/mach-lh7a40x/irq-lh7a404.c
@@ -43,64 +43,64 @@ static unsigned char irq_pri_vic2[] = {
/* CPU IRQ handling */
-static void lh7a404_vic1_mask_irq (u32 irq)
+static void lh7a404_vic1_mask_irq(struct irq_data *d)
{
- VIC1_INTENCLR = (1 << irq);
+ VIC1_INTENCLR = (1 << d->irq);
}
-static void lh7a404_vic1_unmask_irq (u32 irq)
+static void lh7a404_vic1_unmask_irq(struct irq_data *d)
{
- VIC1_INTEN = (1 << irq);
+ VIC1_INTEN = (1 << d->irq);
}
-static void lh7a404_vic2_mask_irq (u32 irq)
+static void lh7a404_vic2_mask_irq(struct irq_data *d)
{
- VIC2_INTENCLR = (1 << (irq - 32));
+ VIC2_INTENCLR = (1 << (d->irq - 32));
}
-static void lh7a404_vic2_unmask_irq (u32 irq)
+static void lh7a404_vic2_unmask_irq(struct irq_data *d)
{
- VIC2_INTEN = (1 << (irq - 32));
+ VIC2_INTEN = (1 << (d->irq - 32));
}
-static void lh7a404_vic1_ack_gpio_irq (u32 irq)
+static void lh7a404_vic1_ack_gpio_irq(struct irq_data *d)
{
- GPIO_GPIOFEOI = (1 << IRQ_TO_GPIO (irq));
- VIC1_INTENCLR = (1 << irq);
+ GPIO_GPIOFEOI = (1 << IRQ_TO_GPIO (d->irq));
+ VIC1_INTENCLR = (1 << d->irq);
}
-static void lh7a404_vic2_ack_gpio_irq (u32 irq)
+static void lh7a404_vic2_ack_gpio_irq(struct irq_data *d)
{
- GPIO_GPIOFEOI = (1 << IRQ_TO_GPIO (irq));
- VIC2_INTENCLR = (1 << irq);
+ GPIO_GPIOFEOI = (1 << IRQ_TO_GPIO (d->irq));
+ VIC2_INTENCLR = (1 << d->irq);
}
static struct irq_chip lh7a404_vic1_chip = {
- .name = "VIC1",
- .ack = lh7a404_vic1_mask_irq, /* Because level-triggered */
- .mask = lh7a404_vic1_mask_irq,
- .unmask = lh7a404_vic1_unmask_irq,
+ .name = "VIC1",
+ .irq_ack = lh7a404_vic1_mask_irq, /* Because level-triggered */
+ .irq_mask = lh7a404_vic1_mask_irq,
+ .irq_unmask = lh7a404_vic1_unmask_irq,
};
static struct irq_chip lh7a404_vic2_chip = {
- .name = "VIC2",
- .ack = lh7a404_vic2_mask_irq, /* Because level-triggered */
- .mask = lh7a404_vic2_mask_irq,
- .unmask = lh7a404_vic2_unmask_irq,
+ .name = "VIC2",
+ .irq_ack = lh7a404_vic2_mask_irq, /* Because level-triggered */
+ .irq_mask = lh7a404_vic2_mask_irq,
+ .irq_unmask = lh7a404_vic2_unmask_irq,
};
static struct irq_chip lh7a404_gpio_vic1_chip = {
- .name = "GPIO-VIC1",
- .ack = lh7a404_vic1_ack_gpio_irq,
- .mask = lh7a404_vic1_mask_irq,
- .unmask = lh7a404_vic1_unmask_irq,
+ .name = "GPIO-VIC1",
+ .irq_ack = lh7a404_vic1_ack_gpio_irq,
+ .irq_mask = lh7a404_vic1_mask_irq,
+ .irq_unmask = lh7a404_vic1_unmask_irq,
};
static struct irq_chip lh7a404_gpio_vic2_chip = {
- .name = "GPIO-VIC2",
- .ack = lh7a404_vic2_ack_gpio_irq,
- .mask = lh7a404_vic2_mask_irq,
- .unmask = lh7a404_vic2_unmask_irq,
+ .name = "GPIO-VIC2",
+ .irq_ack = lh7a404_vic2_ack_gpio_irq,
+ .irq_mask = lh7a404_vic2_mask_irq,
+ .irq_unmask = lh7a404_vic2_unmask_irq,
};
/* IRQ initialization */
diff --git a/arch/arm/mach-lh7a40x/irq-lpd7a40x.c b/arch/arm/mach-lh7a40x/irq-lpd7a40x.c
index fd033bb..1bfdcdd 100644
--- a/arch/arm/mach-lh7a40x/irq-lpd7a40x.c
+++ b/arch/arm/mach-lh7a40x/irq-lpd7a40x.c
@@ -20,14 +20,14 @@
#include "common.h"
-static void lh7a40x_ack_cpld_irq (u32 irq)
+static void lh7a40x_ack_cpld_irq(struct irq_data *d)
{
/* CPLD doesn't have ack capability */
}
-static void lh7a40x_mask_cpld_irq (u32 irq)
+static void lh7a40x_mask_cpld_irq(struct irq_data *d)
{
- switch (irq) {
+ switch (d->irq) {
case IRQ_LPD7A40X_ETH_INT:
CPLD_INTERRUPTS = CPLD_INTERRUPTS | 0x4;
break;
@@ -37,9 +37,9 @@ static void lh7a40x_mask_cpld_irq (u32 irq)
}
}
-static void lh7a40x_unmask_cpld_irq (u32 irq)
+static void lh7a40x_unmask_cpld_irq(struct irq_data *d)
{
- switch (irq) {
+ switch (d->irq) {
case IRQ_LPD7A40X_ETH_INT:
CPLD_INTERRUPTS = CPLD_INTERRUPTS & ~ 0x4;
break;
@@ -50,17 +50,17 @@ static void lh7a40x_unmask_cpld_irq (u32 irq)
}
static struct irq_chip lh7a40x_cpld_chip = {
- .name = "CPLD",
- .ack = lh7a40x_ack_cpld_irq,
- .mask = lh7a40x_mask_cpld_irq,
- .unmask = lh7a40x_unmask_cpld_irq,
+ .name = "CPLD",
+ .irq_ack = lh7a40x_ack_cpld_irq,
+ .irq_mask = lh7a40x_mask_cpld_irq,
+ .irq_unmask = lh7a40x_unmask_cpld_irq,
};
static void lh7a40x_cpld_handler (unsigned int irq, struct irq_desc *desc)
{
unsigned int mask = CPLD_INTERRUPTS;
- desc->chip->ack (irq);
+ desc->irq_data.chip->ack (irq);
if ((mask & 0x1) == 0) /* WLAN */
generic_handle_irq(IRQ_LPD7A40X_ETH_INT);
@@ -68,7 +68,7 @@ static void lh7a40x_cpld_handler (unsigned int irq, struct irq_desc *desc)
if ((mask & 0x2) == 0) /* Touch */
generic_handle_irq(IRQ_LPD7A400_TS);
- desc->chip->unmask (irq); /* Level-triggered need this */
+ desc->irq_data.chip->unmask (irq); /* Level-triggered need this */
}
diff --git a/arch/arm/mach-lpc32xx/irq.c b/arch/arm/mach-lpc32xx/irq.c
index bd0df26..316ecbf 100644
--- a/arch/arm/mach-lpc32xx/irq.c
+++ b/arch/arm/mach-lpc32xx/irq.c
@@ -191,38 +191,38 @@ static void get_controller(unsigned int irq, unsigned int *base,
}
}
-static void lpc32xx_mask_irq(unsigned int irq)
+static void lpc32xx_mask_irq(struct irq_data *d)
{
unsigned int reg, ctrl, mask;
- get_controller(irq, &ctrl, &mask);
+ get_controller(d->irq, &ctrl, &mask);
reg = __raw_readl(LPC32XX_INTC_MASK(ctrl)) & ~mask;
__raw_writel(reg, LPC32XX_INTC_MASK(ctrl));
}
-static void lpc32xx_unmask_irq(unsigned int irq)
+static void lpc32xx_unmask_irq(struct irq_data *d)
{
unsigned int reg, ctrl, mask;
- get_controller(irq, &ctrl, &mask);
+ get_controller(d->irq, &ctrl, &mask);
reg = __raw_readl(LPC32XX_INTC_MASK(ctrl)) | mask;
__raw_writel(reg, LPC32XX_INTC_MASK(ctrl));
}
-static void lpc32xx_ack_irq(unsigned int irq)
+static void lpc32xx_ack_irq(struct irq_data *d)
{
unsigned int ctrl, mask;
- get_controller(irq, &ctrl, &mask);
+ get_controller(d->irq, &ctrl, &mask);
__raw_writel(mask, LPC32XX_INTC_RAW_STAT(ctrl));
/* Also need to clear pending wake event */
- if (lpc32xx_events[irq].mask != 0)
- __raw_writel(lpc32xx_events[irq].mask,
- lpc32xx_events[irq].event_group->rawstat_reg);
+ if (lpc32xx_events[d->irq].mask != 0)
+ __raw_writel(lpc32xx_events[d->irq].mask,
+ lpc32xx_events[d->irq].event_group->rawstat_reg);
}
static void __lpc32xx_set_irq_type(unsigned int irq, int use_high_level,
@@ -261,27 +261,27 @@ static void __lpc32xx_set_irq_type(unsigned int irq, int use_high_level,
}
}
-static int lpc32xx_set_irq_type(unsigned int irq, unsigned int type)
+static int lpc32xx_set_irq_type(struct irq_data *d, unsigned int type)
{
switch (type) {
case IRQ_TYPE_EDGE_RISING:
/* Rising edge sensitive */
- __lpc32xx_set_irq_type(irq, 1, 1);
+ __lpc32xx_set_irq_type(d->irq, 1, 1);
break;
case IRQ_TYPE_EDGE_FALLING:
/* Falling edge sensitive */
- __lpc32xx_set_irq_type(irq, 0, 1);
+ __lpc32xx_set_irq_type(d->irq, 0, 1);
break;
case IRQ_TYPE_LEVEL_LOW:
/* Low level sensitive */
- __lpc32xx_set_irq_type(irq, 0, 0);
+ __lpc32xx_set_irq_type(d->irq, 0, 0);
break;
case IRQ_TYPE_LEVEL_HIGH:
/* High level sensitive */
- __lpc32xx_set_irq_type(irq, 1, 0);
+ __lpc32xx_set_irq_type(d->irq, 1, 0);
break;
/* Other modes are not supported */
@@ -290,33 +290,33 @@ static int lpc32xx_set_irq_type(unsigned int irq, unsigned int type)
}
/* Ok to use the level handler for all types */
- set_irq_handler(irq, handle_level_irq);
+ set_irq_handler(d->irq, handle_level_irq);
return 0;
}
-static int lpc32xx_irq_wake(unsigned int irqno, unsigned int state)
+static int lpc32xx_irq_wake(struct irq_data *d, unsigned int state)
{
unsigned long eventreg;
- if (lpc32xx_events[irqno].mask != 0) {
- eventreg = __raw_readl(lpc32xx_events[irqno].
+ if (lpc32xx_events[d->irq].mask != 0) {
+ eventreg = __raw_readl(lpc32xx_events[d->irq].
event_group->enab_reg);
if (state)
- eventreg |= lpc32xx_events[irqno].mask;
+ eventreg |= lpc32xx_events[d->irq].mask;
else
- eventreg &= ~lpc32xx_events[irqno].mask;
+ eventreg &= ~lpc32xx_events[d->irq].mask;
__raw_writel(eventreg,
- lpc32xx_events[irqno].event_group->enab_reg);
+ lpc32xx_events[d->irq].event_group->enab_reg);
return 0;
}
/* Clear event */
- __raw_writel(lpc32xx_events[irqno].mask,
- lpc32xx_events[irqno].event_group->rawstat_reg);
+ __raw_writel(lpc32xx_events[d->irq].mask,
+ lpc32xx_events[d->irq].event_group->rawstat_reg);
return -ENODEV;
}
@@ -336,11 +336,11 @@ static void __init lpc32xx_set_default_mappings(unsigned int apr,
}
static struct irq_chip lpc32xx_irq_chip = {
- .ack = lpc32xx_ack_irq,
- .mask = lpc32xx_mask_irq,
- .unmask = lpc32xx_unmask_irq,
- .set_type = lpc32xx_set_irq_type,
- .set_wake = lpc32xx_irq_wake
+ .irq_ack = lpc32xx_ack_irq,
+ .irq_mask = lpc32xx_mask_irq,
+ .irq_unmask = lpc32xx_unmask_irq,
+ .irq_set_type = lpc32xx_set_irq_type,
+ .irq_set_wake = lpc32xx_irq_wake
};
static void lpc32xx_sic1_handler(unsigned int irq, struct irq_desc *desc)
diff --git a/arch/arm/mach-mmp/include/mach/mfp-mmp2.h b/arch/arm/mach-mmp/include/mach/mfp-mmp2.h
index 117e303..4ad3862 100644
--- a/arch/arm/mach-mmp/include/mach/mfp-mmp2.h
+++ b/arch/arm/mach-mmp/include/mach/mfp-mmp2.h
@@ -6,7 +6,7 @@
#define MFP_DRIVE_VERY_SLOW (0x0 << 13)
#define MFP_DRIVE_SLOW (0x2 << 13)
#define MFP_DRIVE_MEDIUM (0x4 << 13)
-#define MFP_DRIVE_FAST (0x8 << 13)
+#define MFP_DRIVE_FAST (0x6 << 13)
/* GPIO */
#define GPIO0_GPIO MFP_CFG(GPIO0, AF0)
diff --git a/arch/arm/mach-mmp/include/mach/mfp-pxa910.h b/arch/arm/mach-mmp/include/mach/mfp-pxa910.h
index 7e8a80f..fbd7ee8 100644
--- a/arch/arm/mach-mmp/include/mach/mfp-pxa910.h
+++ b/arch/arm/mach-mmp/include/mach/mfp-pxa910.h
@@ -6,7 +6,7 @@
#define MFP_DRIVE_VERY_SLOW (0x0 << 13)
#define MFP_DRIVE_SLOW (0x2 << 13)
#define MFP_DRIVE_MEDIUM (0x4 << 13)
-#define MFP_DRIVE_FAST (0x8 << 13)
+#define MFP_DRIVE_FAST (0x6 << 13)
/* UART2 */
#define GPIO47_UART2_RXD MFP_CFG(GPIO47, AF6)
diff --git a/arch/arm/mach-mmp/irq-mmp2.c b/arch/arm/mach-mmp/irq-mmp2.c
index 01342be..fa03703 100644
--- a/arch/arm/mach-mmp/irq-mmp2.c
+++ b/arch/arm/mach-mmp/irq-mmp2.c
@@ -20,48 +20,48 @@
#include "common.h"
-static void icu_mask_irq(unsigned int irq)
+static void icu_mask_irq(struct irq_data *d)
{
- uint32_t r = __raw_readl(ICU_INT_CONF(irq));
+ uint32_t r = __raw_readl(ICU_INT_CONF(d->irq));
r &= ~ICU_INT_ROUTE_PJ4_IRQ;
- __raw_writel(r, ICU_INT_CONF(irq));
+ __raw_writel(r, ICU_INT_CONF(d->irq));
}
-static void icu_unmask_irq(unsigned int irq)
+static void icu_unmask_irq(struct irq_data *d)
{
- uint32_t r = __raw_readl(ICU_INT_CONF(irq));
+ uint32_t r = __raw_readl(ICU_INT_CONF(d->irq));
r |= ICU_INT_ROUTE_PJ4_IRQ;
- __raw_writel(r, ICU_INT_CONF(irq));
+ __raw_writel(r, ICU_INT_CONF(d->irq));
}
static struct irq_chip icu_irq_chip = {
.name = "icu_irq",
- .mask = icu_mask_irq,
- .mask_ack = icu_mask_irq,
- .unmask = icu_unmask_irq,
+ .irq_mask = icu_mask_irq,
+ .irq_mask_ack = icu_mask_irq,
+ .irq_unmask = icu_unmask_irq,
};
-static void pmic_irq_ack(unsigned int irq)
+static void pmic_irq_ack(struct irq_data *d)
{
- if (irq == IRQ_MMP2_PMIC)
+ if (d->irq == IRQ_MMP2_PMIC)
mmp2_clear_pmic_int();
}
#define SECOND_IRQ_MASK(_name_, irq_base, prefix) \
-static void _name_##_mask_irq(unsigned int irq) \
+static void _name_##_mask_irq(struct irq_data *d) \
{ \
uint32_t r; \
- r = __raw_readl(prefix##_MASK) | (1 << (irq - irq_base)); \
+ r = __raw_readl(prefix##_MASK) | (1 << (d->irq - irq_base)); \
__raw_writel(r, prefix##_MASK); \
}
#define SECOND_IRQ_UNMASK(_name_, irq_base, prefix) \
-static void _name_##_unmask_irq(unsigned int irq) \
+static void _name_##_unmask_irq(struct irq_data *d) \
{ \
uint32_t r; \
- r = __raw_readl(prefix##_MASK) & ~(1 << (irq - irq_base)); \
+ r = __raw_readl(prefix##_MASK) & ~(1 << (d->irq - irq_base)); \
__raw_writel(r, prefix##_MASK); \
}
@@ -88,8 +88,8 @@ SECOND_IRQ_UNMASK(_name_, irq_base, prefix) \
SECOND_IRQ_DEMUX(_name_, irq_base, prefix) \
static struct irq_chip _name_##_irq_chip = { \
.name = #_name_, \
- .mask = _name_##_mask_irq, \
- .unmask = _name_##_unmask_irq, \
+ .irq_mask = _name_##_mask_irq, \
+ .irq_unmask = _name_##_unmask_irq, \
}
SECOND_IRQ_CHIP(pmic, IRQ_MMP2_PMIC_BASE, MMP2_ICU_INT4);
@@ -103,10 +103,12 @@ static void init_mux_irq(struct irq_chip *chip, int start, int num)
int irq;
for (irq = start; num > 0; irq++, num--) {
+ struct irq_data *d = irq_get_irq_data(irq);
+
/* mask and clear the IRQ */
- chip->mask(irq);
- if (chip->ack)
- chip->ack(irq);
+ chip->irq_mask(d);
+ if (chip->irq_ack)
+ chip->irq_ack(d);
set_irq_chip(irq, chip);
set_irq_flags(irq, IRQF_VALID);
@@ -119,7 +121,7 @@ void __init mmp2_init_icu(void)
int irq;
for (irq = 0; irq < IRQ_MMP2_MUX_BASE; irq++) {
- icu_mask_irq(irq);
+ icu_mask_irq(irq_get_irq_data(irq));
set_irq_chip(irq, &icu_irq_chip);
set_irq_flags(irq, IRQF_VALID);
@@ -139,7 +141,7 @@ void __init mmp2_init_icu(void)
/* NOTE: IRQ_MMP2_PMIC requires the PMIC MFPR register
* to be written to clear the interrupt
*/
- pmic_irq_chip.ack = pmic_irq_ack;
+ pmic_irq_chip.irq_ack = pmic_irq_ack;
init_mux_irq(&pmic_irq_chip, IRQ_MMP2_PMIC_BASE, 2);
init_mux_irq(&rtc_irq_chip, IRQ_MMP2_RTC_BASE, 2);
diff --git a/arch/arm/mach-mmp/irq-pxa168.c b/arch/arm/mach-mmp/irq-pxa168.c
index 52ff2f0..f86b450 100644
--- a/arch/arm/mach-mmp/irq-pxa168.c
+++ b/arch/arm/mach-mmp/irq-pxa168.c
@@ -25,21 +25,21 @@
#define PRIORITY_DEFAULT 0x1
#define PRIORITY_NONE 0x0 /* means IRQ disabled */
-static void icu_mask_irq(unsigned int irq)
+static void icu_mask_irq(struct irq_data *d)
{
- __raw_writel(PRIORITY_NONE, ICU_INT_CONF(irq));
+ __raw_writel(PRIORITY_NONE, ICU_INT_CONF(d->irq));
}
-static void icu_unmask_irq(unsigned int irq)
+static void icu_unmask_irq(struct irq_data *d)
{
- __raw_writel(IRQ_ROUTE_TO_AP | PRIORITY_DEFAULT, ICU_INT_CONF(irq));
+ __raw_writel(IRQ_ROUTE_TO_AP | PRIORITY_DEFAULT, ICU_INT_CONF(d->irq));
}
static struct irq_chip icu_irq_chip = {
- .name = "icu_irq",
- .ack = icu_mask_irq,
- .mask = icu_mask_irq,
- .unmask = icu_unmask_irq,
+ .name = "icu_irq",
+ .irq_ack = icu_mask_irq,
+ .irq_mask = icu_mask_irq,
+ .irq_unmask = icu_unmask_irq,
};
void __init icu_init_irq(void)
@@ -47,7 +47,7 @@ void __init icu_init_irq(void)
int irq;
for (irq = 0; irq < 64; irq++) {
- icu_mask_irq(irq);
+ icu_mask_irq(irq_get_irq_data(irq));
set_irq_chip(irq, &icu_irq_chip);
set_irq_handler(irq, handle_level_irq);
set_irq_flags(irq, IRQF_VALID);
diff --git a/arch/arm/mach-msm/board-qsd8x50.c b/arch/arm/mach-msm/board-qsd8x50.c
index 2e83913..6dde818 100644
--- a/arch/arm/mach-msm/board-qsd8x50.c
+++ b/arch/arm/mach-msm/board-qsd8x50.c
@@ -43,7 +43,7 @@ static const unsigned qsd8x50_surf_smc91x_gpio __initdata = 156;
* at run-time: they vary from board to board, and the true
* configuration won't be known until boot.
*/
-static struct resource smc91x_resources[] __initdata = {
+static struct resource smc91x_resources[] = {
[0] = {
.flags = IORESOURCE_MEM,
},
@@ -52,7 +52,7 @@ static struct resource smc91x_resources[] __initdata = {
},
};
-static struct platform_device smc91x_device __initdata = {
+static struct platform_device smc91x_device = {
.name = "smc91x",
.id = 0,
.num_resources = ARRAY_SIZE(smc91x_resources),
diff --git a/arch/arm/mach-msm/board-trout-gpio.c b/arch/arm/mach-msm/board-trout-gpio.c
index f8c09ef..a604ec1 100644
--- a/arch/arm/mach-msm/board-trout-gpio.c
+++ b/arch/arm/mach-msm/board-trout-gpio.c
@@ -113,52 +113,52 @@ static struct msm_gpio_chip msm_gpio_banks[] = {
TROUT_GPIO_BANK("VIRTUAL", 0x12, TROUT_GPIO_VIRTUAL_BASE, 0),
};
-static void trout_gpio_irq_ack(unsigned int irq)
+static void trout_gpio_irq_ack(struct irq_data *d)
{
- int bank = TROUT_INT_TO_BANK(irq);
- uint8_t mask = TROUT_INT_TO_MASK(irq);
+ int bank = TROUT_INT_TO_BANK(d->irq);
+ uint8_t mask = TROUT_INT_TO_MASK(d->irq);
int reg = TROUT_BANK_TO_STAT_REG(bank);
- /*printk(KERN_INFO "trout_gpio_irq_ack irq %d\n", irq);*/
+ /*printk(KERN_INFO "trout_gpio_irq_ack irq %d\n", d->irq);*/
writeb(mask, TROUT_CPLD_BASE + reg);
}
-static void trout_gpio_irq_mask(unsigned int irq)
+static void trout_gpio_irq_mask(struct irq_data *d)
{
unsigned long flags;
uint8_t reg_val;
- int bank = TROUT_INT_TO_BANK(irq);
- uint8_t mask = TROUT_INT_TO_MASK(irq);
+ int bank = TROUT_INT_TO_BANK(d->irq);
+ uint8_t mask = TROUT_INT_TO_MASK(d->irq);
int reg = TROUT_BANK_TO_MASK_REG(bank);
local_irq_save(flags);
reg_val = trout_int_mask[bank] |= mask;
/*printk(KERN_INFO "trout_gpio_irq_mask irq %d => %d:%02x\n",
- irq, bank, reg_val);*/
+ d->irq, bank, reg_val);*/
writeb(reg_val, TROUT_CPLD_BASE + reg);
local_irq_restore(flags);
}
-static void trout_gpio_irq_unmask(unsigned int irq)
+static void trout_gpio_irq_unmask(struct irq_data *d)
{
unsigned long flags;
uint8_t reg_val;
- int bank = TROUT_INT_TO_BANK(irq);
- uint8_t mask = TROUT_INT_TO_MASK(irq);
+ int bank = TROUT_INT_TO_BANK(d->irq);
+ uint8_t mask = TROUT_INT_TO_MASK(d->irq);
int reg = TROUT_BANK_TO_MASK_REG(bank);
local_irq_save(flags);
reg_val = trout_int_mask[bank] &= ~mask;
/*printk(KERN_INFO "trout_gpio_irq_unmask irq %d => %d:%02x\n",
- irq, bank, reg_val);*/
+ d->irq, bank, reg_val);*/
writeb(reg_val, TROUT_CPLD_BASE + reg);
local_irq_restore(flags);
}
-int trout_gpio_irq_set_wake(unsigned int irq, unsigned int on)
+int trout_gpio_irq_set_wake(struct irq_data *d, unsigned int on)
{
unsigned long flags;
- int bank = TROUT_INT_TO_BANK(irq);
- uint8_t mask = TROUT_INT_TO_MASK(irq);
+ int bank = TROUT_INT_TO_BANK(d->irq);
+ uint8_t mask = TROUT_INT_TO_MASK(d->irq);
local_irq_save(flags);
if(on)
@@ -198,15 +198,15 @@ static void trout_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
}
int_base += TROUT_INT_BANK0_COUNT;
}
- desc->chip->ack(irq);
+ desc->irq_data.chip->irq_ack(&desc->irq_data);
}
static struct irq_chip trout_gpio_irq_chip = {
- .name = "troutgpio",
- .ack = trout_gpio_irq_ack,
- .mask = trout_gpio_irq_mask,
- .unmask = trout_gpio_irq_unmask,
- .set_wake = trout_gpio_irq_set_wake,
+ .name = "troutgpio",
+ .irq_ack = trout_gpio_irq_ack,
+ .irq_mask = trout_gpio_irq_mask,
+ .irq_unmask = trout_gpio_irq_unmask,
+ .irq_set_wake = trout_gpio_irq_set_wake,
};
/*
diff --git a/arch/arm/mach-msm/gpio.c b/arch/arm/mach-msm/gpio.c
index 33051b5..176af9d 100644
--- a/arch/arm/mach-msm/gpio.c
+++ b/arch/arm/mach-msm/gpio.c
@@ -225,21 +225,21 @@ struct msm_gpio_chip msm_gpio_chips[] = {
#endif
};
-static void msm_gpio_irq_ack(unsigned int irq)
+static void msm_gpio_irq_ack(struct irq_data *d)
{
unsigned long irq_flags;
- struct msm_gpio_chip *msm_chip = get_irq_chip_data(irq);
+ struct msm_gpio_chip *msm_chip = irq_data_get_irq_chip_data(d);
spin_lock_irqsave(&msm_chip->lock, irq_flags);
msm_gpio_clear_detect_status(msm_chip,
- irq - gpio_to_irq(msm_chip->chip.base));
+ d->irq - gpio_to_irq(msm_chip->chip.base));
spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
}
-static void msm_gpio_irq_mask(unsigned int irq)
+static void msm_gpio_irq_mask(struct irq_data *d)
{
unsigned long irq_flags;
- struct msm_gpio_chip *msm_chip = get_irq_chip_data(irq);
- unsigned offset = irq - gpio_to_irq(msm_chip->chip.base);
+ struct msm_gpio_chip *msm_chip = irq_data_get_irq_chip_data(d);
+ unsigned offset = d->irq - gpio_to_irq(msm_chip->chip.base);
spin_lock_irqsave(&msm_chip->lock, irq_flags);
/* level triggered interrupts are also latched */
@@ -250,11 +250,11 @@ static void msm_gpio_irq_mask(unsigned int irq)
spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
}
-static void msm_gpio_irq_unmask(unsigned int irq)
+static void msm_gpio_irq_unmask(struct irq_data *d)
{
unsigned long irq_flags;
- struct msm_gpio_chip *msm_chip = get_irq_chip_data(irq);
- unsigned offset = irq - gpio_to_irq(msm_chip->chip.base);
+ struct msm_gpio_chip *msm_chip = irq_data_get_irq_chip_data(d);
+ unsigned offset = d->irq - gpio_to_irq(msm_chip->chip.base);
spin_lock_irqsave(&msm_chip->lock, irq_flags);
/* level triggered interrupts are also latched */
@@ -265,11 +265,11 @@ static void msm_gpio_irq_unmask(unsigned int irq)
spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
}
-static int msm_gpio_irq_set_wake(unsigned int irq, unsigned int on)
+static int msm_gpio_irq_set_wake(struct irq_data *d, unsigned int on)
{
unsigned long irq_flags;
- struct msm_gpio_chip *msm_chip = get_irq_chip_data(irq);
- unsigned offset = irq - gpio_to_irq(msm_chip->chip.base);
+ struct msm_gpio_chip *msm_chip = irq_data_get_irq_chip_data(d);
+ unsigned offset = d->irq - gpio_to_irq(msm_chip->chip.base);
spin_lock_irqsave(&msm_chip->lock, irq_flags);
@@ -282,21 +282,21 @@ static int msm_gpio_irq_set_wake(unsigned int irq, unsigned int on)
return 0;
}
-static int msm_gpio_irq_set_type(unsigned int irq, unsigned int flow_type)
+static int msm_gpio_irq_set_type(struct irq_data *d, unsigned int flow_type)
{
unsigned long irq_flags;
- struct msm_gpio_chip *msm_chip = get_irq_chip_data(irq);
- unsigned offset = irq - gpio_to_irq(msm_chip->chip.base);
+ struct msm_gpio_chip *msm_chip = irq_data_get_irq_chip_data(d);
+ unsigned offset = d->irq - gpio_to_irq(msm_chip->chip.base);
unsigned val, mask = BIT(offset);
spin_lock_irqsave(&msm_chip->lock, irq_flags);
val = readl(msm_chip->regs.int_edge);
if (flow_type & IRQ_TYPE_EDGE_BOTH) {
writel(val | mask, msm_chip->regs.int_edge);
- irq_desc[irq].handle_irq = handle_edge_irq;
+ irq_desc[d->irq].handle_irq = handle_edge_irq;
} else {
writel(val & ~mask, msm_chip->regs.int_edge);
- irq_desc[irq].handle_irq = handle_level_irq;
+ irq_desc[d->irq].handle_irq = handle_level_irq;
}
if ((flow_type & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH) {
msm_chip->both_edge_detect |= mask;
@@ -333,16 +333,16 @@ static void msm_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
msm_chip->chip.base + j);
}
}
- desc->chip->ack(irq);
+ desc->irq_data.chip->irq_ack(&desc->irq_data);
}
static struct irq_chip msm_gpio_irq_chip = {
- .name = "msmgpio",
- .ack = msm_gpio_irq_ack,
- .mask = msm_gpio_irq_mask,
- .unmask = msm_gpio_irq_unmask,
- .set_wake = msm_gpio_irq_set_wake,
- .set_type = msm_gpio_irq_set_type,
+ .name = "msmgpio",
+ .irq_ack = msm_gpio_irq_ack,
+ .irq_mask = msm_gpio_irq_mask,
+ .irq_unmask = msm_gpio_irq_unmask,
+ .irq_set_wake = msm_gpio_irq_set_wake,
+ .irq_set_type = msm_gpio_irq_set_type,
};
static int __init msm_init_gpio(void)
diff --git a/arch/arm/mach-msm/irq-vic.c b/arch/arm/mach-msm/irq-vic.c
index 99f2c34..68c28bb 100644
--- a/arch/arm/mach-msm/irq-vic.c
+++ b/arch/arm/mach-msm/irq-vic.c
@@ -226,19 +226,18 @@ static inline void msm_irq_write_all_regs(void __iomem *base, unsigned int val)
writel(val, base + (i * 4));
}
-static void msm_irq_ack(unsigned int irq)
+static void msm_irq_ack(struct irq_data *d)
{
- void __iomem *reg = VIC_INT_TO_REG_ADDR(VIC_INT_CLEAR0, irq);
- irq = 1 << (irq & 31);
- writel(irq, reg);
+ void __iomem *reg = VIC_INT_TO_REG_ADDR(VIC_INT_CLEAR0, d->irq);
+ writel(1 << (d->irq & 31), reg);
}
-static void msm_irq_mask(unsigned int irq)
+static void msm_irq_mask(struct irq_data *d)
{
- void __iomem *reg = VIC_INT_TO_REG_ADDR(VIC_INT_ENCLEAR0, irq);
- unsigned index = VIC_INT_TO_REG_INDEX(irq);
- uint32_t mask = 1UL << (irq & 31);
- int smsm_irq = msm_irq_to_smsm[irq];
+ void __iomem *reg = VIC_INT_TO_REG_ADDR(VIC_INT_ENCLEAR0, d->irq);
+ unsigned index = VIC_INT_TO_REG_INDEX(d->irq);
+ uint32_t mask = 1UL << (d->irq & 31);
+ int smsm_irq = msm_irq_to_smsm[d->irq];
msm_irq_shadow_reg[index].int_en[0] &= ~mask;
writel(mask, reg);
@@ -250,12 +249,12 @@ static void msm_irq_mask(unsigned int irq)
}
}
-static void msm_irq_unmask(unsigned int irq)
+static void msm_irq_unmask(struct irq_data *d)
{
- void __iomem *reg = VIC_INT_TO_REG_ADDR(VIC_INT_ENSET0, irq);
- unsigned index = VIC_INT_TO_REG_INDEX(irq);
- uint32_t mask = 1UL << (irq & 31);
- int smsm_irq = msm_irq_to_smsm[irq];
+ void __iomem *reg = VIC_INT_TO_REG_ADDR(VIC_INT_ENSET0, d->irq);
+ unsigned index = VIC_INT_TO_REG_INDEX(d->irq);
+ uint32_t mask = 1UL << (d->irq & 31);
+ int smsm_irq = msm_irq_to_smsm[d->irq];
msm_irq_shadow_reg[index].int_en[0] |= mask;
writel(mask, reg);
@@ -268,14 +267,14 @@ static void msm_irq_unmask(unsigned int irq)
}
}
-static int msm_irq_set_wake(unsigned int irq, unsigned int on)
+static int msm_irq_set_wake(struct irq_data *d, unsigned int on)
{
- unsigned index = VIC_INT_TO_REG_INDEX(irq);
- uint32_t mask = 1UL << (irq & 31);
- int smsm_irq = msm_irq_to_smsm[irq];
+ unsigned index = VIC_INT_TO_REG_INDEX(d->irq);
+ uint32_t mask = 1UL << (d->irq & 31);
+ int smsm_irq = msm_irq_to_smsm[d->irq];
if (smsm_irq == 0) {
- printk(KERN_ERR "msm_irq_set_wake: bad wakeup irq %d\n", irq);
+ printk(KERN_ERR "msm_irq_set_wake: bad wakeup irq %d\n", d->irq);
return -EINVAL;
}
if (on)
@@ -294,12 +293,12 @@ static int msm_irq_set_wake(unsigned int irq, unsigned int on)
return 0;
}
-static int msm_irq_set_type(unsigned int irq, unsigned int flow_type)
+static int msm_irq_set_type(struct irq_data *d, unsigned int flow_type)
{
- void __iomem *treg = VIC_INT_TO_REG_ADDR(VIC_INT_TYPE0, irq);
- void __iomem *preg = VIC_INT_TO_REG_ADDR(VIC_INT_POLARITY0, irq);
- unsigned index = VIC_INT_TO_REG_INDEX(irq);
- int b = 1 << (irq & 31);
+ void __iomem *treg = VIC_INT_TO_REG_ADDR(VIC_INT_TYPE0, d->irq);
+ void __iomem *preg = VIC_INT_TO_REG_ADDR(VIC_INT_POLARITY0, d->irq);
+ unsigned index = VIC_INT_TO_REG_INDEX(d->irq);
+ int b = 1 << (d->irq & 31);
uint32_t polarity;
uint32_t type;
@@ -314,11 +313,11 @@ static int msm_irq_set_type(unsigned int irq, unsigned int flow_type)
type = msm_irq_shadow_reg[index].int_type;
if (flow_type & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)) {
type |= b;
- irq_desc[irq].handle_irq = handle_edge_irq;
+ irq_desc[d->irq].handle_irq = handle_edge_irq;
}
if (flow_type & (IRQF_TRIGGER_HIGH | IRQF_TRIGGER_LOW)) {
type &= ~b;
- irq_desc[irq].handle_irq = handle_level_irq;
+ irq_desc[d->irq].handle_irq = handle_level_irq;
}
writel(type, treg);
msm_irq_shadow_reg[index].int_type = type;
@@ -326,13 +325,13 @@ static int msm_irq_set_type(unsigned int irq, unsigned int flow_type)
}
static struct irq_chip msm_irq_chip = {
- .name = "msm",
- .disable = msm_irq_mask,
- .ack = msm_irq_ack,
- .mask = msm_irq_mask,
- .unmask = msm_irq_unmask,
- .set_wake = msm_irq_set_wake,
- .set_type = msm_irq_set_type,
+ .name = "msm",
+ .irq_disable = msm_irq_mask,
+ .irq_ack = msm_irq_ack,
+ .irq_mask = msm_irq_mask,
+ .irq_unmask = msm_irq_unmask,
+ .irq_set_wake = msm_irq_set_wake,
+ .irq_set_type = msm_irq_set_type,
};
void __init msm_init_irq(void)
diff --git a/arch/arm/mach-msm/irq.c b/arch/arm/mach-msm/irq.c
index 6c8d5f8..0b27d89 100644
--- a/arch/arm/mach-msm/irq.c
+++ b/arch/arm/mach-msm/irq.c
@@ -64,35 +64,34 @@
#define VIC_VECTPRIORITY(n) VIC_REG(0x0200+((n) * 4))
#define VIC_VECTADDR(n) VIC_REG(0x0400+((n) * 4))
-static void msm_irq_ack(unsigned int irq)
+static void msm_irq_ack(struct irq_data *d)
{
- void __iomem *reg = VIC_INT_CLEAR0 + ((irq & 32) ? 4 : 0);
- irq = 1 << (irq & 31);
- writel(irq, reg);
+ void __iomem *reg = VIC_INT_CLEAR0 + ((d->irq & 32) ? 4 : 0);
+ writel(1 << (d->irq & 31), reg);
}
-static void msm_irq_mask(unsigned int irq)
+static void msm_irq_mask(struct irq_data *d)
{
- void __iomem *reg = VIC_INT_ENCLEAR0 + ((irq & 32) ? 4 : 0);
- writel(1 << (irq & 31), reg);
+ void __iomem *reg = VIC_INT_ENCLEAR0 + ((d->irq & 32) ? 4 : 0);
+ writel(1 << (d->irq & 31), reg);
}
-static void msm_irq_unmask(unsigned int irq)
+static void msm_irq_unmask(struct irq_data *d)
{
- void __iomem *reg = VIC_INT_ENSET0 + ((irq & 32) ? 4 : 0);
- writel(1 << (irq & 31), reg);
+ void __iomem *reg = VIC_INT_ENSET0 + ((d->irq & 32) ? 4 : 0);
+ writel(1 << (d->irq & 31), reg);
}
-static int msm_irq_set_wake(unsigned int irq, unsigned int on)
+static int msm_irq_set_wake(struct irq_data *d, unsigned int on)
{
return -EINVAL;
}
-static int msm_irq_set_type(unsigned int irq, unsigned int flow_type)
+static int msm_irq_set_type(struct irq_data *d, unsigned int flow_type)
{
- void __iomem *treg = VIC_INT_TYPE0 + ((irq & 32) ? 4 : 0);
- void __iomem *preg = VIC_INT_POLARITY0 + ((irq & 32) ? 4 : 0);
- int b = 1 << (irq & 31);
+ void __iomem *treg = VIC_INT_TYPE0 + ((d->irq & 32) ? 4 : 0);
+ void __iomem *preg = VIC_INT_POLARITY0 + ((d->irq & 32) ? 4 : 0);
+ int b = 1 << (d->irq & 31);
if (flow_type & (IRQF_TRIGGER_FALLING | IRQF_TRIGGER_LOW))
writel(readl(preg) | b, preg);
@@ -101,22 +100,22 @@ static int msm_irq_set_type(unsigned int irq, unsigned int flow_type)
if (flow_type & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)) {
writel(readl(treg) | b, treg);
- irq_desc[irq].handle_irq = handle_edge_irq;
+ irq_desc[d->irq].handle_irq = handle_edge_irq;
}
if (flow_type & (IRQF_TRIGGER_HIGH | IRQF_TRIGGER_LOW)) {
writel(readl(treg) & (~b), treg);
- irq_desc[irq].handle_irq = handle_level_irq;
+ irq_desc[d->irq].handle_irq = handle_level_irq;
}
return 0;
}
static struct irq_chip msm_irq_chip = {
- .name = "msm",
- .ack = msm_irq_ack,
- .mask = msm_irq_mask,
- .unmask = msm_irq_unmask,
- .set_wake = msm_irq_set_wake,
- .set_type = msm_irq_set_type,
+ .name = "msm",
+ .irq_ack = msm_irq_ack,
+ .irq_mask = msm_irq_mask,
+ .irq_unmask = msm_irq_unmask,
+ .irq_set_wake = msm_irq_set_wake,
+ .irq_set_type = msm_irq_set_type,
};
void __init msm_init_irq(void)
diff --git a/arch/arm/mach-msm/sirc.c b/arch/arm/mach-msm/sirc.c
index 152eefd..11b54c7 100644
--- a/arch/arm/mach-msm/sirc.c
+++ b/arch/arm/mach-msm/sirc.c
@@ -42,12 +42,11 @@ static struct sirc_cascade_regs sirc_reg_table[] = {
/* Mask off the given interrupt. Keep the int_enable mask in sync with
the enable reg, so it can be restored after power collapse. */
-static void sirc_irq_mask(unsigned int irq)
+static void sirc_irq_mask(struct irq_data *d)
{
unsigned int mask;
-
- mask = 1 << (irq - FIRST_SIRC_IRQ);
+ mask = 1 << (d->irq - FIRST_SIRC_IRQ);
writel(mask, sirc_regs.int_enable_clear);
int_enable &= ~mask;
return;
@@ -55,31 +54,31 @@ static void sirc_irq_mask(unsigned int irq)
/* Unmask the given interrupt. Keep the int_enable mask in sync with
the enable reg, so it can be restored after power collapse. */
-static void sirc_irq_unmask(unsigned int irq)
+static void sirc_irq_unmask(struct irq_data *d)
{
unsigned int mask;
- mask = 1 << (irq - FIRST_SIRC_IRQ);
+ mask = 1 << (d->irq - FIRST_SIRC_IRQ);
writel(mask, sirc_regs.int_enable_set);
int_enable |= mask;
return;
}
-static void sirc_irq_ack(unsigned int irq)
+static void sirc_irq_ack(struct irq_data *d)
{
unsigned int mask;
- mask = 1 << (irq - FIRST_SIRC_IRQ);
+ mask = 1 << (d->irq - FIRST_SIRC_IRQ);
writel(mask, sirc_regs.int_clear);
return;
}
-static int sirc_irq_set_wake(unsigned int irq, unsigned int on)
+static int sirc_irq_set_wake(struct irq_data *d, unsigned int on)
{
unsigned int mask;
/* Used to set the interrupt enable mask during power collapse. */
- mask = 1 << (irq - FIRST_SIRC_IRQ);
+ mask = 1 << (d->irq - FIRST_SIRC_IRQ);
if (on)
wake_enable |= mask;
else
@@ -88,12 +87,12 @@ static int sirc_irq_set_wake(unsigned int irq, unsigned int on)
return 0;
}
-static int sirc_irq_set_type(unsigned int irq, unsigned int flow_type)
+static int sirc_irq_set_type(struct irq_data *d, unsigned int flow_type)
{
unsigned int mask;
unsigned int val;
- mask = 1 << (irq - FIRST_SIRC_IRQ);
+ mask = 1 << (d->irq - FIRST_SIRC_IRQ);
val = readl(sirc_regs.int_polarity);
if (flow_type & (IRQF_TRIGGER_LOW | IRQF_TRIGGER_FALLING))
@@ -106,10 +105,10 @@ static int sirc_irq_set_type(unsigned int irq, unsigned int flow_type)
val = readl(sirc_regs.int_type);
if (flow_type & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)) {
val |= mask;
- irq_desc[irq].handle_irq = handle_edge_irq;
+ irq_desc[d->irq].handle_irq = handle_edge_irq;
} else {
val &= ~mask;
- irq_desc[irq].handle_irq = handle_level_irq;
+ irq_desc[d->irq].handle_irq = handle_level_irq;
}
writel(val, sirc_regs.int_type);
@@ -139,16 +138,16 @@ static void sirc_irq_handler(unsigned int irq, struct irq_desc *desc)
;
generic_handle_irq(sirq+FIRST_SIRC_IRQ);
- desc->chip->ack(irq);
+ desc->irq_data.chip->irq_ack(&desc->irq_data);
}
static struct irq_chip sirc_irq_chip = {
- .name = "sirc",
- .ack = sirc_irq_ack,
- .mask = sirc_irq_mask,
- .unmask = sirc_irq_unmask,
- .set_wake = sirc_irq_set_wake,
- .set_type = sirc_irq_set_type,
+ .name = "sirc",
+ .irq_ack = sirc_irq_ack,
+ .irq_mask = sirc_irq_mask,
+ .irq_unmask = sirc_irq_unmask,
+ .irq_set_wake = sirc_irq_set_wake,
+ .irq_set_type = sirc_irq_set_type,
};
void __init msm_init_sirc(void)
diff --git a/arch/arm/mach-mx3/mach-mx31_3ds.c b/arch/arm/mach-mx3/mach-mx31_3ds.c
index 899a969..0d65db8 100644
--- a/arch/arm/mach-mx3/mach-mx31_3ds.c
+++ b/arch/arm/mach-mx3/mach-mx31_3ds.c
@@ -147,10 +147,10 @@ static struct mc13783_regulator_init_data mx31_3ds_regulators[] = {
.init_data = &pwgtx_init,
}, {
- .id = MC13783_REGU_GPO1, /* Turn on 1.8V */
+ .id = MC13783_REG_GPO1, /* Turn on 1.8V */
.init_data = &gpo_init,
}, {
- .id = MC13783_REGU_GPO3, /* Turn on 3.3V */
+ .id = MC13783_REG_GPO3, /* Turn on 3.3V */
.init_data = &gpo_init,
},
};
diff --git a/arch/arm/mach-mx3/mach-mx31ads.c b/arch/arm/mach-mx3/mach-mx31ads.c
index b993b9b..88b97d6 100644
--- a/arch/arm/mach-mx3/mach-mx31ads.c
+++ b/arch/arm/mach-mx3/mach-mx31ads.c
@@ -162,9 +162,9 @@ static void mx31ads_expio_irq_handler(u32 irq, struct irq_desc *desc)
* Disable an expio pin's interrupt by setting the bit in the imr.
* @param irq an expio virtual irq number
*/
-static void expio_mask_irq(u32 irq)
+static void expio_mask_irq(struct irq_data *d)
{
- u32 expio = MXC_IRQ_TO_EXPIO(irq);
+ u32 expio = MXC_IRQ_TO_EXPIO(d->irq);
/* mask the interrupt */
__raw_writew(1 << expio, PBC_INTMASK_CLEAR_REG);
__raw_readw(PBC_INTMASK_CLEAR_REG);
@@ -174,9 +174,9 @@ static void expio_mask_irq(u32 irq)
* Acknowledge an expanded io pin's interrupt by clearing the bit in the isr.
* @param irq an expanded io virtual irq number
*/
-static void expio_ack_irq(u32 irq)
+static void expio_ack_irq(struct irq_data *d)
{
- u32 expio = MXC_IRQ_TO_EXPIO(irq);
+ u32 expio = MXC_IRQ_TO_EXPIO(d->irq);
/* clear the interrupt status */
__raw_writew(1 << expio, PBC_INTSTATUS_REG);
}
@@ -185,18 +185,18 @@ static void expio_ack_irq(u32 irq)
* Enable a expio pin's interrupt by clearing the bit in the imr.
* @param irq a expio virtual irq number
*/
-static void expio_unmask_irq(u32 irq)
+static void expio_unmask_irq(struct irq_data *d)
{
- u32 expio = MXC_IRQ_TO_EXPIO(irq);
+ u32 expio = MXC_IRQ_TO_EXPIO(d->irq);
/* unmask the interrupt */
__raw_writew(1 << expio, PBC_INTMASK_SET_REG);
}
static struct irq_chip expio_irq_chip = {
.name = "EXPIO(CPLD)",
- .ack = expio_ack_irq,
- .mask = expio_mask_irq,
- .unmask = expio_unmask_irq,
+ .irq_ack = expio_ack_irq,
+ .irq_mask = expio_mask_irq,
+ .irq_unmask = expio_unmask_irq,
};
static void __init mx31ads_init_expio(void)
diff --git a/arch/arm/mach-mx5/Kconfig b/arch/arm/mach-mx5/Kconfig
index 55254b6..de4fa992f 100644
--- a/arch/arm/mach-mx5/Kconfig
+++ b/arch/arm/mach-mx5/Kconfig
@@ -50,6 +50,7 @@ config MACH_MX51_BABBAGE
config MACH_MX51_3DS
bool "Support MX51PDK (3DS)"
select SOC_IMX51
+ select IMX_HAVE_PLATFORM_IMX_KEYPAD
select IMX_HAVE_PLATFORM_IMX_UART
select IMX_HAVE_PLATFORM_SDHCI_ESDHC_IMX
select IMX_HAVE_PLATFORM_SPI_IMX
@@ -77,6 +78,7 @@ choice
config MACH_EUKREA_MBIMX51_BASEBOARD
prompt "Eukrea MBIMX51 development board"
bool
+ select IMX_HAVE_PLATFORM_IMX_KEYPAD
select IMX_HAVE_PLATFORM_SDHCI_ESDHC_IMX
help
This adds board specific devices that can be found on Eukrea's
@@ -124,10 +126,28 @@ config MACH_MX53_EVK
bool "Support MX53 EVK platforms"
select SOC_IMX53
select IMX_HAVE_PLATFORM_IMX_UART
+ select IMX_HAVE_PLATFORM_IMX_I2C
+ select IMX_HAVE_PLATFORM_SDHCI_ESDHC_IMX
+ select IMX_HAVE_PLATFORM_SPI_IMX
help
Include support for MX53 EVK platform. This includes specific
configurations for the board and its peripherals.
+config MACH_MX53_SMD
+ bool "Support MX53 SMD platforms"
+ select SOC_IMX53
+ select IMX_HAVE_PLATFORM_IMX_UART
+ help
+ Include support for MX53 SMD platform. This includes specific
+ configurations for the board and its peripherals.
+
+config MACH_MX53_LOCO
+ bool "Support MX53 LOCO platforms"
+ select SOC_IMX53
+ select IMX_HAVE_PLATFORM_IMX_UART
+ help
+ Include support for MX53 LOCO platform. This includes specific
+ configurations for the board and its peripherals.
config MACH_MX50_RDP
bool "Support MX50 reference design platform"
diff --git a/arch/arm/mach-mx5/Makefile b/arch/arm/mach-mx5/Makefile
index 0c398ba..0d43be9 100644
--- a/arch/arm/mach-mx5/Makefile
+++ b/arch/arm/mach-mx5/Makefile
@@ -10,6 +10,8 @@ obj-$(CONFIG_CPU_FREQ_IMX) += cpu_op-mx51.o
obj-$(CONFIG_MACH_MX51_BABBAGE) += board-mx51_babbage.o
obj-$(CONFIG_MACH_MX51_3DS) += board-mx51_3ds.o
obj-$(CONFIG_MACH_MX53_EVK) += board-mx53_evk.o
+obj-$(CONFIG_MACH_MX53_SMD) += board-mx53_smd.o
+obj-$(CONFIG_MACH_MX53_LOCO) += board-mx53_loco.o
obj-$(CONFIG_MACH_EUKREA_CPUIMX51) += board-cpuimx51.o
obj-$(CONFIG_MACH_EUKREA_MBIMX51_BASEBOARD) += eukrea_mbimx51-baseboard.o
obj-$(CONFIG_MACH_EUKREA_CPUIMX51SD) += board-cpuimx51sd.o
diff --git a/arch/arm/mach-mx5/board-mx51_3ds.c b/arch/arm/mach-mx5/board-mx51_3ds.c
index e42bd2e..49d6448 100644
--- a/arch/arm/mach-mx5/board-mx51_3ds.c
+++ b/arch/arm/mach-mx5/board-mx51_3ds.c
@@ -12,7 +12,6 @@
#include <linux/irq.h>
#include <linux/platform_device.h>
-#include <linux/input/matrix_keypad.h>
#include <linux/spi/spi.h>
#include <asm/mach-types.h>
@@ -120,14 +119,14 @@ static int mx51_3ds_board_keymap[] = {
KEY(3, 5, KEY_BACK)
};
-static struct matrix_keymap_data mx51_3ds_map_data = {
+static const struct matrix_keymap_data mx51_3ds_map_data __initconst = {
.keymap = mx51_3ds_board_keymap,
.keymap_size = ARRAY_SIZE(mx51_3ds_board_keymap),
};
static void mxc_init_keypad(void)
{
- mxc_register_device(&mxc_keypad_device, &mx51_3ds_map_data);
+ imx51_add_imx_keypad(&mx51_3ds_map_data);
}
#else
static inline void mxc_init_keypad(void)
diff --git a/arch/arm/mach-mx5/board-mx53_evk.c b/arch/arm/mach-mx5/board-mx53_evk.c
index fa97d0d..caee04c 100644
--- a/arch/arm/mach-mx5/board-mx53_evk.c
+++ b/arch/arm/mach-mx5/board-mx53_evk.c
@@ -21,6 +21,11 @@
#include <linux/init.h>
#include <linux/clk.h>
+#include <linux/fec.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/spi/flash.h>
+#include <linux/spi/spi.h>
#include <mach/common.h>
#include <mach/hardware.h>
#include <asm/mach-types.h>
@@ -29,6 +34,10 @@
#include <mach/imx-uart.h>
#include <mach/iomux-mx53.h>
+#define SMD_FEC_PHY_RST IMX_GPIO_NR(7, 6)
+#define EVK_ECSPI1_CS0 IMX_GPIO_NR(2, 30)
+#define EVK_ECSPI1_CS1 IMX_GPIO_NR(3, 19)
+
#include "crm_regs.h"
#include "devices-imx53.h"
@@ -47,6 +56,14 @@ static iomux_v3_cfg_t mx53_evk_pads[] = {
MX53_PAD_ATA_CS_1__UART3_RXD,
MX53_PAD_ATA_DA_1__UART3_CTS,
MX53_PAD_ATA_DA_2__UART3_RTS,
+
+ MX53_PAD_EIM_D16__CSPI1_SCLK,
+ MX53_PAD_EIM_D17__CSPI1_MISO,
+ MX53_PAD_EIM_D18__CSPI1_MOSI,
+
+ /* ecspi chip select lines */
+ MX53_PAD_EIM_EB2__GPIO_2_30,
+ MX53_PAD_EIM_D19__GPIO_3_19,
};
static const struct imxuart_platform_data mx53_evk_uart_pdata __initconst = {
@@ -60,11 +77,68 @@ static inline void mx53_evk_init_uart(void)
imx53_add_imx_uart(2, &mx53_evk_uart_pdata);
}
+static const struct imxi2c_platform_data mx53_evk_i2c_data __initconst = {
+ .bitrate = 100000,
+};
+
+static inline void mx53_evk_fec_reset(void)
+{
+ int ret;
+
+ /* reset FEC PHY */
+ ret = gpio_request(SMD_FEC_PHY_RST, "fec-phy-reset");
+ if (ret) {
+ printk(KERN_ERR"failed to get GPIO_FEC_PHY_RESET: %d\n", ret);
+ return;
+ }
+ gpio_direction_output(SMD_FEC_PHY_RST, 0);
+ gpio_set_value(SMD_FEC_PHY_RST, 0);
+ msleep(1);
+ gpio_set_value(SMD_FEC_PHY_RST, 1);
+}
+
+static struct fec_platform_data mx53_evk_fec_pdata = {
+ .phy = PHY_INTERFACE_MODE_RMII,
+};
+
+static struct spi_board_info mx53_evk_spi_board_info[] __initdata = {
+ {
+ .modalias = "mtd_dataflash",
+ .max_speed_hz = 25000000,
+ .bus_num = 0,
+ .chip_select = 1,
+ .mode = SPI_MODE_0,
+ .platform_data = NULL,
+ },
+};
+
+static int mx53_evk_spi_cs[] = {
+ EVK_ECSPI1_CS0,
+ EVK_ECSPI1_CS1,
+};
+
+static const struct spi_imx_master mx53_evk_spi_data __initconst = {
+ .chipselect = mx53_evk_spi_cs,
+ .num_chipselect = ARRAY_SIZE(mx53_evk_spi_cs),
+};
+
static void __init mx53_evk_board_init(void)
{
mxc_iomux_v3_setup_multiple_pads(mx53_evk_pads,
ARRAY_SIZE(mx53_evk_pads));
mx53_evk_init_uart();
+ mx53_evk_fec_reset();
+ imx53_add_fec(&mx53_evk_fec_pdata);
+
+ imx53_add_imx_i2c(0, &mx53_evk_i2c_data);
+ imx53_add_imx_i2c(1, &mx53_evk_i2c_data);
+
+ imx53_add_sdhci_esdhc_imx(0, NULL);
+ imx53_add_sdhci_esdhc_imx(1, NULL);
+
+ spi_register_board_info(mx53_evk_spi_board_info,
+ ARRAY_SIZE(mx53_evk_spi_board_info));
+ imx53_add_ecspi(0, &mx53_evk_spi_data);
}
static void __init mx53_evk_timer_init(void)
diff --git a/arch/arm/mach-mx5/board-mx53_loco.c b/arch/arm/mach-mx5/board-mx53_loco.c
new file mode 100644
index 0000000..d1348e0
--- /dev/null
+++ b/arch/arm/mach-mx5/board-mx53_loco.c
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/init.h>
+#include <linux/clk.h>
+#include <linux/fec.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+
+#include <mach/common.h>
+#include <mach/hardware.h>
+#include <mach/imx-uart.h>
+#include <mach/iomux-mx53.h>
+
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/time.h>
+
+#include "crm_regs.h"
+#include "devices-imx53.h"
+
+#define LOCO_FEC_PHY_RST IMX_GPIO_NR(7, 6)
+
+static iomux_v3_cfg_t mx53_loco_pads[] = {
+ MX53_PAD_CSI0_D10__UART1_TXD,
+ MX53_PAD_CSI0_D11__UART1_RXD,
+ MX53_PAD_ATA_DIOW__UART1_TXD,
+ MX53_PAD_ATA_DMACK__UART1_RXD,
+
+ MX53_PAD_ATA_BUFFER_EN__UART2_RXD,
+ MX53_PAD_ATA_DMARQ__UART2_TXD,
+ MX53_PAD_ATA_DIOR__UART2_RTS,
+ MX53_PAD_ATA_INTRQ__UART2_CTS,
+
+ MX53_PAD_ATA_CS_0__UART3_TXD,
+ MX53_PAD_ATA_CS_1__UART3_RXD,
+ MX53_PAD_ATA_DA_1__UART3_CTS,
+ MX53_PAD_ATA_DA_2__UART3_RTS,
+};
+
+static const struct imxuart_platform_data mx53_loco_uart_data __initconst = {
+ .flags = IMXUART_HAVE_RTSCTS,
+};
+
+static inline void mx53_loco_init_uart(void)
+{
+ imx53_add_imx_uart(0, &mx53_loco_uart_data);
+ imx53_add_imx_uart(1, &mx53_loco_uart_data);
+ imx53_add_imx_uart(2, &mx53_loco_uart_data);
+}
+
+static inline void mx53_loco_fec_reset(void)
+{
+ int ret;
+
+ /* reset FEC PHY */
+ ret = gpio_request(LOCO_FEC_PHY_RST, "fec-phy-reset");
+ if (ret) {
+ printk(KERN_ERR"failed to get GPIO_FEC_PHY_RESET: %d\n", ret);
+ return;
+ }
+ gpio_direction_output(LOCO_FEC_PHY_RST, 0);
+ msleep(1);
+ gpio_set_value(LOCO_FEC_PHY_RST, 1);
+}
+
+static struct fec_platform_data mx53_loco_fec_data = {
+ .phy = PHY_INTERFACE_MODE_RMII,
+};
+
+static void __init mx53_loco_board_init(void)
+{
+ mxc_iomux_v3_setup_multiple_pads(mx53_loco_pads,
+ ARRAY_SIZE(mx53_loco_pads));
+ mx53_loco_init_uart();
+ mx53_loco_fec_reset();
+ imx53_add_fec(&mx53_loco_fec_data);
+}
+
+static void __init mx53_loco_timer_init(void)
+{
+ mx53_clocks_init(32768, 24000000, 0, 0);
+}
+
+static struct sys_timer mx53_loco_timer = {
+ .init = mx53_loco_timer_init,
+};
+
+MACHINE_START(MX53_LOCO, "Freescale MX53 LOCO Board")
+ .map_io = mx53_map_io,
+ .init_irq = mx53_init_irq,
+ .init_machine = mx53_loco_board_init,
+ .timer = &mx53_loco_timer,
+MACHINE_END
diff --git a/arch/arm/mach-mx5/board-mx53_smd.c b/arch/arm/mach-mx5/board-mx53_smd.c
new file mode 100644
index 0000000..7970f7a
--- /dev/null
+++ b/arch/arm/mach-mx5/board-mx53_smd.c
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/init.h>
+#include <linux/clk.h>
+#include <linux/fec.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+
+#include <mach/common.h>
+#include <mach/hardware.h>
+#include <mach/imx-uart.h>
+#include <mach/iomux-mx53.h>
+
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/time.h>
+
+#include "crm_regs.h"
+#include "devices-imx53.h"
+
+#define SMD_FEC_PHY_RST IMX_GPIO_NR(7, 6)
+
+static iomux_v3_cfg_t mx53_smd_pads[] = {
+ MX53_PAD_CSI0_D10__UART1_TXD,
+ MX53_PAD_CSI0_D11__UART1_RXD,
+ MX53_PAD_ATA_DIOW__UART1_TXD,
+ MX53_PAD_ATA_DMACK__UART1_RXD,
+
+ MX53_PAD_ATA_BUFFER_EN__UART2_RXD,
+ MX53_PAD_ATA_DMARQ__UART2_TXD,
+ MX53_PAD_ATA_DIOR__UART2_RTS,
+ MX53_PAD_ATA_INTRQ__UART2_CTS,
+
+ MX53_PAD_ATA_CS_0__UART3_TXD,
+ MX53_PAD_ATA_CS_1__UART3_RXD,
+ MX53_PAD_ATA_DA_1__UART3_CTS,
+ MX53_PAD_ATA_DA_2__UART3_RTS,
+};
+
+static const struct imxuart_platform_data mx53_smd_uart_data __initconst = {
+ .flags = IMXUART_HAVE_RTSCTS,
+};
+
+static inline void mx53_smd_init_uart(void)
+{
+ imx53_add_imx_uart(0, &mx53_smd_uart_data);
+ imx53_add_imx_uart(1, &mx53_smd_uart_data);
+ imx53_add_imx_uart(2, &mx53_smd_uart_data);
+}
+
+static inline void mx53_smd_fec_reset(void)
+{
+ int ret;
+
+ /* reset FEC PHY */
+ ret = gpio_request(SMD_FEC_PHY_RST, "fec-phy-reset");
+ if (ret) {
+ printk(KERN_ERR"failed to get GPIO_FEC_PHY_RESET: %d\n", ret);
+ return;
+ }
+ gpio_direction_output(SMD_FEC_PHY_RST, 0);
+ msleep(1);
+ gpio_set_value(SMD_FEC_PHY_RST, 1);
+}
+
+static struct fec_platform_data mx53_smd_fec_data = {
+ .phy = PHY_INTERFACE_MODE_RMII,
+};
+
+static void __init mx53_smd_board_init(void)
+{
+ mxc_iomux_v3_setup_multiple_pads(mx53_smd_pads,
+ ARRAY_SIZE(mx53_smd_pads));
+ mx53_smd_init_uart();
+ mx53_smd_fec_reset();
+ imx53_add_fec(&mx53_smd_fec_data);
+}
+
+static void __init mx53_smd_timer_init(void)
+{
+ mx53_clocks_init(32768, 24000000, 22579200, 0);
+}
+
+static struct sys_timer mx53_smd_timer = {
+ .init = mx53_smd_timer_init,
+};
+
+MACHINE_START(MX53_SMD, "Freescale MX53 SMD Board")
+ .map_io = mx53_map_io,
+ .init_irq = mx53_init_irq,
+ .init_machine = mx53_smd_board_init,
+ .timer = &mx53_smd_timer,
+MACHINE_END
diff --git a/arch/arm/mach-mx5/clock-mx51-mx53.c b/arch/arm/mach-mx5/clock-mx51-mx53.c
index 785e1a3..0a19e75 100644
--- a/arch/arm/mach-mx5/clock-mx51-mx53.c
+++ b/arch/arm/mach-mx5/clock-mx51-mx53.c
@@ -1191,6 +1191,11 @@ DEFINE_CLOCK(gpt_ipg_clk, 0, MXC_CCM_CCGR2, MXC_CCM_CCGRx_CG10_OFFSET,
DEFINE_CLOCK(gpt_clk, 0, MXC_CCM_CCGR2, MXC_CCM_CCGRx_CG9_OFFSET,
NULL, NULL, &ipg_clk, &gpt_ipg_clk);
+DEFINE_CLOCK(pwm1_clk, 0, MXC_CCM_CCGR2, MXC_CCM_CCGRx_CG6_OFFSET,
+ NULL, NULL, &ipg_clk, NULL);
+DEFINE_CLOCK(pwm2_clk, 0, MXC_CCM_CCGR2, MXC_CCM_CCGRx_CG8_OFFSET,
+ NULL, NULL, &ipg_clk, NULL);
+
/* I2C */
DEFINE_CLOCK(i2c1_clk, 0, MXC_CCM_CCGR1, MXC_CCM_CCGRx_CG9_OFFSET,
NULL, NULL, &ipg_clk, NULL);
@@ -1283,6 +1288,8 @@ static struct clk_lookup mx51_lookups[] = {
_REGISTER_CLOCK("imx-uart.2", NULL, uart3_clk)
_REGISTER_CLOCK(NULL, "gpt", gpt_clk)
_REGISTER_CLOCK("fec.0", NULL, fec_clk)
+ _REGISTER_CLOCK("mxc_pwm.0", "pwm", pwm1_clk)
+ _REGISTER_CLOCK("mxc_pwm.1", "pwm", pwm2_clk)
_REGISTER_CLOCK("imx-i2c.0", NULL, i2c1_clk)
_REGISTER_CLOCK("imx-i2c.1", NULL, i2c2_clk)
_REGISTER_CLOCK("imx-i2c.2", NULL, hsi2c_clk)
@@ -1295,7 +1302,7 @@ static struct clk_lookup mx51_lookups[] = {
_REGISTER_CLOCK("mxc-ehci.2", "usb_ahb", usb_ahb_clk)
_REGISTER_CLOCK("fsl-usb2-udc", "usb", usboh3_clk)
_REGISTER_CLOCK("fsl-usb2-udc", "usb_ahb", ahb_clk)
- _REGISTER_CLOCK("imx-keypad.0", NULL, kpp_clk)
+ _REGISTER_CLOCK("imx-keypad", NULL, kpp_clk)
_REGISTER_CLOCK("mxc_nand", NULL, nfc_clk)
_REGISTER_CLOCK("imx-ssi.0", NULL, ssi1_clk)
_REGISTER_CLOCK("imx-ssi.1", NULL, ssi2_clk)
@@ -1326,6 +1333,13 @@ static struct clk_lookup mx53_lookups[] = {
_REGISTER_CLOCK(NULL, "gpt", gpt_clk)
_REGISTER_CLOCK("fec.0", NULL, fec_clk)
_REGISTER_CLOCK(NULL, "iim_clk", iim_clk)
+ _REGISTER_CLOCK("imx-i2c.0", NULL, i2c1_clk)
+ _REGISTER_CLOCK("imx-i2c.1", NULL, i2c2_clk)
+ _REGISTER_CLOCK("sdhci-esdhc-imx.0", NULL, esdhc1_clk)
+ _REGISTER_CLOCK("sdhci-esdhc-imx.1", NULL, esdhc2_clk)
+ _REGISTER_CLOCK("imx53-ecspi.0", NULL, ecspi1_clk)
+ _REGISTER_CLOCK("imx53-ecspi.1", NULL, ecspi2_clk)
+ _REGISTER_CLOCK("imx53-cspi.0", NULL, cspi_clk)
};
static void clk_tree_init(void)
@@ -1363,7 +1377,6 @@ int __init mx51_clocks_init(unsigned long ckil, unsigned long osc,
clk_tree_init();
- clk_set_parent(&uart_root_clk, &pll3_sw_clk);
clk_enable(&cpu_clk);
clk_enable(&main_bus_clk);
@@ -1406,6 +1419,7 @@ int __init mx53_clocks_init(unsigned long ckil, unsigned long osc,
clk_tree_init();
+ clk_set_parent(&uart_root_clk, &pll3_sw_clk);
clk_enable(&cpu_clk);
clk_enable(&main_bus_clk);
diff --git a/arch/arm/mach-mx5/devices-imx51.h b/arch/arm/mach-mx5/devices-imx51.h
index 6302e46..7fff485 100644
--- a/arch/arm/mach-mx5/devices-imx51.h
+++ b/arch/arm/mach-mx5/devices-imx51.h
@@ -47,3 +47,11 @@ extern const struct imx_spi_imx_data imx51_ecspi_data[] __initconst;
extern const struct imx_imx2_wdt_data imx51_imx2_wdt_data[] __initconst;
#define imx51_add_imx2_wdt(id, pdata) \
imx_add_imx2_wdt(&imx51_imx2_wdt_data[id])
+
+extern const struct imx_mxc_pwm_data imx51_mxc_pwm_data[] __initconst;
+#define imx51_add_mxc_pwm(id) \
+ imx_add_mxc_pwm(&imx51_mxc_pwm_data[id])
+
+extern const struct imx_imx_keypad_data imx51_imx_keypad_data __initconst;
+#define imx51_add_imx_keypad(pdata) \
+ imx_add_imx_keypad(&imx51_imx_keypad_data, pdata)
diff --git a/arch/arm/mach-mx5/devices-imx53.h b/arch/arm/mach-mx5/devices-imx53.h
index 9d0ec25..8639735 100644
--- a/arch/arm/mach-mx5/devices-imx53.h
+++ b/arch/arm/mach-mx5/devices-imx53.h
@@ -8,6 +8,24 @@
#include <mach/mx53.h>
#include <mach/devices-common.h>
+extern const struct imx_fec_data imx53_fec_data __initconst;
+#define imx53_add_fec(pdata) \
+ imx_add_fec(&imx53_fec_data, pdata)
+
extern const struct imx_imx_uart_1irq_data imx53_imx_uart_data[] __initconst;
#define imx53_add_imx_uart(id, pdata) \
imx_add_imx_uart_1irq(&imx53_imx_uart_data[id], pdata)
+
+
+extern const struct imx_imx_i2c_data imx53_imx_i2c_data[] __initconst;
+#define imx53_add_imx_i2c(id, pdata) \
+ imx_add_imx_i2c(&imx53_imx_i2c_data[id], pdata)
+
+extern const struct imx_sdhci_esdhc_imx_data
+imx53_sdhci_esdhc_imx_data[] __initconst;
+#define imx53_add_sdhci_esdhc_imx(id, pdata) \
+ imx_add_sdhci_esdhc_imx(&imx53_sdhci_esdhc_imx_data[id], pdata)
+
+extern const struct imx_spi_imx_data imx53_ecspi_data[] __initconst;
+#define imx53_add_ecspi(id, pdata) \
+ imx_add_spi_imx(&imx53_ecspi_data[id], pdata)
diff --git a/arch/arm/mach-mx5/devices.c b/arch/arm/mach-mx5/devices.c
index 1bda5cb..153ada5 100644
--- a/arch/arm/mach-mx5/devices.c
+++ b/arch/arm/mach-mx5/devices.c
@@ -120,25 +120,6 @@ struct platform_device mxc_usbh2_device = {
},
};
-static struct resource mxc_kpp_resources[] = {
- {
- .start = MX51_MXC_INT_KPP,
- .end = MX51_MXC_INT_KPP,
- .flags = IORESOURCE_IRQ,
- } , {
- .start = MX51_KPP_BASE_ADDR,
- .end = MX51_KPP_BASE_ADDR + 0x8 - 1,
- .flags = IORESOURCE_MEM,
- },
-};
-
-struct platform_device mxc_keypad_device = {
- .name = "imx-keypad",
- .id = 0,
- .num_resources = ARRAY_SIZE(mxc_kpp_resources),
- .resource = mxc_kpp_resources,
-};
-
static struct mxc_gpio_port mxc_gpio_ports[] = {
{
.chip.label = "gpio-0",
diff --git a/arch/arm/mach-mx5/devices.h b/arch/arm/mach-mx5/devices.h
index 16891aa..55a5129 100644
--- a/arch/arm/mach-mx5/devices.h
+++ b/arch/arm/mach-mx5/devices.h
@@ -3,4 +3,3 @@ extern struct platform_device mxc_usbh1_device;
extern struct platform_device mxc_usbh2_device;
extern struct platform_device mxc_usbdr_udc_device;
extern struct platform_device mxc_hsi2c_device;
-extern struct platform_device mxc_keypad_device;
diff --git a/arch/arm/mach-mx5/eukrea_mbimx51-baseboard.c b/arch/arm/mach-mx5/eukrea_mbimx51-baseboard.c
index c96d018..e83ffad 100644
--- a/arch/arm/mach-mx5/eukrea_mbimx51-baseboard.c
+++ b/arch/arm/mach-mx5/eukrea_mbimx51-baseboard.c
@@ -21,7 +21,6 @@
#include <linux/fsl_devices.h>
#include <linux/i2c/tsc2007.h>
#include <linux/leds.h>
-#include <linux/input/matrix_keypad.h>
#include <mach/common.h>
#include <mach/hardware.h>
@@ -157,7 +156,7 @@ static int mbimx51_keymap[] = {
KEY(3, 3, KEY_ENTER),
};
-static struct matrix_keymap_data mbimx51_map_data = {
+static const struct matrix_keymap_data mbimx51_map_data __initconst = {
.keymap = mbimx51_keymap,
.keymap_size = ARRAY_SIZE(mbimx51_keymap),
};
@@ -209,7 +208,7 @@ void __init eukrea_mbimx51_baseboard_init(void)
platform_add_devices(devices, ARRAY_SIZE(devices));
- mxc_register_device(&mxc_keypad_device, &mbimx51_map_data);
+ imx51_add_imx_keypad(&mbimx51_map_data);
gpio_request(MBIMX51_TSC2007_GPIO, "tsc2007_irq");
gpio_direction_input(MBIMX51_TSC2007_GPIO);
diff --git a/arch/arm/mach-mxs/Kconfig b/arch/arm/mach-mxs/Kconfig
index c4ac7b4..8bfc8df 100644
--- a/arch/arm/mach-mxs/Kconfig
+++ b/arch/arm/mach-mxs/Kconfig
@@ -15,7 +15,7 @@ comment "MXS platforms:"
config MACH_MX23EVK
bool "Support MX23EVK Platform"
select SOC_IMX23
- select MXS_HAVE_PLATFORM_DUART
+ select MXS_HAVE_AMBA_DUART
default y
help
Include support for MX23EVK platform. This includes specific
@@ -24,7 +24,7 @@ config MACH_MX23EVK
config MACH_MX28EVK
bool "Support MX28EVK Platform"
select SOC_IMX28
- select MXS_HAVE_PLATFORM_DUART
+ select MXS_HAVE_AMBA_DUART
select MXS_HAVE_PLATFORM_FEC
default y
help
diff --git a/arch/arm/mach-mxs/clock-mx23.c b/arch/arm/mach-mxs/clock-mx23.c
index 8f5a19a..b1a362e 100644
--- a/arch/arm/mach-mxs/clock-mx23.c
+++ b/arch/arm/mach-mxs/clock-mx23.c
@@ -21,6 +21,7 @@
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/jiffies.h>
+#include <linux/clkdev.h>
#include <asm/clkdev.h>
#include <asm/div64.h>
@@ -437,10 +438,12 @@ _DEFINE_CLOCK(clk32k_clk, XTAL, TIMROT_CLK32K_GATE, &ref_xtal_clk);
},
static struct clk_lookup lookups[] = {
- _REGISTER_CLOCK("mxs-duart.0", NULL, uart_clk)
+ /* for amba bus driver */
+ _REGISTER_CLOCK("duart", "apb_pclk", xbus_clk)
+ /* for amba-pl011 driver */
+ _REGISTER_CLOCK("duart", NULL, uart_clk)
_REGISTER_CLOCK("rtc", NULL, rtc_clk)
_REGISTER_CLOCK(NULL, "hclk", hbus_clk)
- _REGISTER_CLOCK(NULL, "xclk", xbus_clk)
_REGISTER_CLOCK(NULL, "usb", usb_clk)
_REGISTER_CLOCK(NULL, "audio", audio_clk)
_REGISTER_CLOCK(NULL, "pwm", pwm_clk)
@@ -518,6 +521,12 @@ int __init mx23_clocks_init(void)
{
clk_misc_init();
+ clk_enable(&cpu_clk);
+ clk_enable(&hbus_clk);
+ clk_enable(&xbus_clk);
+ clk_enable(&emi_clk);
+ clk_enable(&uart_clk);
+
clkdev_add_table(lookups, ARRAY_SIZE(lookups));
mxs_timer_init(&clk32k_clk, MX23_INT_TIMER0);
diff --git a/arch/arm/mach-mxs/clock-mx28.c b/arch/arm/mach-mxs/clock-mx28.c
index 74e2103..56312c0 100644
--- a/arch/arm/mach-mxs/clock-mx28.c
+++ b/arch/arm/mach-mxs/clock-mx28.c
@@ -21,6 +21,7 @@
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/jiffies.h>
+#include <linux/clkdev.h>
#include <asm/clkdev.h>
#include <asm/div64.h>
@@ -602,7 +603,12 @@ _DEFINE_CLOCK(fec_clk, ENET, DISABLE, &hbus_clk);
},
static struct clk_lookup lookups[] = {
- _REGISTER_CLOCK("mxs-duart.0", NULL, uart_clk)
+ /* for amba bus driver */
+ _REGISTER_CLOCK("duart", "apb_pclk", xbus_clk)
+ /* for amba-pl011 driver */
+ _REGISTER_CLOCK("duart", NULL, uart_clk)
+ _REGISTER_CLOCK("imx28-fec.0", NULL, fec_clk)
+ _REGISTER_CLOCK("imx28-fec.1", NULL, fec_clk)
_REGISTER_CLOCK("fec.0", NULL, fec_clk)
_REGISTER_CLOCK("rtc", NULL, rtc_clk)
_REGISTER_CLOCK("pll2", NULL, pll2_clk)
@@ -726,6 +732,12 @@ int __init mx28_clocks_init(void)
{
clk_misc_init();
+ clk_enable(&cpu_clk);
+ clk_enable(&hbus_clk);
+ clk_enable(&xbus_clk);
+ clk_enable(&emi_clk);
+ clk_enable(&uart_clk);
+
clkdev_add_table(lookups, ARRAY_SIZE(lookups));
mxs_timer_init(&clk32k_clk, MX28_INT_TIMER0);
diff --git a/arch/arm/mach-mxs/devices-mx23.h b/arch/arm/mach-mxs/devices-mx23.h
index d0f49fc..1256788 100644
--- a/arch/arm/mach-mxs/devices-mx23.h
+++ b/arch/arm/mach-mxs/devices-mx23.h
@@ -11,6 +11,6 @@
#include <mach/mx23.h>
#include <mach/devices-common.h>
-extern const struct mxs_duart_data mx23_duart_data __initconst;
+extern const struct amba_device mx23_duart_device __initconst;
#define mx23_add_duart() \
- mxs_add_duart(&mx23_duart_data)
+ mxs_add_duart(&mx23_duart_device)
diff --git a/arch/arm/mach-mxs/devices-mx28.h b/arch/arm/mach-mxs/devices-mx28.h
index 00b736c..33773a6 100644
--- a/arch/arm/mach-mxs/devices-mx28.h
+++ b/arch/arm/mach-mxs/devices-mx28.h
@@ -11,9 +11,9 @@
#include <mach/mx28.h>
#include <mach/devices-common.h>
-extern const struct mxs_duart_data mx28_duart_data __initconst;
+extern const struct amba_device mx28_duart_device __initconst;
#define mx28_add_duart() \
- mxs_add_duart(&mx28_duart_data)
+ mxs_add_duart(&mx28_duart_device)
extern const struct mxs_fec_data mx28_fec_data[] __initconst;
#define mx28_add_fec(id, pdata) \
diff --git a/arch/arm/mach-mxs/devices.c b/arch/arm/mach-mxs/devices.c
index 6b60f02..c20d547 100644
--- a/arch/arm/mach-mxs/devices.c
+++ b/arch/arm/mach-mxs/devices.c
@@ -19,9 +19,8 @@
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/init.h>
-#include <linux/err.h>
#include <linux/platform_device.h>
-#include <mach/common.h>
+#include <linux/amba/bus.h>
struct platform_device *__init mxs_add_platform_device_dmamask(
const char *name, int id,
@@ -73,3 +72,17 @@ err:
return pdev;
}
+
+int __init mxs_add_amba_device(const struct amba_device *dev)
+{
+ struct amba_device *adev = kmalloc(sizeof(*adev), GFP_KERNEL);
+
+ if (!adev) {
+ pr_err("%s: failed to allocate memory", __func__);
+ return -ENOMEM;
+ }
+
+ *adev = *dev;
+
+ return amba_device_register(adev, &iomem_resource);
+}
diff --git a/arch/arm/mach-mxs/devices/Kconfig b/arch/arm/mach-mxs/devices/Kconfig
index a35a2dc..cf7dc1a 100644
--- a/arch/arm/mach-mxs/devices/Kconfig
+++ b/arch/arm/mach-mxs/devices/Kconfig
@@ -1,5 +1,6 @@
-config MXS_HAVE_PLATFORM_DUART
+config MXS_HAVE_AMBA_DUART
bool
+ select ARM_AMBA
config MXS_HAVE_PLATFORM_FEC
bool
diff --git a/arch/arm/mach-mxs/devices/Makefile b/arch/arm/mach-mxs/devices/Makefile
index 4b5266a..d0a09f6 100644
--- a/arch/arm/mach-mxs/devices/Makefile
+++ b/arch/arm/mach-mxs/devices/Makefile
@@ -1,2 +1,2 @@
-obj-$(CONFIG_MXS_HAVE_PLATFORM_DUART) += platform-duart.o
+obj-$(CONFIG_MXS_HAVE_AMBA_DUART) += amba-duart.o
obj-$(CONFIG_MXS_HAVE_PLATFORM_FEC) += platform-fec.o
diff --git a/arch/arm/mach-mxs/devices/amba-duart.c b/arch/arm/mach-mxs/devices/amba-duart.c
new file mode 100644
index 0000000..a559db0
--- /dev/null
+++ b/arch/arm/mach-mxs/devices/amba-duart.c
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2009-2010 Pengutronix
+ * Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de>
+ *
+ * Copyright 2010 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation.
+ */
+#include <asm/irq.h>
+#include <mach/mx23.h>
+#include <mach/mx28.h>
+#include <mach/devices-common.h>
+
+#define MXS_AMBA_DUART_DEVICE(name, soc) \
+const struct amba_device name##_device __initconst = { \
+ .dev = { \
+ .init_name = "duart", \
+ }, \
+ .res = { \
+ .start = soc ## _DUART_BASE_ADDR, \
+ .end = (soc ## _DUART_BASE_ADDR) + SZ_8K - 1, \
+ .flags = IORESOURCE_MEM, \
+ }, \
+ .irq = {soc ## _INT_DUART, NO_IRQ}, \
+}
+
+#ifdef CONFIG_SOC_IMX23
+MXS_AMBA_DUART_DEVICE(mx23_duart, MX23);
+#endif
+
+#ifdef CONFIG_SOC_IMX28
+MXS_AMBA_DUART_DEVICE(mx28_duart, MX28);
+#endif
+
+int __init mxs_add_duart(const struct amba_device *dev)
+{
+ return mxs_add_amba_device(dev);
+}
diff --git a/arch/arm/mach-mxs/devices/platform-duart.c b/arch/arm/mach-mxs/devices/platform-duart.c
deleted file mode 100644
index 2fe0df5..0000000
--- a/arch/arm/mach-mxs/devices/platform-duart.c
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (C) 2009-2010 Pengutronix
- * Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de>
- *
- * Copyright 2010 Freescale Semiconductor, Inc. All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License version 2 as published by the
- * Free Software Foundation.
- */
-#include <mach/mx23.h>
-#include <mach/mx28.h>
-#include <mach/devices-common.h>
-
-#define mxs_duart_data_entry(soc) \
- { \
- .iobase = soc ## _DUART_BASE_ADDR, \
- .irq = soc ## _INT_DUART, \
- }
-
-#ifdef CONFIG_SOC_IMX23
-const struct mxs_duart_data mx23_duart_data __initconst =
- mxs_duart_data_entry(MX23);
-#endif
-
-#ifdef CONFIG_SOC_IMX28
-const struct mxs_duart_data mx28_duart_data __initconst =
- mxs_duart_data_entry(MX28);
-#endif
-
-struct platform_device *__init mxs_add_duart(
- const struct mxs_duart_data *data)
-{
- struct resource res[] = {
- {
- .start = data->iobase,
- .end = data->iobase + SZ_8K - 1,
- .flags = IORESOURCE_MEM,
- }, {
- .start = data->irq,
- .end = data->irq,
- .flags = IORESOURCE_IRQ,
- },
- };
-
- return mxs_add_platform_device("mxs-duart", 0, res, ARRAY_SIZE(res),
- NULL, 0);
-}
diff --git a/arch/arm/mach-mxs/devices/platform-fec.c b/arch/arm/mach-mxs/devices/platform-fec.c
index c08168c..c42dff7 100644
--- a/arch/arm/mach-mxs/devices/platform-fec.c
+++ b/arch/arm/mach-mxs/devices/platform-fec.c
@@ -45,6 +45,6 @@ struct platform_device *__init mxs_add_fec(
},
};
- return mxs_add_platform_device("fec", data->id,
+ return mxs_add_platform_device("imx28-fec", data->id,
res, ARRAY_SIZE(res), pdata, sizeof(*pdata));
}
diff --git a/arch/arm/mach-mxs/include/mach/devices-common.h b/arch/arm/mach-mxs/include/mach/devices-common.h
index 3da48d4..6c3d1a1 100644
--- a/arch/arm/mach-mxs/include/mach/devices-common.h
+++ b/arch/arm/mach-mxs/include/mach/devices-common.h
@@ -9,6 +9,7 @@
#include <linux/kernel.h>
#include <linux/platform_device.h>
#include <linux/init.h>
+#include <linux/amba/bus.h>
struct platform_device *mxs_add_platform_device_dmamask(
const char *name, int id,
@@ -24,14 +25,10 @@ static inline struct platform_device *mxs_add_platform_device(
name, id, res, num_resources, data, size_data, 0);
}
+int __init mxs_add_amba_device(const struct amba_device *dev);
+
/* duart */
-struct mxs_duart_data {
- resource_size_t iobase;
- resource_size_t iosize;
- resource_size_t irq;
-};
-struct platform_device *__init mxs_add_duart(
- const struct mxs_duart_data *data);
+int __init mxs_add_duart(const struct amba_device *dev);
/* fec */
#include <linux/fec.h>
diff --git a/arch/arm/mach-mxs/mach-mx28evk.c b/arch/arm/mach-mxs/mach-mx28evk.c
index d162e95..8e2c597 100644
--- a/arch/arm/mach-mxs/mach-mx28evk.c
+++ b/arch/arm/mach-mxs/mach-mx28evk.c
@@ -57,6 +57,19 @@ static const iomux_cfg_t mx28evk_pads[] __initconst = {
(MXS_PAD_8MA | MXS_PAD_3V3 | MXS_PAD_PULLUP),
MX28_PAD_ENET_CLK__CLKCTRL_ENET |
(MXS_PAD_8MA | MXS_PAD_3V3 | MXS_PAD_PULLUP),
+ /* fec1 */
+ MX28_PAD_ENET0_CRS__ENET1_RX_EN |
+ (MXS_PAD_8MA | MXS_PAD_3V3 | MXS_PAD_PULLUP),
+ MX28_PAD_ENET0_RXD2__ENET1_RXD0 |
+ (MXS_PAD_8MA | MXS_PAD_3V3 | MXS_PAD_PULLUP),
+ MX28_PAD_ENET0_RXD3__ENET1_RXD1 |
+ (MXS_PAD_8MA | MXS_PAD_3V3 | MXS_PAD_PULLUP),
+ MX28_PAD_ENET0_COL__ENET1_TX_EN |
+ (MXS_PAD_8MA | MXS_PAD_3V3 | MXS_PAD_PULLUP),
+ MX28_PAD_ENET0_TXD2__ENET1_TXD0 |
+ (MXS_PAD_8MA | MXS_PAD_3V3 | MXS_PAD_PULLUP),
+ MX28_PAD_ENET0_TXD3__ENET1_TXD1 |
+ (MXS_PAD_8MA | MXS_PAD_3V3 | MXS_PAD_PULLUP),
/* phy power line */
MX28_PAD_SSP1_DATA3__GPIO_2_15 |
(MXS_PAD_4MA | MXS_PAD_3V3 | MXS_PAD_NOPULL),
@@ -106,8 +119,14 @@ static void __init mx28evk_fec_reset(void)
gpio_set_value(MX28EVK_FEC_PHY_RESET, 1);
}
-static const struct fec_platform_data mx28_fec_pdata __initconst = {
- .phy = PHY_INTERFACE_MODE_RMII,
+static struct fec_platform_data mx28_fec_pdata[] = {
+ {
+ /* fec0 */
+ .phy = PHY_INTERFACE_MODE_RMII,
+ }, {
+ /* fec1 */
+ .phy = PHY_INTERFACE_MODE_RMII,
+ },
};
static void __init mx28evk_init(void)
@@ -117,7 +136,8 @@ static void __init mx28evk_init(void)
mx28_add_duart();
mx28evk_fec_reset();
- mx28_add_fec(0, &mx28_fec_pdata);
+ mx28_add_fec(0, &mx28_fec_pdata[0]);
+ mx28_add_fec(1, &mx28_fec_pdata[1]);
}
static void __init mx28evk_timer_init(void)
diff --git a/arch/arm/mach-netx/generic.c b/arch/arm/mach-netx/generic.c
index 43da8bb..29ffa75 100644
--- a/arch/arm/mach-netx/generic.c
+++ b/arch/arm/mach-netx/generic.c
@@ -88,13 +88,13 @@ netx_hif_demux_handler(unsigned int irq_unused, struct irq_desc *desc)
}
static int
-netx_hif_irq_type(unsigned int _irq, unsigned int type)
+netx_hif_irq_type(struct irq_data *d, unsigned int type)
{
unsigned int val, irq;
val = readl(NETX_DPMAS_IF_CONF1);
- irq = _irq - NETX_IRQ_HIF_CHAINED(0);
+ irq = d->irq - NETX_IRQ_HIF_CHAINED(0);
if (type & IRQ_TYPE_EDGE_RISING) {
DEBUG_IRQ("rising edges\n");
@@ -119,49 +119,49 @@ netx_hif_irq_type(unsigned int _irq, unsigned int type)
}
static void
-netx_hif_ack_irq(unsigned int _irq)
+netx_hif_ack_irq(struct irq_data *d)
{
unsigned int val, irq;
- irq = _irq - NETX_IRQ_HIF_CHAINED(0);
+ irq = d->irq - NETX_IRQ_HIF_CHAINED(0);
writel((1 << 24) << irq, NETX_DPMAS_INT_STAT);
val = readl(NETX_DPMAS_INT_EN);
val &= ~((1 << 24) << irq);
writel(val, NETX_DPMAS_INT_EN);
- DEBUG_IRQ("%s: irq %d\n", __func__, _irq);
+ DEBUG_IRQ("%s: irq %d\n", __func__, d->irq);
}
static void
-netx_hif_mask_irq(unsigned int _irq)
+netx_hif_mask_irq(struct irq_data *d)
{
unsigned int val, irq;
- irq = _irq - NETX_IRQ_HIF_CHAINED(0);
+ irq = d->irq - NETX_IRQ_HIF_CHAINED(0);
val = readl(NETX_DPMAS_INT_EN);
val &= ~((1 << 24) << irq);
writel(val, NETX_DPMAS_INT_EN);
- DEBUG_IRQ("%s: irq %d\n", __func__, _irq);
+ DEBUG_IRQ("%s: irq %d\n", __func__, d->irq);
}
static void
-netx_hif_unmask_irq(unsigned int _irq)
+netx_hif_unmask_irq(struct irq_data *d)
{
unsigned int val, irq;
- irq = _irq - NETX_IRQ_HIF_CHAINED(0);
+ irq = d->irq - NETX_IRQ_HIF_CHAINED(0);
val = readl(NETX_DPMAS_INT_EN);
val |= (1 << 24) << irq;
writel(val, NETX_DPMAS_INT_EN);
- DEBUG_IRQ("%s: irq %d\n", __func__, _irq);
+ DEBUG_IRQ("%s: irq %d\n", __func__, d->irq);
}
static struct irq_chip netx_hif_chip = {
- .ack = netx_hif_ack_irq,
- .mask = netx_hif_mask_irq,
- .unmask = netx_hif_unmask_irq,
- .set_type = netx_hif_irq_type,
+ .irq_ack = netx_hif_ack_irq,
+ .irq_mask = netx_hif_mask_irq,
+ .irq_unmask = netx_hif_unmask_irq,
+ .irq_set_type = netx_hif_irq_type,
};
void __init netx_init_irq(void)
diff --git a/arch/arm/mach-ns9xxx/board-a9m9750dev.c b/arch/arm/mach-ns9xxx/board-a9m9750dev.c
index b45bb3b..0c0d524 100644
--- a/arch/arm/mach-ns9xxx/board-a9m9750dev.c
+++ b/arch/arm/mach-ns9xxx/board-a9m9750dev.c
@@ -37,44 +37,44 @@ void __init board_a9m9750dev_map_io(void)
ARRAY_SIZE(board_a9m9750dev_io_desc));
}
-static void a9m9750dev_fpga_ack_irq(unsigned int irq)
+static void a9m9750dev_fpga_ack_irq(struct irq_data *d)
{
/* nothing */
}
-static void a9m9750dev_fpga_mask_irq(unsigned int irq)
+static void a9m9750dev_fpga_mask_irq(struct irq_data *d)
{
u8 ier;
ier = __raw_readb(FPGA_IER);
- ier &= ~(1 << (irq - FPGA_IRQ(0)));
+ ier &= ~(1 << (d->irq - FPGA_IRQ(0)));
__raw_writeb(ier, FPGA_IER);
}
-static void a9m9750dev_fpga_maskack_irq(unsigned int irq)
+static void a9m9750dev_fpga_maskack_irq(struct irq_data *d)
{
- a9m9750dev_fpga_mask_irq(irq);
- a9m9750dev_fpga_ack_irq(irq);
+ a9m9750dev_fpga_mask_irq(d);
+ a9m9750dev_fpga_ack_irq(d);
}
-static void a9m9750dev_fpga_unmask_irq(unsigned int irq)
+static void a9m9750dev_fpga_unmask_irq(struct irq_data *d)
{
u8 ier;
ier = __raw_readb(FPGA_IER);
- ier |= 1 << (irq - FPGA_IRQ(0));
+ ier |= 1 << (d->irq - FPGA_IRQ(0));
__raw_writeb(ier, FPGA_IER);
}
static struct irq_chip a9m9750dev_fpga_chip = {
- .ack = a9m9750dev_fpga_ack_irq,
- .mask = a9m9750dev_fpga_mask_irq,
- .mask_ack = a9m9750dev_fpga_maskack_irq,
- .unmask = a9m9750dev_fpga_unmask_irq,
+ .irq_ack = a9m9750dev_fpga_ack_irq,
+ .irq_mask = a9m9750dev_fpga_mask_irq,
+ .irq_mask_ack = a9m9750dev_fpga_maskack_irq,
+ .irq_unmask = a9m9750dev_fpga_unmask_irq,
};
static void a9m9750dev_fpga_demux_handler(unsigned int irq,
@@ -82,7 +82,7 @@ static void a9m9750dev_fpga_demux_handler(unsigned int irq,
{
u8 stat = __raw_readb(FPGA_ISR);
- desc->chip->mask_ack(irq);
+ desc->irq_data.chip->irq_mask_ack(&desc->irq_data);
while (stat != 0) {
int irqno = fls(stat) - 1;
@@ -92,7 +92,7 @@ static void a9m9750dev_fpga_demux_handler(unsigned int irq,
generic_handle_irq(FPGA_IRQ(irqno));
}
- desc->chip->unmask(irq);
+ desc->irq_data.chip->irq_unmask(&desc->irq_data);
}
void __init board_a9m9750dev_init_irq(void)
diff --git a/arch/arm/mach-ns9xxx/irq.c b/arch/arm/mach-ns9xxx/irq.c
index 038f24d..389fa5c 100644
--- a/arch/arm/mach-ns9xxx/irq.c
+++ b/arch/arm/mach-ns9xxx/irq.c
@@ -22,40 +22,40 @@
#define irq2prio(i) (i)
#define prio2irq(p) (p)
-static void ns9xxx_mask_irq(unsigned int irq)
+static void ns9xxx_mask_irq(struct irq_data *d)
{
/* XXX: better use cpp symbols */
- int prio = irq2prio(irq);
+ int prio = irq2prio(d->irq);
u32 ic = __raw_readl(SYS_IC(prio / 4));
ic &= ~(1 << (7 + 8 * (3 - (prio & 3))));
__raw_writel(ic, SYS_IC(prio / 4));
}
-static void ns9xxx_ack_irq(unsigned int irq)
+static void ns9xxx_ack_irq(struct irq_data *d)
{
__raw_writel(0, SYS_ISRADDR);
}
-static void ns9xxx_maskack_irq(unsigned int irq)
+static void ns9xxx_maskack_irq(struct irq_data *d)
{
- ns9xxx_mask_irq(irq);
- ns9xxx_ack_irq(irq);
+ ns9xxx_mask_irq(d);
+ ns9xxx_ack_irq(d);
}
-static void ns9xxx_unmask_irq(unsigned int irq)
+static void ns9xxx_unmask_irq(struct irq_data *d)
{
/* XXX: better use cpp symbols */
- int prio = irq2prio(irq);
+ int prio = irq2prio(d->irq);
u32 ic = __raw_readl(SYS_IC(prio / 4));
ic |= 1 << (7 + 8 * (3 - (prio & 3)));
__raw_writel(ic, SYS_IC(prio / 4));
}
static struct irq_chip ns9xxx_chip = {
- .ack = ns9xxx_ack_irq,
- .mask = ns9xxx_mask_irq,
- .mask_ack = ns9xxx_maskack_irq,
- .unmask = ns9xxx_unmask_irq,
+ .irq_ack = ns9xxx_ack_irq,
+ .irq_mask = ns9xxx_mask_irq,
+ .irq_mask_ack = ns9xxx_maskack_irq,
+ .irq_unmask = ns9xxx_unmask_irq,
};
#if 0
@@ -92,10 +92,10 @@ static void handle_prio_irq(unsigned int irq, struct irq_desc *desc)
if (desc->status & IRQ_DISABLED)
out_mask:
- desc->chip->mask(irq);
+ desc->irq_data.chip->irq_mask(&desc->irq_data);
/* ack unconditionally to unmask lower prio irqs */
- desc->chip->ack(irq);
+ desc->irq_data.chip->irq_ack(&desc->irq_data);
raw_spin_unlock(&desc->lock);
}
diff --git a/arch/arm/mach-nuc93x/irq.c b/arch/arm/mach-nuc93x/irq.c
index a7a88ea..1f8a05a 100644
--- a/arch/arm/mach-nuc93x/irq.c
+++ b/arch/arm/mach-nuc93x/irq.c
@@ -25,9 +25,9 @@
#include <mach/hardware.h>
#include <mach/regs-irq.h>
-static void nuc93x_irq_mask(unsigned int irq)
+static void nuc93x_irq_mask(struct irq_data *d)
{
- __raw_writel(1 << irq, REG_AIC_MDCR);
+ __raw_writel(1 << d->irq, REG_AIC_MDCR);
}
/*
@@ -35,21 +35,21 @@ static void nuc93x_irq_mask(unsigned int irq)
* to REG_AIC_EOSCR for ACK
*/
-static void nuc93x_irq_ack(unsigned int irq)
+static void nuc93x_irq_ack(struct irq_data *d)
{
__raw_writel(0x01, REG_AIC_EOSCR);
}
-static void nuc93x_irq_unmask(unsigned int irq)
+static void nuc93x_irq_unmask(struct irq_data *d)
{
- __raw_writel(1 << irq, REG_AIC_MECR);
+ __raw_writel(1 << d->irq, REG_AIC_MECR);
}
static struct irq_chip nuc93x_irq_chip = {
- .ack = nuc93x_irq_ack,
- .mask = nuc93x_irq_mask,
- .unmask = nuc93x_irq_unmask,
+ .irq_ack = nuc93x_irq_ack,
+ .irq_mask = nuc93x_irq_mask,
+ .irq_unmask = nuc93x_irq_unmask,
};
void __init nuc93x_init_irq(void)
diff --git a/arch/arm/mach-omap1/Kconfig b/arch/arm/mach-omap1/Kconfig
index 8d2f2da..e0a0281 100644
--- a/arch/arm/mach-omap1/Kconfig
+++ b/arch/arm/mach-omap1/Kconfig
@@ -9,6 +9,7 @@ config ARCH_OMAP730
depends on ARCH_OMAP1
bool "OMAP730 Based System"
select CPU_ARM926T
+ select OMAP_MPU_TIMER
select ARCH_OMAP_OTG
config ARCH_OMAP850
@@ -22,6 +23,7 @@ config ARCH_OMAP15XX
default y
bool "OMAP15xx Based System"
select CPU_ARM925T
+ select OMAP_MPU_TIMER
config ARCH_OMAP16XX
depends on ARCH_OMAP1
diff --git a/arch/arm/mach-omap1/Makefile b/arch/arm/mach-omap1/Makefile
index 6ee1950..ba6009f 100644
--- a/arch/arm/mach-omap1/Makefile
+++ b/arch/arm/mach-omap1/Makefile
@@ -3,12 +3,11 @@
#
# Common support
-obj-y := io.o id.o sram.o irq.o mux.o flash.o serial.o devices.o dma.o
+obj-y := io.o id.o sram.o time.o irq.o mux.o flash.o serial.o devices.o dma.o
obj-y += clock.o clock_data.o opp_data.o
obj-$(CONFIG_OMAP_MCBSP) += mcbsp.o
-obj-$(CONFIG_OMAP_MPU_TIMER) += time.o
obj-$(CONFIG_OMAP_32K_TIMER) += timer32k.o
# Power Management
diff --git a/arch/arm/mach-omap1/ams-delta-fiq.c b/arch/arm/mach-omap1/ams-delta-fiq.c
index 6c994e2..152b32c 100644
--- a/arch/arm/mach-omap1/ams-delta-fiq.c
+++ b/arch/arm/mach-omap1/ams-delta-fiq.c
@@ -49,7 +49,7 @@ static irqreturn_t deferred_fiq(int irq, void *dev_id)
irq_desc = irq_to_desc(IH_GPIO_BASE);
if (irq_desc)
- irq_chip = irq_desc->chip;
+ irq_chip = irq_desc->irq_data.chip;
/*
* For each handled GPIO interrupt, keep calling its interrupt handler
@@ -62,13 +62,15 @@ static irqreturn_t deferred_fiq(int irq, void *dev_id)
while (irq_counter[gpio] < fiq_count) {
if (gpio != AMS_DELTA_GPIO_PIN_KEYBRD_CLK) {
+ struct irq_data *d = irq_get_irq_data(irq_num);
+
/*
* It looks like handle_edge_irq() that
* OMAP GPIO edge interrupts default to,
* expects interrupt already unmasked.
*/
- if (irq_chip && irq_chip->unmask)
- irq_chip->unmask(irq_num);
+ if (irq_chip && irq_chip->irq_unmask)
+ irq_chip->irq_unmask(d);
}
generic_handle_irq(irq_num);
diff --git a/arch/arm/mach-omap1/board-ams-delta.c b/arch/arm/mach-omap1/board-ams-delta.c
index bd0495a..22cc8c8 100644
--- a/arch/arm/mach-omap1/board-ams-delta.c
+++ b/arch/arm/mach-omap1/board-ams-delta.c
@@ -179,6 +179,22 @@ static struct omap_board_config_kernel ams_delta_config[] = {
{ OMAP_TAG_LCD, &ams_delta_lcd_config },
};
+static struct resource ams_delta_nand_resources[] = {
+ [0] = {
+ .start = OMAP1_MPUIO_BASE,
+ .end = OMAP1_MPUIO_BASE +
+ OMAP_MPUIO_IO_CNTL + sizeof(u32) - 1,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct platform_device ams_delta_nand_device = {
+ .name = "ams-delta-nand",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(ams_delta_nand_resources),
+ .resource = ams_delta_nand_resources,
+};
+
static struct resource ams_delta_kp_resources[] = {
[0] = {
.start = INT_KEYBOARD,
@@ -265,6 +281,7 @@ static struct omap1_cam_platform_data ams_delta_camera_platform_data = {
};
static struct platform_device *ams_delta_devices[] __initdata = {
+ &ams_delta_nand_device,
&ams_delta_kp_device,
&ams_delta_lcd_device,
&ams_delta_led_device,
diff --git a/arch/arm/mach-omap1/fpga.c b/arch/arm/mach-omap1/fpga.c
index 8780e75..0ace799 100644
--- a/arch/arm/mach-omap1/fpga.c
+++ b/arch/arm/mach-omap1/fpga.c
@@ -30,9 +30,9 @@
#include <plat/fpga.h>
#include <mach/gpio.h>
-static void fpga_mask_irq(unsigned int irq)
+static void fpga_mask_irq(struct irq_data *d)
{
- irq -= OMAP_FPGA_IRQ_BASE;
+ unsigned int irq = d->irq - OMAP_FPGA_IRQ_BASE;
if (irq < 8)
__raw_writeb((__raw_readb(OMAP1510_FPGA_IMR_LO)
@@ -58,14 +58,14 @@ static inline u32 get_fpga_unmasked_irqs(void)
}
-static void fpga_ack_irq(unsigned int irq)
+static void fpga_ack_irq(struct irq_data *d)
{
/* Don't need to explicitly ACK FPGA interrupts */
}
-static void fpga_unmask_irq(unsigned int irq)
+static void fpga_unmask_irq(struct irq_data *d)
{
- irq -= OMAP_FPGA_IRQ_BASE;
+ unsigned int irq = d->irq - OMAP_FPGA_IRQ_BASE;
if (irq < 8)
__raw_writeb((__raw_readb(OMAP1510_FPGA_IMR_LO) | (1 << irq)),
@@ -78,10 +78,10 @@ static void fpga_unmask_irq(unsigned int irq)
| (1 << (irq - 16))), INNOVATOR_FPGA_IMR2);
}
-static void fpga_mask_ack_irq(unsigned int irq)
+static void fpga_mask_ack_irq(struct irq_data *d)
{
- fpga_mask_irq(irq);
- fpga_ack_irq(irq);
+ fpga_mask_irq(d);
+ fpga_ack_irq(d);
}
void innovator_fpga_IRQ_demux(unsigned int irq, struct irq_desc *desc)
@@ -105,17 +105,17 @@ void innovator_fpga_IRQ_demux(unsigned int irq, struct irq_desc *desc)
static struct irq_chip omap_fpga_irq_ack = {
.name = "FPGA-ack",
- .ack = fpga_mask_ack_irq,
- .mask = fpga_mask_irq,
- .unmask = fpga_unmask_irq,
+ .irq_ack = fpga_mask_ack_irq,
+ .irq_mask = fpga_mask_irq,
+ .irq_unmask = fpga_unmask_irq,
};
static struct irq_chip omap_fpga_irq = {
.name = "FPGA",
- .ack = fpga_ack_irq,
- .mask = fpga_mask_irq,
- .unmask = fpga_unmask_irq,
+ .irq_ack = fpga_ack_irq,
+ .irq_mask = fpga_mask_irq,
+ .irq_unmask = fpga_unmask_irq,
};
/*
diff --git a/arch/arm/mach-omap1/irq.c b/arch/arm/mach-omap1/irq.c
index 6bddbc8..4770158 100644
--- a/arch/arm/mach-omap1/irq.c
+++ b/arch/arm/mach-omap1/irq.c
@@ -70,48 +70,48 @@ static inline void irq_bank_writel(unsigned long value, int bank, int offset)
omap_writel(value, irq_banks[bank].base_reg + offset);
}
-static void omap_ack_irq(unsigned int irq)
+static void omap_ack_irq(struct irq_data *d)
{
- if (irq > 31)
+ if (d->irq > 31)
omap_writel(0x1, OMAP_IH2_BASE + IRQ_CONTROL_REG_OFFSET);
omap_writel(0x1, OMAP_IH1_BASE + IRQ_CONTROL_REG_OFFSET);
}
-static void omap_mask_irq(unsigned int irq)
+static void omap_mask_irq(struct irq_data *d)
{
- int bank = IRQ_BANK(irq);
+ int bank = IRQ_BANK(d->irq);
u32 l;
l = omap_readl(irq_banks[bank].base_reg + IRQ_MIR_REG_OFFSET);
- l |= 1 << IRQ_BIT(irq);
+ l |= 1 << IRQ_BIT(d->irq);
omap_writel(l, irq_banks[bank].base_reg + IRQ_MIR_REG_OFFSET);
}
-static void omap_unmask_irq(unsigned int irq)
+static void omap_unmask_irq(struct irq_data *d)
{
- int bank = IRQ_BANK(irq);
+ int bank = IRQ_BANK(d->irq);
u32 l;
l = omap_readl(irq_banks[bank].base_reg + IRQ_MIR_REG_OFFSET);
- l &= ~(1 << IRQ_BIT(irq));
+ l &= ~(1 << IRQ_BIT(d->irq));
omap_writel(l, irq_banks[bank].base_reg + IRQ_MIR_REG_OFFSET);
}
-static void omap_mask_ack_irq(unsigned int irq)
+static void omap_mask_ack_irq(struct irq_data *d)
{
- omap_mask_irq(irq);
- omap_ack_irq(irq);
+ omap_mask_irq(d);
+ omap_ack_irq(d);
}
-static int omap_wake_irq(unsigned int irq, unsigned int enable)
+static int omap_wake_irq(struct irq_data *d, unsigned int enable)
{
- int bank = IRQ_BANK(irq);
+ int bank = IRQ_BANK(d->irq);
if (enable)
- irq_banks[bank].wake_enable |= IRQ_BIT(irq);
+ irq_banks[bank].wake_enable |= IRQ_BIT(d->irq);
else
- irq_banks[bank].wake_enable &= ~IRQ_BIT(irq);
+ irq_banks[bank].wake_enable &= ~IRQ_BIT(d->irq);
return 0;
}
@@ -168,10 +168,10 @@ static struct omap_irq_bank omap1610_irq_banks[] = {
static struct irq_chip omap_irq_chip = {
.name = "MPU",
- .ack = omap_mask_ack_irq,
- .mask = omap_mask_irq,
- .unmask = omap_unmask_irq,
- .set_wake = omap_wake_irq,
+ .irq_ack = omap_mask_ack_irq,
+ .irq_mask = omap_mask_irq,
+ .irq_unmask = omap_unmask_irq,
+ .irq_set_wake = omap_wake_irq,
};
void __init omap_init_irq(void)
@@ -239,9 +239,9 @@ void __init omap_init_irq(void)
/* Unmask level 2 handler */
if (cpu_is_omap7xx())
- omap_unmask_irq(INT_7XX_IH2_IRQ);
+ omap_unmask_irq(irq_get_irq_data(INT_7XX_IH2_IRQ));
else if (cpu_is_omap15xx())
- omap_unmask_irq(INT_1510_IH2_IRQ);
+ omap_unmask_irq(irq_get_irq_data(INT_1510_IH2_IRQ));
else if (cpu_is_omap16xx())
- omap_unmask_irq(INT_1610_IH2_IRQ);
+ omap_unmask_irq(irq_get_irq_data(INT_1610_IH2_IRQ));
}
diff --git a/arch/arm/mach-omap1/time.c b/arch/arm/mach-omap1/time.c
index ed7a61f..f83fc33 100644
--- a/arch/arm/mach-omap1/time.c
+++ b/arch/arm/mach-omap1/time.c
@@ -44,16 +44,21 @@
#include <linux/clocksource.h>
#include <linux/clockchips.h>
#include <linux/io.h>
+#include <linux/sched.h>
#include <asm/system.h>
#include <mach/hardware.h>
#include <asm/leds.h>
#include <asm/irq.h>
+#include <asm/sched_clock.h>
+
#include <asm/mach/irq.h>
#include <asm/mach/time.h>
#include <plat/common.h>
+#ifdef CONFIG_OMAP_MPU_TIMER
+
#define OMAP_MPU_TIMER_BASE OMAP_MPU_TIMER1_BASE
#define OMAP_MPU_TIMER_OFFSET 0x100
@@ -67,7 +72,7 @@ typedef struct {
((volatile omap_mpu_timer_regs_t*)OMAP1_IO_ADDRESS(OMAP_MPU_TIMER_BASE + \
(n)*OMAP_MPU_TIMER_OFFSET))
-static inline unsigned long omap_mpu_timer_read(int nr)
+static inline unsigned long notrace omap_mpu_timer_read(int nr)
{
volatile omap_mpu_timer_regs_t* timer = omap_mpu_timer_base(nr);
return timer->read_tim;
@@ -212,6 +217,32 @@ static struct clocksource clocksource_mpu = {
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
};
+static DEFINE_CLOCK_DATA(cd);
+
+static inline unsigned long long notrace _omap_mpu_sched_clock(void)
+{
+ u32 cyc = mpu_read(&clocksource_mpu);
+ return cyc_to_sched_clock(&cd, cyc, (u32)~0);
+}
+
+#ifndef CONFIG_OMAP_32K_TIMER
+unsigned long long notrace sched_clock(void)
+{
+ return _omap_mpu_sched_clock();
+}
+#else
+static unsigned long long notrace omap_mpu_sched_clock(void)
+{
+ return _omap_mpu_sched_clock();
+}
+#endif
+
+static void notrace mpu_update_sched_clock(void)
+{
+ u32 cyc = mpu_read(&clocksource_mpu);
+ update_sched_clock(&cd, cyc, (u32)~0);
+}
+
static void __init omap_init_clocksource(unsigned long rate)
{
static char err[] __initdata = KERN_ERR
@@ -219,17 +250,13 @@ static void __init omap_init_clocksource(unsigned long rate)
setup_irq(INT_TIMER2, &omap_mpu_timer2_irq);
omap_mpu_timer_start(1, ~0, 1);
+ init_sched_clock(&cd, mpu_update_sched_clock, 32, rate);
if (clocksource_register_hz(&clocksource_mpu, rate))
printk(err, clocksource_mpu.name);
}
-/*
- * ---------------------------------------------------------------------------
- * Timer initialization
- * ---------------------------------------------------------------------------
- */
-static void __init omap_timer_init(void)
+static void __init omap_mpu_timer_init(void)
{
struct clk *ck_ref = clk_get(NULL, "ck_ref");
unsigned long rate;
@@ -246,6 +273,66 @@ static void __init omap_timer_init(void)
omap_init_clocksource(rate);
}
+#else
+static inline void omap_mpu_timer_init(void)
+{
+ pr_err("Bogus timer, should not happen\n");
+}
+#endif /* CONFIG_OMAP_MPU_TIMER */
+
+#if defined(CONFIG_OMAP_MPU_TIMER) && defined(CONFIG_OMAP_32K_TIMER)
+static unsigned long long (*preferred_sched_clock)(void);
+
+unsigned long long notrace sched_clock(void)
+{
+ if (!preferred_sched_clock)
+ return 0;
+
+ return preferred_sched_clock();
+}
+
+static inline void preferred_sched_clock_init(bool use_32k_sched_clock)
+{
+ if (use_32k_sched_clock)
+ preferred_sched_clock = omap_32k_sched_clock;
+ else
+ preferred_sched_clock = omap_mpu_sched_clock;
+}
+#else
+static inline void preferred_sched_clock_init(bool use_32k_sched_clcok)
+{
+}
+#endif
+
+static inline int omap_32k_timer_usable(void)
+{
+ int res = false;
+
+ if (cpu_is_omap730() || cpu_is_omap15xx())
+ return res;
+
+#ifdef CONFIG_OMAP_32K_TIMER
+ res = omap_32k_timer_init();
+#endif
+
+ return res;
+}
+
+/*
+ * ---------------------------------------------------------------------------
+ * Timer initialization
+ * ---------------------------------------------------------------------------
+ */
+static void __init omap_timer_init(void)
+{
+ if (omap_32k_timer_usable()) {
+ preferred_sched_clock_init(1);
+ } else {
+ omap_mpu_timer_init();
+ preferred_sched_clock_init(0);
+ }
+}
+
struct sys_timer omap_timer = {
.init = omap_timer_init,
};
diff --git a/arch/arm/mach-omap1/timer32k.c b/arch/arm/mach-omap1/timer32k.c
index 20cfbcc..13d7b8f 100644
--- a/arch/arm/mach-omap1/timer32k.c
+++ b/arch/arm/mach-omap1/timer32k.c
@@ -52,10 +52,9 @@
#include <asm/irq.h>
#include <asm/mach/irq.h>
#include <asm/mach/time.h>
+#include <plat/common.h>
#include <plat/dmtimer.h>
-struct sys_timer omap_timer;
-
/*
* ---------------------------------------------------------------------------
* 32KHz OS timer
@@ -181,14 +180,14 @@ static __init void omap_init_32k_timer(void)
* Timer initialization
* ---------------------------------------------------------------------------
*/
-static void __init omap_timer_init(void)
+bool __init omap_32k_timer_init(void)
{
+ omap_init_clocksource_32k();
+
#ifdef CONFIG_OMAP_DM_TIMER
omap_dm_timer_init();
#endif
omap_init_32k_timer();
-}
-struct sys_timer omap_timer = {
- .init = omap_timer_init,
-};
+ return true;
+}
diff --git a/arch/arm/mach-omap2/board-4430sdp.c b/arch/arm/mach-omap2/board-4430sdp.c
index a70bdf2..07d1b20 100644
--- a/arch/arm/mach-omap2/board-4430sdp.c
+++ b/arch/arm/mach-omap2/board-4430sdp.c
@@ -554,6 +554,7 @@ static void __init omap_sfh7741prox_init(void)
#ifdef CONFIG_OMAP_MUX
static struct omap_board_mux board_mux[] __initdata = {
+ OMAP4_MUX(USBB2_ULPITLL_CLK, OMAP_MUX_MODE4 | OMAP_PIN_OUTPUT),
{ .reg_offset = OMAP_MUX_TERMINATOR },
};
#else
@@ -576,11 +577,12 @@ static void __init omap_4430sdp_init(void)
omap4_twl6030_hsmmc_init(mmc);
/* Power on the ULPI PHY */
- if (gpio_is_valid(OMAP4SDP_MDM_PWR_EN_GPIO)) {
- /* FIXME: Assumes pad is already muxed for GPIO mode */
- gpio_request(OMAP4SDP_MDM_PWR_EN_GPIO, "USBB1 PHY VMDM_3V3");
+ status = gpio_request(OMAP4SDP_MDM_PWR_EN_GPIO, "USBB1 PHY VMDM_3V3");
+ if (status)
+ pr_err("%s: Could not get USBB1 PHY GPIO\n", __func__);
+ else
gpio_direction_output(OMAP4SDP_MDM_PWR_EN_GPIO, 1);
- }
+
usb_ehci_init(&ehci_pdata);
usb_musb_init(&musb_board_data);
diff --git a/arch/arm/mach-omap2/board-cm-t3517.c b/arch/arm/mach-omap2/board-cm-t3517.c
index 5b0c777..8f9a64d 100644
--- a/arch/arm/mach-omap2/board-cm-t3517.c
+++ b/arch/arm/mach-omap2/board-cm-t3517.c
@@ -124,8 +124,9 @@ static inline void cm_t3517_init_hecc(void) {}
#if defined(CONFIG_RTC_DRV_V3020) || defined(CONFIG_RTC_DRV_V3020_MODULE)
#define RTC_IO_GPIO (153)
#define RTC_WR_GPIO (154)
-#define RTC_RD_GPIO (160)
+#define RTC_RD_GPIO (53)
#define RTC_CS_GPIO (163)
+#define RTC_CS_EN_GPIO (160)
struct v3020_platform_data cm_t3517_v3020_pdata = {
.use_gpio = 1,
@@ -145,6 +146,16 @@ static struct platform_device cm_t3517_rtc_device = {
static void __init cm_t3517_init_rtc(void)
{
+ int err;
+
+ err = gpio_request(RTC_CS_EN_GPIO, "rtc cs en");
+ if (err) {
+ pr_err("CM-T3517: rtc cs en gpio request failed: %d\n", err);
+ return;
+ }
+
+ gpio_direction_output(RTC_CS_EN_GPIO, 1);
+
platform_device_register(&cm_t3517_rtc_device);
}
#else
@@ -214,12 +225,12 @@ static struct mtd_partition cm_t3517_nand_partitions[] = {
},
{
.name = "linux",
- .offset = MTDPART_OFS_APPEND, /* Offset = 0x280000 */
+ .offset = MTDPART_OFS_APPEND, /* Offset = 0x2A0000 */
.size = 32 * NAND_BLOCK_SIZE,
},
{
.name = "rootfs",
- .offset = MTDPART_OFS_APPEND, /* Offset = 0x680000 */
+ .offset = MTDPART_OFS_APPEND, /* Offset = 0x6A0000 */
.size = MTDPART_SIZ_FULL,
},
};
@@ -256,11 +267,19 @@ static void __init cm_t3517_init_irq(void)
static struct omap_board_mux board_mux[] __initdata = {
/* GPIO186 - Green LED */
OMAP3_MUX(SYS_CLKOUT2, OMAP_MUX_MODE4 | OMAP_PIN_OUTPUT),
- /* RTC GPIOs: IO, WR#, RD#, CS# */
+
+ /* RTC GPIOs: */
+ /* IO - GPIO153 */
OMAP3_MUX(MCBSP4_DR, OMAP_MUX_MODE4 | OMAP_PIN_INPUT),
+ /* WR# - GPIO154 */
OMAP3_MUX(MCBSP4_DX, OMAP_MUX_MODE4 | OMAP_PIN_INPUT),
- OMAP3_MUX(MCBSP_CLKS, OMAP_MUX_MODE4 | OMAP_PIN_INPUT),
+ /* RD# - GPIO53 */
+ OMAP3_MUX(GPMC_NCS2, OMAP_MUX_MODE4 | OMAP_PIN_INPUT),
+ /* CS# - GPIO163 */
OMAP3_MUX(UART3_CTS_RCTX, OMAP_MUX_MODE4 | OMAP_PIN_INPUT),
+ /* CS EN - GPIO160 */
+ OMAP3_MUX(MCBSP_CLKS, OMAP_MUX_MODE4 | OMAP_PIN_INPUT),
+
/* HSUSB1 RESET */
OMAP3_MUX(UART2_TX, OMAP_MUX_MODE4 | OMAP_PIN_OUTPUT),
/* HSUSB2 RESET */
diff --git a/arch/arm/mach-omap2/board-devkit8000.c b/arch/arm/mach-omap2/board-devkit8000.c
index 00bb1fc..e906e05 100644
--- a/arch/arm/mach-omap2/board-devkit8000.c
+++ b/arch/arm/mach-omap2/board-devkit8000.c
@@ -275,8 +275,7 @@ static struct twl4030_gpio_platform_data devkit8000_gpio_data = {
.irq_base = TWL4030_GPIO_IRQ_BASE,
.irq_end = TWL4030_GPIO_IRQ_END,
.use_leds = true,
- .pullups = BIT(1),
- .pulldowns = BIT(2) | BIT(6) | BIT(7) | BIT(8) | BIT(13)
+ .pulldowns = BIT(1) | BIT(2) | BIT(6) | BIT(8) | BIT(13)
| BIT(15) | BIT(16) | BIT(17),
.setup = devkit8000_twl_gpio_setup,
};
diff --git a/arch/arm/mach-omap2/board-igep0020.c b/arch/arm/mach-omap2/board-igep0020.c
index ebaa230..3be85a1 100644
--- a/arch/arm/mach-omap2/board-igep0020.c
+++ b/arch/arm/mach-omap2/board-igep0020.c
@@ -17,6 +17,7 @@
#include <linux/io.h>
#include <linux/gpio.h>
#include <linux/interrupt.h>
+#include <linux/input.h>
#include <linux/regulator/machine.h>
#include <linux/regulator/fixed.h>
@@ -541,6 +542,37 @@ static struct twl4030_codec_data igep2_codec_data = {
.audio = &igep2_audio_data,
};
+static int igep2_keymap[] = {
+ KEY(0, 0, KEY_LEFT),
+ KEY(0, 1, KEY_RIGHT),
+ KEY(0, 2, KEY_A),
+ KEY(0, 3, KEY_B),
+ KEY(1, 0, KEY_DOWN),
+ KEY(1, 1, KEY_UP),
+ KEY(1, 2, KEY_E),
+ KEY(1, 3, KEY_F),
+ KEY(2, 0, KEY_ENTER),
+ KEY(2, 1, KEY_I),
+ KEY(2, 2, KEY_J),
+ KEY(2, 3, KEY_K),
+ KEY(3, 0, KEY_M),
+ KEY(3, 1, KEY_N),
+ KEY(3, 2, KEY_O),
+ KEY(3, 3, KEY_P)
+};
+
+static struct matrix_keymap_data igep2_keymap_data = {
+ .keymap = igep2_keymap,
+ .keymap_size = ARRAY_SIZE(igep2_keymap),
+};
+
+static struct twl4030_keypad_data igep2_keypad_pdata = {
+ .keymap_data = &igep2_keymap_data,
+ .rows = 4,
+ .cols = 4,
+ .rep = 1,
+};
+
static struct twl4030_platform_data igep2_twldata = {
.irq_base = TWL4030_IRQ_BASE,
.irq_end = TWL4030_IRQ_END,
@@ -549,6 +581,7 @@ static struct twl4030_platform_data igep2_twldata = {
.usb = &igep2_usb_data,
.codec = &igep2_codec_data,
.gpio = &igep2_twl4030_gpio_pdata,
+ .keypad = &igep2_keypad_pdata,
.vmmc1 = &igep2_vmmc1,
.vpll2 = &igep2_vpll2,
.vio = &igep2_vio,
diff --git a/arch/arm/mach-omap2/board-igep0030.c b/arch/arm/mach-omap2/board-igep0030.c
index bcccd68..4dc62a9 100644
--- a/arch/arm/mach-omap2/board-igep0030.c
+++ b/arch/arm/mach-omap2/board-igep0030.c
@@ -19,6 +19,7 @@
#include <linux/interrupt.h>
#include <linux/regulator/machine.h>
+#include <linux/regulator/fixed.h>
#include <linux/i2c/twl.h>
#include <linux/mmc/host.h>
@@ -43,7 +44,7 @@
#define IGEP3_GPIO_WIFI_NRESET 139
#define IGEP3_GPIO_BT_NRESET 137
-#define IGEP3_GPIO_USBH_NRESET 115
+#define IGEP3_GPIO_USBH_NRESET 183
#if defined(CONFIG_MTD_ONENAND_OMAP2) || \
@@ -103,7 +104,7 @@ static struct platform_device igep3_onenand_device = {
},
};
-void __init igep3_flash_init(void)
+static void __init igep3_flash_init(void)
{
u8 cs = 0;
u8 onenandcs = GPMC_CS_NUM + 1;
@@ -137,12 +138,11 @@ void __init igep3_flash_init(void)
}
#else
-void __init igep3_flash_init(void) {}
+static void __init igep3_flash_init(void) {}
#endif
-static struct regulator_consumer_supply igep3_vmmc1_supply = {
- .supply = "vmmc",
-};
+static struct regulator_consumer_supply igep3_vmmc1_supply =
+ REGULATOR_SUPPLY("vmmc", "mmci-omap-hs.0");
/* VMMC1 for OMAP VDD_MMC1 (i/o) and MMC1 card */
static struct regulator_init_data igep3_vmmc1 = {
@@ -159,6 +159,52 @@ static struct regulator_init_data igep3_vmmc1 = {
.consumer_supplies = &igep3_vmmc1_supply,
};
+static struct regulator_consumer_supply igep3_vio_supply =
+ REGULATOR_SUPPLY("vmmc_aux", "mmci-omap-hs.1");
+
+static struct regulator_init_data igep3_vio = {
+ .constraints = {
+ .min_uV = 1800000,
+ .max_uV = 1800000,
+ .apply_uV = 1,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL
+ | REGULATOR_MODE_STANDBY,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE
+ | REGULATOR_CHANGE_MODE
+ | REGULATOR_CHANGE_STATUS,
+ },
+ .num_consumer_supplies = 1,
+ .consumer_supplies = &igep3_vio_supply,
+};
+
+static struct regulator_consumer_supply igep3_vmmc2_supply =
+ REGULATOR_SUPPLY("vmmc", "mmci-omap-hs.1");
+
+static struct regulator_init_data igep3_vmmc2 = {
+ .constraints = {
+ .valid_modes_mask = REGULATOR_MODE_NORMAL,
+ .always_on = 1,
+ },
+ .num_consumer_supplies = 1,
+ .consumer_supplies = &igep3_vmmc2_supply,
+};
+
+static struct fixed_voltage_config igep3_vwlan = {
+ .supply_name = "vwlan",
+ .microvolts = 3300000,
+ .gpio = -EINVAL,
+ .enabled_at_boot = 1,
+ .init_data = &igep3_vmmc2,
+};
+
+static struct platform_device igep3_vwlan_device = {
+ .name = "reg-fixed-voltage",
+ .id = 0,
+ .dev = {
+ .platform_data = &igep3_vwlan,
+ },
+};
+
static struct omap2_hsmmc_info mmc[] = {
[0] = {
.mmc = 1,
@@ -254,12 +300,6 @@ static int igep3_twl4030_gpio_setup(struct device *dev,
mmc[0].gpio_cd = gpio + 0;
omap2_hsmmc_init(mmc);
- /*
- * link regulators to MMC adapters ... we "know" the
- * regulators will be set up only *after* we return.
- */
- igep3_vmmc1_supply.dev = mmc[0].dev;
-
/* TWL4030_GPIO_MAX + 1 == ledB (out, active low LED) */
#if !defined(CONFIG_LEDS_GPIO) && !defined(CONFIG_LEDS_GPIO_MODULE)
if ((gpio_request(gpio+TWL4030_GPIO_MAX+1, "gpio-led:green:d1") == 0)
@@ -287,6 +327,10 @@ static struct twl4030_usb_data igep3_twl4030_usb_data = {
.usb_mode = T2_USB_MODE_ULPI,
};
+static struct platform_device *igep3_devices[] __initdata = {
+ &igep3_vwlan_device,
+};
+
static void __init igep3_init_irq(void)
{
omap2_init_common_infrastructure();
@@ -303,6 +347,7 @@ static struct twl4030_platform_data igep3_twl4030_pdata = {
.usb = &igep3_twl4030_usb_data,
.gpio = &igep3_twl4030_gpio_pdata,
.vmmc1 = &igep3_vmmc1,
+ .vio = &igep3_vio,
};
static struct i2c_board_info __initdata igep3_i2c_boardinfo[] = {
@@ -363,8 +408,20 @@ static void __init igep3_wifi_bt_init(void)
void __init igep3_wifi_bt_init(void) {}
#endif
+static const struct ehci_hcd_omap_platform_data ehci_pdata __initconst = {
+ .port_mode[0] = EHCI_HCD_OMAP_MODE_UNKNOWN,
+ .port_mode[1] = EHCI_HCD_OMAP_MODE_PHY,
+ .port_mode[2] = EHCI_HCD_OMAP_MODE_UNKNOWN,
+
+ .phy_reset = true,
+ .reset_gpio_port[0] = -EINVAL,
+ .reset_gpio_port[1] = IGEP3_GPIO_USBH_NRESET,
+ .reset_gpio_port[2] = -EINVAL,
+};
+
#ifdef CONFIG_OMAP_MUX
static struct omap_board_mux board_mux[] __initdata = {
+ OMAP3_MUX(I2C2_SDA, OMAP_MUX_MODE4 | OMAP_PIN_OUTPUT),
{ .reg_offset = OMAP_MUX_TERMINATOR },
};
#endif
@@ -375,9 +432,10 @@ static void __init igep3_init(void)
/* Register I2C busses and drivers */
igep3_i2c_init();
-
+ platform_add_devices(igep3_devices, ARRAY_SIZE(igep3_devices));
omap_serial_init();
usb_musb_init(&musb_board_data);
+ usb_ehci_init(&ehci_pdata);
igep3_flash_init();
igep3_leds_init();
@@ -392,6 +450,7 @@ static void __init igep3_init(void)
MACHINE_START(IGEP0030, "IGEP OMAP3 module")
.boot_params = 0x80000100,
+ .reserve = omap_reserve,
.map_io = omap3_map_io,
.init_irq = igep3_init_irq,
.init_machine = igep3_init,
diff --git a/arch/arm/mach-omap2/board-omap3beagle.c b/arch/arm/mach-omap2/board-omap3beagle.c
index a4fe8e1..46d814a 100644
--- a/arch/arm/mach-omap2/board-omap3beagle.c
+++ b/arch/arm/mach-omap2/board-omap3beagle.c
@@ -207,7 +207,7 @@ static struct omap_dss_device beagle_dvi_device = {
.driver_name = "generic_dpi_panel",
.data = &dvi_panel,
.phy.dpi.data_lines = 24,
- .reset_gpio = 170,
+ .reset_gpio = -EINVAL,
};
static struct omap_dss_device beagle_tv_device = {
@@ -279,6 +279,8 @@ static struct gpio_led gpio_leds[];
static int beagle_twl_gpio_setup(struct device *dev,
unsigned gpio, unsigned ngpio)
{
+ int r;
+
if (omap3_beagle_get_rev() == OMAP3BEAGLE_BOARD_XM) {
mmc[0].gpio_wp = -EINVAL;
} else if ((omap3_beagle_get_rev() == OMAP3BEAGLE_BOARD_C1_3) ||
@@ -299,17 +301,63 @@ static int beagle_twl_gpio_setup(struct device *dev,
/* REVISIT: need ehci-omap hooks for external VBUS
* power switch and overcurrent detect
*/
+ if (omap3_beagle_get_rev() != OMAP3BEAGLE_BOARD_XM) {
+ r = gpio_request(gpio + 1, "EHCI_nOC");
+ if (!r) {
+ r = gpio_direction_input(gpio + 1);
+ if (r)
+ gpio_free(gpio + 1);
+ }
+ if (r)
+ pr_err("%s: unable to configure EHCI_nOC\n", __func__);
+ }
- gpio_request(gpio + 1, "EHCI_nOC");
- gpio_direction_input(gpio + 1);
-
- /* TWL4030_GPIO_MAX + 0 == ledA, EHCI nEN_USB_PWR (out, active low) */
+ /*
+ * TWL4030_GPIO_MAX + 0 == ledA, EHCI nEN_USB_PWR (out, XM active
+ * high / others active low)
+ */
gpio_request(gpio + TWL4030_GPIO_MAX, "nEN_USB_PWR");
- gpio_direction_output(gpio + TWL4030_GPIO_MAX, 0);
+ if (omap3_beagle_get_rev() == OMAP3BEAGLE_BOARD_XM)
+ gpio_direction_output(gpio + TWL4030_GPIO_MAX, 1);
+ else
+ gpio_direction_output(gpio + TWL4030_GPIO_MAX, 0);
+
+ /* DVI reset GPIO is different between beagle revisions */
+ if (omap3_beagle_get_rev() == OMAP3BEAGLE_BOARD_XM)
+ beagle_dvi_device.reset_gpio = 129;
+ else
+ beagle_dvi_device.reset_gpio = 170;
/* TWL4030_GPIO_MAX + 1 == ledB, PMU_STAT (out, active low LED) */
gpio_leds[2].gpio = gpio + TWL4030_GPIO_MAX + 1;
+ /*
+ * gpio + 1 on Xm controls the TFP410's enable line (active low)
+ * gpio + 2 control varies depending on the board rev as follows:
+ * P7/P8 revisions(prototype): Camera EN
+ * A2+ revisions (production): LDO (supplies DVI, serial, led blocks)
+ */
+ if (omap3_beagle_get_rev() == OMAP3BEAGLE_BOARD_XM) {
+ r = gpio_request(gpio + 1, "nDVI_PWR_EN");
+ if (!r) {
+ r = gpio_direction_output(gpio + 1, 0);
+ if (r)
+ gpio_free(gpio + 1);
+ }
+ if (r)
+ pr_err("%s: unable to configure nDVI_PWR_EN\n",
+ __func__);
+ r = gpio_request(gpio + 2, "DVI_LDO_EN");
+ if (!r) {
+ r = gpio_direction_output(gpio + 2, 1);
+ if (r)
+ gpio_free(gpio + 2);
+ }
+ if (r)
+ pr_err("%s: unable to configure DVI_LDO_EN\n",
+ __func__);
+ }
+
return 0;
}
diff --git a/arch/arm/mach-omap2/board-omap4panda.c b/arch/arm/mach-omap2/board-omap4panda.c
index 3094e20..e001a04 100644
--- a/arch/arm/mach-omap2/board-omap4panda.c
+++ b/arch/arm/mach-omap2/board-omap4panda.c
@@ -19,6 +19,7 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h>
+#include <linux/clk.h>
#include <linux/io.h>
#include <linux/leds.h>
#include <linux/gpio.h>
@@ -95,7 +96,16 @@ static const struct ehci_hcd_omap_platform_data ehci_pdata __initconst = {
static void __init omap4_ehci_init(void)
{
int ret;
+ struct clk *phy_ref_clk;
+ /* FREF_CLK3 provides the 19.2 MHz reference clock to the PHY */
+ phy_ref_clk = clk_get(NULL, "auxclk3_ck");
+ if (IS_ERR(phy_ref_clk)) {
+ pr_err("Cannot request auxclk3\n");
+ goto error1;
+ }
+ clk_set_rate(phy_ref_clk, 19200000);
+ clk_enable(phy_ref_clk);
/* disable the power to the usb hub prior to init */
ret = gpio_request(GPIO_HUB_POWER, "hub_power");
diff --git a/arch/arm/mach-omap2/board-zoom-peripherals.c b/arch/arm/mach-omap2/board-zoom-peripherals.c
index 14d95af..e0e040f 100644
--- a/arch/arm/mach-omap2/board-zoom-peripherals.c
+++ b/arch/arm/mach-omap2/board-zoom-peripherals.c
@@ -192,7 +192,7 @@ static struct platform_device omap_vwlan_device = {
},
};
-struct wl12xx_platform_data omap_zoom_wlan_data __initdata = {
+static struct wl12xx_platform_data omap_zoom_wlan_data __initdata = {
.irq = OMAP_GPIO_IRQ(OMAP_ZOOM_WLAN_IRQ_GPIO),
/* ZOOM ref clock is 26 MHz */
.board_ref_clock = 1,
@@ -286,7 +286,7 @@ static int zoom_twl_gpio_setup(struct device *dev,
}
/* EXTMUTE callback function */
-void zoom2_set_hs_extmute(int mute)
+static void zoom2_set_hs_extmute(int mute)
{
gpio_set_value(ZOOM2_HEADSET_EXTMUTE_GPIO, mute);
}
diff --git a/arch/arm/mach-omap2/clock3xxx_data.c b/arch/arm/mach-omap2/clock3xxx_data.c
index d3ab1c9e..403a4a1 100644
--- a/arch/arm/mach-omap2/clock3xxx_data.c
+++ b/arch/arm/mach-omap2/clock3xxx_data.c
@@ -3286,7 +3286,7 @@ static struct omap_clk omap3xxx_clks[] = {
CLK(NULL, "cpefuse_fck", &cpefuse_fck, CK_3430ES2PLUS | CK_AM35XX | CK_36XX),
CLK(NULL, "ts_fck", &ts_fck, CK_3430ES2PLUS | CK_AM35XX | CK_36XX),
CLK(NULL, "usbtll_fck", &usbtll_fck, CK_3430ES2PLUS | CK_AM35XX | CK_36XX),
- CLK("ehci-omap.0", "usbtll_fck", &usbtll_fck, CK_3430ES2 | CK_AM35XX),
+ CLK("ehci-omap.0", "usbtll_fck", &usbtll_fck, CK_3430ES2PLUS | CK_AM35XX | CK_36XX),
CLK("omap-mcbsp.1", "prcm_fck", &core_96m_fck, CK_3XXX),
CLK("omap-mcbsp.5", "prcm_fck", &core_96m_fck, CK_3XXX),
CLK(NULL, "core_96m_fck", &core_96m_fck, CK_3XXX),
diff --git a/arch/arm/mach-omap2/clock44xx_data.c b/arch/arm/mach-omap2/clock44xx_data.c
index e8cb32f..de9ec8d 100644
--- a/arch/arm/mach-omap2/clock44xx_data.c
+++ b/arch/arm/mach-omap2/clock44xx_data.c
@@ -34,7 +34,6 @@
#include "cm2_44xx.h"
#include "cm-regbits-44xx.h"
#include "prm44xx.h"
-#include "prm44xx.h"
#include "prm-regbits-44xx.h"
#include "control.h"
#include "scrm44xx.h"
diff --git a/arch/arm/mach-omap2/clockdomain.c b/arch/arm/mach-omap2/clockdomain.c
index e20b986..58e42f7 100644
--- a/arch/arm/mach-omap2/clockdomain.c
+++ b/arch/arm/mach-omap2/clockdomain.c
@@ -423,6 +423,12 @@ int clkdm_add_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
{
struct clkdm_dep *cd;
+ if (!cpu_is_omap24xx() && !cpu_is_omap34xx()) {
+ pr_err("clockdomain: %s/%s: %s: not yet implemented\n",
+ clkdm1->name, clkdm2->name, __func__);
+ return -EINVAL;
+ }
+
if (!clkdm1 || !clkdm2)
return -EINVAL;
@@ -458,6 +464,12 @@ int clkdm_del_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
{
struct clkdm_dep *cd;
+ if (!cpu_is_omap24xx() && !cpu_is_omap34xx()) {
+ pr_err("clockdomain: %s/%s: %s: not yet implemented\n",
+ clkdm1->name, clkdm2->name, __func__);
+ return -EINVAL;
+ }
+
if (!clkdm1 || !clkdm2)
return -EINVAL;
@@ -500,6 +512,12 @@ int clkdm_read_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
if (!clkdm1 || !clkdm2)
return -EINVAL;
+ if (!cpu_is_omap24xx() && !cpu_is_omap34xx()) {
+ pr_err("clockdomain: %s/%s: %s: not yet implemented\n",
+ clkdm1->name, clkdm2->name, __func__);
+ return -EINVAL;
+ }
+
cd = _clkdm_deps_lookup(clkdm2, clkdm1->wkdep_srcs);
if (IS_ERR(cd)) {
pr_debug("clockdomain: hardware cannot set/clear wake up of "
@@ -527,6 +545,12 @@ int clkdm_clear_all_wkdeps(struct clockdomain *clkdm)
struct clkdm_dep *cd;
u32 mask = 0;
+ if (!cpu_is_omap24xx() && !cpu_is_omap34xx()) {
+ pr_err("clockdomain: %s: %s: not yet implemented\n",
+ clkdm->name, __func__);
+ return -EINVAL;
+ }
+
if (!clkdm)
return -EINVAL;
@@ -830,8 +854,7 @@ void omap2_clkdm_allow_idle(struct clockdomain *clkdm)
* dependency code and data for OMAP4.
*/
if (cpu_is_omap44xx()) {
- WARN_ONCE(1, "clockdomain: OMAP4 wakeup/sleep dependency "
- "support is not yet implemented\n");
+ pr_err("clockdomain: %s: OMAP4 wakeup/sleep dependency support: not yet implemented\n", clkdm->name);
} else {
if (atomic_read(&clkdm->usecount) > 0)
_clkdm_add_autodeps(clkdm);
@@ -872,8 +895,7 @@ void omap2_clkdm_deny_idle(struct clockdomain *clkdm)
* dependency code and data for OMAP4.
*/
if (cpu_is_omap44xx()) {
- WARN_ONCE(1, "clockdomain: OMAP4 wakeup/sleep dependency "
- "support is not yet implemented\n");
+ pr_err("clockdomain: %s: OMAP4 wakeup/sleep dependency support: not yet implemented\n", clkdm->name);
} else {
if (atomic_read(&clkdm->usecount) > 0)
_clkdm_del_autodeps(clkdm);
diff --git a/arch/arm/mach-omap2/clockdomain.h b/arch/arm/mach-omap2/clockdomain.h
index de3faa2..9b459c2 100644
--- a/arch/arm/mach-omap2/clockdomain.h
+++ b/arch/arm/mach-omap2/clockdomain.h
@@ -103,9 +103,7 @@ struct clockdomain {
const char *name;
struct powerdomain *ptr;
} pwrdm;
-#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)
const u16 clktrctrl_mask;
-#endif
const u8 flags;
const u8 dep_bit;
const u8 prcm_partition;
diff --git a/arch/arm/mach-omap2/clockdomains44xx_data.c b/arch/arm/mach-omap2/clockdomains44xx_data.c
index 51920fc..10622c9 100644
--- a/arch/arm/mach-omap2/clockdomains44xx_data.c
+++ b/arch/arm/mach-omap2/clockdomains44xx_data.c
@@ -30,8 +30,6 @@
#include "cm1_44xx.h"
#include "cm2_44xx.h"
-#include "cm1_44xx.h"
-#include "cm2_44xx.h"
#include "cm-regbits-44xx.h"
#include "prm44xx.h"
#include "prcm44xx.h"
diff --git a/arch/arm/mach-omap2/cpuidle34xx.c b/arch/arm/mach-omap2/cpuidle34xx.c
index 11b89e9..f7b22a1 100644
--- a/arch/arm/mach-omap2/cpuidle34xx.c
+++ b/arch/arm/mach-omap2/cpuidle34xx.c
@@ -47,6 +47,8 @@
#define OMAP3_STATE_MAX OMAP3_STATE_C7
+#define CPUIDLE_FLAG_CHECK_BM 0x10000 /* use omap3_enter_idle_bm() */
+
struct omap3_processor_cx {
u8 valid;
u8 type;
diff --git a/arch/arm/mach-omap2/devices.c b/arch/arm/mach-omap2/devices.c
index 381f4eb..2c9c912 100644
--- a/arch/arm/mach-omap2/devices.c
+++ b/arch/arm/mach-omap2/devices.c
@@ -978,7 +978,7 @@ static int __init omap2_init_devices(void)
arch_initcall(omap2_init_devices);
#if defined(CONFIG_OMAP_WATCHDOG) || defined(CONFIG_OMAP_WATCHDOG_MODULE)
-struct omap_device_pm_latency omap_wdt_latency[] = {
+static struct omap_device_pm_latency omap_wdt_latency[] = {
[0] = {
.deactivate_func = omap_device_idle_hwmods,
.activate_func = omap_device_enable_hwmods,
diff --git a/arch/arm/mach-omap2/irq.c b/arch/arm/mach-omap2/irq.c
index 85bf8ca..23049c4 100644
--- a/arch/arm/mach-omap2/irq.c
+++ b/arch/arm/mach-omap2/irq.c
@@ -100,13 +100,14 @@ static int omap_check_spurious(unsigned int irq)
}
/* XXX: FIQ and additional INTC support (only MPU at the moment) */
-static void omap_ack_irq(unsigned int irq)
+static void omap_ack_irq(struct irq_data *d)
{
intc_bank_write_reg(0x1, &irq_banks[0], INTC_CONTROL);
}
-static void omap_mask_irq(unsigned int irq)
+static void omap_mask_irq(struct irq_data *d)
{
+ unsigned int irq = d->irq;
int offset = irq & (~(IRQ_BITS_PER_REG - 1));
if (cpu_is_omap34xx()) {
@@ -128,8 +129,9 @@ static void omap_mask_irq(unsigned int irq)
intc_bank_write_reg(1 << irq, &irq_banks[0], INTC_MIR_SET0 + offset);
}
-static void omap_unmask_irq(unsigned int irq)
+static void omap_unmask_irq(struct irq_data *d)
{
+ unsigned int irq = d->irq;
int offset = irq & (~(IRQ_BITS_PER_REG - 1));
irq &= (IRQ_BITS_PER_REG - 1);
@@ -137,17 +139,17 @@ static void omap_unmask_irq(unsigned int irq)
intc_bank_write_reg(1 << irq, &irq_banks[0], INTC_MIR_CLEAR0 + offset);
}
-static void omap_mask_ack_irq(unsigned int irq)
+static void omap_mask_ack_irq(struct irq_data *d)
{
- omap_mask_irq(irq);
- omap_ack_irq(irq);
+ omap_mask_irq(d);
+ omap_ack_irq(d);
}
static struct irq_chip omap_irq_chip = {
- .name = "INTC",
- .ack = omap_mask_ack_irq,
- .mask = omap_mask_irq,
- .unmask = omap_unmask_irq,
+ .name = "INTC",
+ .irq_ack = omap_mask_ack_irq,
+ .irq_mask = omap_mask_irq,
+ .irq_unmask = omap_unmask_irq,
};
static void __init omap_irq_bank_init_one(struct omap_irq_bank *bank)
diff --git a/arch/arm/mach-omap2/mux.c b/arch/arm/mach-omap2/mux.c
index 17bd639..df8d2f2 100644
--- a/arch/arm/mach-omap2/mux.c
+++ b/arch/arm/mach-omap2/mux.c
@@ -893,7 +893,7 @@ static struct omap_mux * __init omap_mux_list_add(
return NULL;
m = &entry->mux;
- memcpy(m, src, sizeof(struct omap_mux_entry));
+ entry->mux = *src;
#ifdef CONFIG_OMAP_MUX
if (omap_mux_copy_names(src, m)) {
diff --git a/arch/arm/mach-omap2/mux34xx.c b/arch/arm/mach-omap2/mux34xx.c
index 440c98e..17f80e4 100644
--- a/arch/arm/mach-omap2/mux34xx.c
+++ b/arch/arm/mach-omap2/mux34xx.c
@@ -703,7 +703,7 @@ static struct omap_mux __initdata omap3_muxmodes[] = {
* Signals different on CBC package compared to the superset
*/
#if defined(CONFIG_OMAP_MUX) && defined(CONFIG_OMAP_PACKAGE_CBC)
-struct omap_mux __initdata omap3_cbc_subset[] = {
+static struct omap_mux __initdata omap3_cbc_subset[] = {
{ .reg_offset = OMAP_MUX_TERMINATOR },
};
#else
@@ -721,7 +721,7 @@ struct omap_mux __initdata omap3_cbc_subset[] = {
*/
#if defined(CONFIG_OMAP_MUX) && defined(CONFIG_DEBUG_FS) \
&& defined(CONFIG_OMAP_PACKAGE_CBC)
-struct omap_ball __initdata omap3_cbc_ball[] = {
+static struct omap_ball __initdata omap3_cbc_ball[] = {
_OMAP3_BALLENTRY(CAM_D0, "ae16", NULL),
_OMAP3_BALLENTRY(CAM_D1, "ae15", NULL),
_OMAP3_BALLENTRY(CAM_D10, "d25", NULL),
diff --git a/arch/arm/mach-omap2/mux44xx.c b/arch/arm/mach-omap2/mux44xx.c
index 980f11d..c322e7b 100644
--- a/arch/arm/mach-omap2/mux44xx.c
+++ b/arch/arm/mach-omap2/mux44xx.c
@@ -544,7 +544,7 @@ static struct omap_mux __initdata omap4_core_muxmodes[] = {
*/
#if defined(CONFIG_OMAP_MUX) && defined(CONFIG_DEBUG_FS) \
&& defined(CONFIG_OMAP_PACKAGE_CBL)
-struct omap_ball __initdata omap4_core_cbl_ball[] = {
+static struct omap_ball __initdata omap4_core_cbl_ball[] = {
_OMAP4_BALLENTRY(GPMC_AD0, "c12", NULL),
_OMAP4_BALLENTRY(GPMC_AD1, "d12", NULL),
_OMAP4_BALLENTRY(GPMC_AD2, "c13", NULL),
@@ -1262,7 +1262,7 @@ static struct omap_mux __initdata omap4_es2_core_muxmodes[] = {
*/
#if defined(CONFIG_OMAP_MUX) && defined(CONFIG_DEBUG_FS) \
&& defined(CONFIG_OMAP_PACKAGE_CBS)
-struct omap_ball __initdata omap4_core_cbs_ball[] = {
+static struct omap_ball __initdata omap4_core_cbs_ball[] = {
_OMAP4_BALLENTRY(GPMC_AD0, "c12", NULL),
_OMAP4_BALLENTRY(GPMC_AD1, "d12", NULL),
_OMAP4_BALLENTRY(GPMC_AD2, "c13", NULL),
@@ -1546,7 +1546,7 @@ static struct omap_mux __initdata omap4_wkup_muxmodes[] = {
*/
#if defined(CONFIG_OMAP_MUX) && defined(CONFIG_DEBUG_FS) \
&& defined(CONFIG_OMAP_PACKAGE_CBL)
-struct omap_ball __initdata omap4_wkup_cbl_cbs_ball[] = {
+static struct omap_ball __initdata omap4_wkup_cbl_cbs_ball[] = {
_OMAP4_BALLENTRY(SIM_IO, "h4", NULL),
_OMAP4_BALLENTRY(SIM_CLK, "j2", NULL),
_OMAP4_BALLENTRY(SIM_RESET, "g2", NULL),
diff --git a/arch/arm/mach-omap2/omap_twl.c b/arch/arm/mach-omap2/omap_twl.c
index 15f8c6c..00e1d2b 100644
--- a/arch/arm/mach-omap2/omap_twl.c
+++ b/arch/arm/mach-omap2/omap_twl.c
@@ -20,6 +20,8 @@
#include <plat/voltage.h>
+#include "pm.h"
+
#define OMAP3_SRI2C_SLAVE_ADDR 0x12
#define OMAP3_VDD_MPU_SR_CONTROL_REG 0x00
#define OMAP3_VDD_CORE_SR_CONTROL_REG 0x01
@@ -60,17 +62,17 @@ static u8 smps_offset;
#define REG_SMPS_OFFSET 0xE0
-unsigned long twl4030_vsel_to_uv(const u8 vsel)
+static unsigned long twl4030_vsel_to_uv(const u8 vsel)
{
return (((vsel * 125) + 6000)) * 100;
}
-u8 twl4030_uv_to_vsel(unsigned long uv)
+static u8 twl4030_uv_to_vsel(unsigned long uv)
{
return DIV_ROUND_UP(uv - 600000, 12500);
}
-unsigned long twl6030_vsel_to_uv(const u8 vsel)
+static unsigned long twl6030_vsel_to_uv(const u8 vsel)
{
/*
* In TWL6030 depending on the value of SMPS_OFFSET
@@ -102,7 +104,7 @@ unsigned long twl6030_vsel_to_uv(const u8 vsel)
return ((((vsel - 1) * 125) + 6000)) * 100;
}
-u8 twl6030_uv_to_vsel(unsigned long uv)
+static u8 twl6030_uv_to_vsel(unsigned long uv)
{
/*
* In TWL6030 depending on the value of SMPS_OFFSET
diff --git a/arch/arm/mach-omap2/pm_bus.c b/arch/arm/mach-omap2/pm_bus.c
index 784989f..5acd2ab 100644
--- a/arch/arm/mach-omap2/pm_bus.c
+++ b/arch/arm/mach-omap2/pm_bus.c
@@ -20,7 +20,7 @@
#include <plat/omap-pm.h>
#ifdef CONFIG_PM_RUNTIME
-int omap_pm_runtime_suspend(struct device *dev)
+static int omap_pm_runtime_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
int r, ret = 0;
@@ -37,7 +37,7 @@ int omap_pm_runtime_suspend(struct device *dev)
return ret;
};
-int omap_pm_runtime_resume(struct device *dev)
+static int omap_pm_runtime_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
int r;
diff --git a/arch/arm/mach-omap2/powerdomain2xxx_3xxx.c b/arch/arm/mach-omap2/powerdomain2xxx_3xxx.c
index d523389..cf600e2 100644
--- a/arch/arm/mach-omap2/powerdomain2xxx_3xxx.c
+++ b/arch/arm/mach-omap2/powerdomain2xxx_3xxx.c
@@ -19,7 +19,6 @@
#include <plat/prcm.h>
#include "powerdomain.h"
-#include "prm-regbits-34xx.h"
#include "prm.h"
#include "prm-regbits-24xx.h"
#include "prm-regbits-34xx.h"
diff --git a/arch/arm/mach-omap2/prm2xxx_3xxx.h b/arch/arm/mach-omap2/prm2xxx_3xxx.h
index 53d44f6..49654c8 100644
--- a/arch/arm/mach-omap2/prm2xxx_3xxx.h
+++ b/arch/arm/mach-omap2/prm2xxx_3xxx.h
@@ -228,7 +228,67 @@
#ifndef __ASSEMBLER__
-
+/*
+ * Stub omap2xxx/omap3xxx functions so that common files
+ * continue to build when custom builds are used
+ */
+#if defined(CONFIG_ARCH_OMAP4) && !(defined(CONFIG_ARCH_OMAP2) || \
+ defined(CONFIG_ARCH_OMAP3))
+static inline u32 omap2_prm_read_mod_reg(s16 module, u16 idx)
+{
+ WARN(1, "prm: omap2xxx/omap3xxx specific function and "
+ "not suppose to be used on omap4\n");
+ return 0;
+}
+static inline void omap2_prm_write_mod_reg(u32 val, s16 module, u16 idx)
+{
+ WARN(1, "prm: omap2xxx/omap3xxx specific function and "
+ "not suppose to be used on omap4\n");
+}
+static inline u32 omap2_prm_rmw_mod_reg_bits(u32 mask, u32 bits,
+ s16 module, s16 idx)
+{
+ WARN(1, "prm: omap2xxx/omap3xxx specific function and "
+ "not suppose to be used on omap4\n");
+ return 0;
+}
+static inline u32 omap2_prm_set_mod_reg_bits(u32 bits, s16 module, s16 idx)
+{
+ WARN(1, "prm: omap2xxx/omap3xxx specific function and "
+ "not suppose to be used on omap4\n");
+ return 0;
+}
+static inline u32 omap2_prm_clear_mod_reg_bits(u32 bits, s16 module, s16 idx)
+{
+ WARN(1, "prm: omap2xxx/omap3xxx specific function and "
+ "not suppose to be used on omap4\n");
+ return 0;
+}
+static inline u32 omap2_prm_read_mod_bits_shift(s16 domain, s16 idx, u32 mask)
+{
+ WARN(1, "prm: omap2xxx/omap3xxx specific function and "
+ "not suppose to be used on omap4\n");
+ return 0;
+}
+static inline int omap2_prm_is_hardreset_asserted(s16 prm_mod, u8 shift)
+{
+ WARN(1, "prm: omap2xxx/omap3xxx specific function and "
+ "not suppose to be used on omap4\n");
+ return 0;
+}
+static inline int omap2_prm_assert_hardreset(s16 prm_mod, u8 shift)
+{
+ WARN(1, "prm: omap2xxx/omap3xxx specific function and "
+ "not suppose to be used on omap4\n");
+ return 0;
+}
+static inline int omap2_prm_deassert_hardreset(s16 prm_mod, u8 shift)
+{
+ WARN(1, "prm: omap2xxx/omap3xxx specific function and "
+ "not suppose to be used on omap4\n");
+ return 0;
+}
+#else
/* Power/reset management domain register get/set */
extern u32 omap2_prm_read_mod_reg(s16 module, u16 idx);
extern void omap2_prm_write_mod_reg(u32 val, s16 module, u16 idx);
@@ -242,6 +302,7 @@ extern int omap2_prm_is_hardreset_asserted(s16 prm_mod, u8 shift);
extern int omap2_prm_assert_hardreset(s16 prm_mod, u8 shift);
extern int omap2_prm_deassert_hardreset(s16 prm_mod, u8 shift);
+#endif /* CONFIG_ARCH_OMAP4 */
#endif
/*
diff --git a/arch/arm/mach-omap2/sr_device.c b/arch/arm/mach-omap2/sr_device.c
index 786d685..b1e0af1 100644
--- a/arch/arm/mach-omap2/sr_device.c
+++ b/arch/arm/mach-omap2/sr_device.c
@@ -27,6 +27,7 @@
#include <plat/voltage.h>
#include "control.h"
+#include "pm.h"
static bool sr_enable_on_init;
diff --git a/arch/arm/mach-omap2/timer-gp.c b/arch/arm/mach-omap2/timer-gp.c
index 4e48e78..7b7c268 100644
--- a/arch/arm/mach-omap2/timer-gp.c
+++ b/arch/arm/mach-omap2/timer-gp.c
@@ -42,6 +42,8 @@
#include "timer-gp.h"
+#include <plat/common.h>
+
/* MAX_GPTIMER_ID: number of GPTIMERs on the chip */
#define MAX_GPTIMER_ID 12
@@ -176,10 +178,14 @@ static void __init omap2_gp_clockevent_init(void)
/*
* When 32k-timer is enabled, don't use GPTimer for clocksource
* instead, just leave default clocksource which uses the 32k
- * sync counter. See clocksource setup in see plat-omap/common.c.
+ * sync counter. See clocksource setup in plat-omap/counter_32k.c
*/
-static inline void __init omap2_gp_clocksource_init(void) {}
+static void __init omap2_gp_clocksource_init(void)
+{
+ omap_init_clocksource_32k();
+}
+
#else
/*
* clocksource
diff --git a/arch/arm/mach-omap2/wd_timer.c b/arch/arm/mach-omap2/wd_timer.c
index b0c4907..4067669 100644
--- a/arch/arm/mach-omap2/wd_timer.c
+++ b/arch/arm/mach-omap2/wd_timer.c
@@ -13,6 +13,8 @@
#include <plat/omap_hwmod.h>
+#include "wd_timer.h"
+
/*
* In order to avoid any assumptions from bootloader regarding WDT
* settings, WDT module is reset during init. This enables the watchdog
diff --git a/arch/arm/mach-pnx4008/irq.c b/arch/arm/mach-pnx4008/irq.c
index a9ce02b..c69c180 100644
--- a/arch/arm/mach-pnx4008/irq.c
+++ b/arch/arm/mach-pnx4008/irq.c
@@ -36,44 +36,44 @@
static u8 pnx4008_irq_type[NR_IRQS] = PNX4008_IRQ_TYPES;
-static void pnx4008_mask_irq(unsigned int irq)
+static void pnx4008_mask_irq(struct irq_data *d)
{
- __raw_writel(__raw_readl(INTC_ER(irq)) & ~INTC_BIT(irq), INTC_ER(irq)); /* mask interrupt */
+ __raw_writel(__raw_readl(INTC_ER(d->irq)) & ~INTC_BIT(d->irq), INTC_ER(d->irq)); /* mask interrupt */
}
-static void pnx4008_unmask_irq(unsigned int irq)
+static void pnx4008_unmask_irq(struct irq_data *d)
{
- __raw_writel(__raw_readl(INTC_ER(irq)) | INTC_BIT(irq), INTC_ER(irq)); /* unmask interrupt */
+ __raw_writel(__raw_readl(INTC_ER(d->irq)) | INTC_BIT(d->irq), INTC_ER(d->irq)); /* unmask interrupt */
}
-static void pnx4008_mask_ack_irq(unsigned int irq)
+static void pnx4008_mask_ack_irq(struct irq_data *d)
{
- __raw_writel(__raw_readl(INTC_ER(irq)) & ~INTC_BIT(irq), INTC_ER(irq)); /* mask interrupt */
- __raw_writel(INTC_BIT(irq), INTC_SR(irq)); /* clear interrupt status */
+ __raw_writel(__raw_readl(INTC_ER(d->irq)) & ~INTC_BIT(d->irq), INTC_ER(d->irq)); /* mask interrupt */
+ __raw_writel(INTC_BIT(d->irq), INTC_SR(d->irq)); /* clear interrupt status */
}
-static int pnx4008_set_irq_type(unsigned int irq, unsigned int type)
+static int pnx4008_set_irq_type(struct irq_data *d, unsigned int type)
{
switch (type) {
case IRQ_TYPE_EDGE_RISING:
- __raw_writel(__raw_readl(INTC_ATR(irq)) | INTC_BIT(irq), INTC_ATR(irq)); /*edge sensitive */
- __raw_writel(__raw_readl(INTC_APR(irq)) | INTC_BIT(irq), INTC_APR(irq)); /*rising edge */
- set_irq_handler(irq, handle_edge_irq);
+ __raw_writel(__raw_readl(INTC_ATR(d->irq)) | INTC_BIT(d->irq), INTC_ATR(d->irq)); /*edge sensitive */
+ __raw_writel(__raw_readl(INTC_APR(d->irq)) | INTC_BIT(d->irq), INTC_APR(d->irq)); /*rising edge */
+ set_irq_handler(d->irq, handle_edge_irq);
break;
case IRQ_TYPE_EDGE_FALLING:
- __raw_writel(__raw_readl(INTC_ATR(irq)) | INTC_BIT(irq), INTC_ATR(irq)); /*edge sensitive */
- __raw_writel(__raw_readl(INTC_APR(irq)) & ~INTC_BIT(irq), INTC_APR(irq)); /*falling edge */
- set_irq_handler(irq, handle_edge_irq);
+ __raw_writel(__raw_readl(INTC_ATR(d->irq)) | INTC_BIT(d->irq), INTC_ATR(d->irq)); /*edge sensitive */
+ __raw_writel(__raw_readl(INTC_APR(d->irq)) & ~INTC_BIT(d->irq), INTC_APR(d->irq)); /*falling edge */
+ set_irq_handler(d->irq, handle_edge_irq);
break;
case IRQ_TYPE_LEVEL_LOW:
- __raw_writel(__raw_readl(INTC_ATR(irq)) & ~INTC_BIT(irq), INTC_ATR(irq)); /*level sensitive */
- __raw_writel(__raw_readl(INTC_APR(irq)) & ~INTC_BIT(irq), INTC_APR(irq)); /*low level */
- set_irq_handler(irq, handle_level_irq);
+ __raw_writel(__raw_readl(INTC_ATR(d->irq)) & ~INTC_BIT(d->irq), INTC_ATR(d->irq)); /*level sensitive */
+ __raw_writel(__raw_readl(INTC_APR(d->irq)) & ~INTC_BIT(d->irq), INTC_APR(d->irq)); /*low level */
+ set_irq_handler(d->irq, handle_level_irq);
break;
case IRQ_TYPE_LEVEL_HIGH:
- __raw_writel(__raw_readl(INTC_ATR(irq)) & ~INTC_BIT(irq), INTC_ATR(irq)); /*level sensitive */
- __raw_writel(__raw_readl(INTC_APR(irq)) | INTC_BIT(irq), INTC_APR(irq)); /* high level */
- set_irq_handler(irq, handle_level_irq);
+ __raw_writel(__raw_readl(INTC_ATR(d->irq)) & ~INTC_BIT(d->irq), INTC_ATR(d->irq)); /*level sensitive */
+ __raw_writel(__raw_readl(INTC_APR(d->irq)) | INTC_BIT(d->irq), INTC_APR(d->irq)); /* high level */
+ set_irq_handler(d->irq, handle_level_irq);
break;
/* IRQ_TYPE_EDGE_BOTH is not supported */
@@ -85,10 +85,10 @@ static int pnx4008_set_irq_type(unsigned int irq, unsigned int type)
}
static struct irq_chip pnx4008_irq_chip = {
- .ack = pnx4008_mask_ack_irq,
- .mask = pnx4008_mask_irq,
- .unmask = pnx4008_unmask_irq,
- .set_type = pnx4008_set_irq_type,
+ .irq_ack = pnx4008_mask_ack_irq,
+ .irq_mask = pnx4008_mask_irq,
+ .irq_unmask = pnx4008_unmask_irq,
+ .irq_set_type = pnx4008_set_irq_type,
};
void __init pnx4008_init_irq(void)
@@ -99,14 +99,18 @@ void __init pnx4008_init_irq(void)
for (i = 0; i < NR_IRQS; i++) {
set_irq_flags(i, IRQF_VALID);
set_irq_chip(i, &pnx4008_irq_chip);
- pnx4008_set_irq_type(i, pnx4008_irq_type[i]);
+ pnx4008_set_irq_type(irq_get_irq_data(i), pnx4008_irq_type[i]);
}
/* configure and enable IRQ 0,1,30,31 (cascade interrupts) */
- pnx4008_set_irq_type(SUB1_IRQ_N, pnx4008_irq_type[SUB1_IRQ_N]);
- pnx4008_set_irq_type(SUB2_IRQ_N, pnx4008_irq_type[SUB2_IRQ_N]);
- pnx4008_set_irq_type(SUB1_FIQ_N, pnx4008_irq_type[SUB1_FIQ_N]);
- pnx4008_set_irq_type(SUB2_FIQ_N, pnx4008_irq_type[SUB2_FIQ_N]);
+ pnx4008_set_irq_type(irq_get_irq_data(SUB1_IRQ_N),
+ pnx4008_irq_type[SUB1_IRQ_N]);
+ pnx4008_set_irq_type(irq_get_irq_data(SUB2_IRQ_N),
+ pnx4008_irq_type[SUB2_IRQ_N]);
+ pnx4008_set_irq_type(irq_get_irq_data(SUB1_FIQ_N),
+ pnx4008_irq_type[SUB1_FIQ_N]);
+ pnx4008_set_irq_type(irq_get_irq_data(SUB2_FIQ_N),
+ pnx4008_irq_type[SUB2_FIQ_N]);
/* mask all others */
__raw_writel((1 << SUB2_FIQ_N) | (1 << SUB1_FIQ_N) |
diff --git a/arch/arm/mach-pxa/balloon3.c b/arch/arm/mach-pxa/balloon3.c
index ccb2d0c..a134a14 100644
--- a/arch/arm/mach-pxa/balloon3.c
+++ b/arch/arm/mach-pxa/balloon3.c
@@ -477,25 +477,25 @@ static inline void balloon3_leds_init(void) {}
/******************************************************************************
* FPGA IRQ
******************************************************************************/
-static void balloon3_mask_irq(unsigned int irq)
+static void balloon3_mask_irq(struct irq_data *d)
{
- int balloon3_irq = (irq - BALLOON3_IRQ(0));
+ int balloon3_irq = (d->irq - BALLOON3_IRQ(0));
balloon3_irq_enabled &= ~(1 << balloon3_irq);
__raw_writel(~balloon3_irq_enabled, BALLOON3_INT_CONTROL_REG);
}
-static void balloon3_unmask_irq(unsigned int irq)
+static void balloon3_unmask_irq(struct irq_data *d)
{
- int balloon3_irq = (irq - BALLOON3_IRQ(0));
+ int balloon3_irq = (d->irq - BALLOON3_IRQ(0));
balloon3_irq_enabled |= (1 << balloon3_irq);
__raw_writel(~balloon3_irq_enabled, BALLOON3_INT_CONTROL_REG);
}
static struct irq_chip balloon3_irq_chip = {
.name = "FPGA",
- .ack = balloon3_mask_irq,
- .mask = balloon3_mask_irq,
- .unmask = balloon3_unmask_irq,
+ .irq_ack = balloon3_mask_irq,
+ .irq_mask = balloon3_mask_irq,
+ .irq_unmask = balloon3_unmask_irq,
};
static void balloon3_irq_handler(unsigned int irq, struct irq_desc *desc)
@@ -504,8 +504,13 @@ static void balloon3_irq_handler(unsigned int irq, struct irq_desc *desc)
balloon3_irq_enabled;
do {
/* clear useless edge notification */
- if (desc->chip->ack)
- desc->chip->ack(BALLOON3_AUX_NIRQ);
+ if (desc->irq_data.chip->irq_ack) {
+ struct irq_data *d;
+
+ d = irq_get_irq_data(BALLOON3_AUX_NIRQ);
+ desc->irq_data.chip->irq_ack(d);
+ }
+
while (pending) {
irq = BALLOON3_IRQ(0) + __ffs(pending);
generic_handle_irq(irq);
diff --git a/arch/arm/mach-pxa/clock-pxa3xx.c b/arch/arm/mach-pxa/clock-pxa3xx.c
index 1b08a34..3f864cd 100644
--- a/arch/arm/mach-pxa/clock-pxa3xx.c
+++ b/arch/arm/mach-pxa/clock-pxa3xx.c
@@ -115,7 +115,6 @@ static unsigned long clk_pxa3xx_smemc_getrate(struct clk *clk)
{
unsigned long acsr = ACSR;
unsigned long memclkcfg = __raw_readl(MEMCLKCFG);
- unsigned int smcfs = (acsr >> 23) & 0x7;
return BASE_CLK * smcfs_mult[(acsr >> 23) & 0x7] /
df_clkdiv[(memclkcfg >> 16) & 0x3];
diff --git a/arch/arm/mach-pxa/cm-x2xx-pci.c b/arch/arm/mach-pxa/cm-x2xx-pci.c
index 0f31305..a2380cd 100644
--- a/arch/arm/mach-pxa/cm-x2xx-pci.c
+++ b/arch/arm/mach-pxa/cm-x2xx-pci.c
@@ -59,7 +59,7 @@ void __init cmx2xx_pci_adjust_zones(unsigned long *zone_size,
static void cmx2xx_it8152_irq_demux(unsigned int irq, struct irq_desc *desc)
{
/* clear our parent irq */
- desc->chip->ack(irq);
+ desc->irq_data.chip->irq_ack(&desc->irq_data);
it8152_irq_demux(irq, desc);
}
diff --git a/arch/arm/mach-pxa/generic.c b/arch/arm/mach-pxa/generic.c
index d6e15f7..f5d91ef 100644
--- a/arch/arm/mach-pxa/generic.c
+++ b/arch/arm/mach-pxa/generic.c
@@ -22,7 +22,6 @@
#include <mach/hardware.h>
#include <asm/system.h>
-#include <asm/pgtable.h>
#include <asm/mach/map.h>
#include <asm/mach-types.h>
diff --git a/arch/arm/mach-pxa/generic.h b/arch/arm/mach-pxa/generic.h
index 6205dc9..a079d8b 100644
--- a/arch/arm/mach-pxa/generic.h
+++ b/arch/arm/mach-pxa/generic.h
@@ -9,11 +9,13 @@
* published by the Free Software Foundation.
*/
+struct irq_data;
struct sys_timer;
extern struct sys_timer pxa_timer;
extern void __init pxa_init_irq(int irq_nr,
- int (*set_wake)(unsigned int, unsigned int));
+ int (*set_wake)(struct irq_data *,
+ unsigned int));
extern void __init pxa25x_init_irq(void);
#ifdef CONFIG_CPU_PXA26x
extern void __init pxa26x_init_irq(void);
diff --git a/arch/arm/mach-pxa/irq.c b/arch/arm/mach-pxa/irq.c
index 54e91c9..2693e3c 100644
--- a/arch/arm/mach-pxa/irq.c
+++ b/arch/arm/mach-pxa/irq.c
@@ -53,37 +53,48 @@ static inline int cpu_has_ipr(void)
return !cpu_is_pxa25x();
}
-static void pxa_mask_irq(unsigned int irq)
+static inline void __iomem *irq_base(int i)
+{
+ static unsigned long phys_base[] = {
+ 0x40d00000,
+ 0x40d0009c,
+ 0x40d00130,
+ };
+
+ return (void __iomem *)io_p2v(phys_base[i]);
+}
+
+static void pxa_mask_irq(struct irq_data *d)
{
- void __iomem *base = get_irq_chip_data(irq);
+ void __iomem *base = irq_data_get_irq_chip_data(d);
uint32_t icmr = __raw_readl(base + ICMR);
- icmr &= ~(1 << IRQ_BIT(irq));
+ icmr &= ~(1 << IRQ_BIT(d->irq));
__raw_writel(icmr, base + ICMR);
}
-static void pxa_unmask_irq(unsigned int irq)
+static void pxa_unmask_irq(struct irq_data *d)
{
- void __iomem *base = get_irq_chip_data(irq);
+ void __iomem *base = irq_data_get_irq_chip_data(d);
uint32_t icmr = __raw_readl(base + ICMR);
- icmr |= 1 << IRQ_BIT(irq);
+ icmr |= 1 << IRQ_BIT(d->irq);
__raw_writel(icmr, base + ICMR);
}
static struct irq_chip pxa_internal_irq_chip = {
.name = "SC",
- .ack = pxa_mask_irq,
- .mask = pxa_mask_irq,
- .unmask = pxa_unmask_irq,
+ .irq_ack = pxa_mask_irq,
+ .irq_mask = pxa_mask_irq,
+ .irq_unmask = pxa_unmask_irq,
};
/*
* GPIO IRQs for GPIO 0 and 1
*/
-static int pxa_set_low_gpio_type(unsigned int irq, unsigned int type)
+static int pxa_set_low_gpio_type(struct irq_data *d, unsigned int type)
{
- int gpio = irq - IRQ_GPIO0;
+ int gpio = d->irq - IRQ_GPIO0;
if (__gpio_is_occupied(gpio)) {
pr_err("%s failed: GPIO is configured\n", __func__);
@@ -103,31 +114,17 @@ static int pxa_set_low_gpio_type(unsigned int irq, unsigned int type)
return 0;
}
-static void pxa_ack_low_gpio(unsigned int irq)
-{
- GEDR0 = (1 << (irq - IRQ_GPIO0));
-}
-
-static void pxa_mask_low_gpio(unsigned int irq)
-{
- struct irq_desc *desc = irq_to_desc(irq);
-
- desc->chip->mask(irq);
-}
-
-static void pxa_unmask_low_gpio(unsigned int irq)
+static void pxa_ack_low_gpio(struct irq_data *d)
{
- struct irq_desc *desc = irq_to_desc(irq);
-
- desc->chip->unmask(irq);
+ GEDR0 = (1 << (d->irq - IRQ_GPIO0));
}
static struct irq_chip pxa_low_gpio_chip = {
.name = "GPIO-l",
- .ack = pxa_ack_low_gpio,
- .mask = pxa_mask_low_gpio,
- .unmask = pxa_unmask_low_gpio,
- .set_type = pxa_set_low_gpio_type,
+ .irq_ack = pxa_ack_low_gpio,
+ .irq_mask = pxa_mask_irq,
+ .irq_unmask = pxa_unmask_irq,
+ .irq_set_type = pxa_set_low_gpio_type,
};
static void __init pxa_init_low_gpio_irq(set_wake_t fn)
@@ -141,22 +138,12 @@ static void __init pxa_init_low_gpio_irq(set_wake_t fn)
for (irq = IRQ_GPIO0; irq <= IRQ_GPIO1; irq++) {
set_irq_chip(irq, &pxa_low_gpio_chip);
+ set_irq_chip_data(irq, irq_base(0));
set_irq_handler(irq, handle_edge_irq);
set_irq_flags(irq, IRQF_VALID);
}
- pxa_low_gpio_chip.set_wake = fn;
-}
-
-static inline void __iomem *irq_base(int i)
-{
- static unsigned long phys_base[] = {
- 0x40d00000,
- 0x40d0009c,
- 0x40d00130,
- };
-
- return (void __iomem *)io_p2v(phys_base[i >> 5]);
+ pxa_low_gpio_chip.irq_set_wake = fn;
}
void __init pxa_init_irq(int irq_nr, set_wake_t fn)
@@ -168,7 +155,7 @@ void __init pxa_init_irq(int irq_nr, set_wake_t fn)
pxa_internal_irq_nr = irq_nr;
for (n = 0; n < irq_nr; n += 32) {
- void __iomem *base = irq_base(n);
+ void __iomem *base = irq_base(n >> 5);
__raw_writel(0, base + ICMR); /* disable all IRQs */
__raw_writel(0, base + ICLR); /* all IRQs are IRQ, not FIQ */
@@ -188,7 +175,7 @@ void __init pxa_init_irq(int irq_nr, set_wake_t fn)
/* only unmasked interrupts kick us out of idle */
__raw_writel(1, irq_base(0) + ICCR);
- pxa_internal_irq_chip.set_wake = fn;
+ pxa_internal_irq_chip.irq_set_wake = fn;
pxa_init_low_gpio_irq(fn);
}
@@ -200,7 +187,7 @@ static int pxa_irq_suspend(struct sys_device *dev, pm_message_t state)
{
int i;
- for (i = 0; i < pxa_internal_irq_nr; i += 32) {
+ for (i = 0; i < pxa_internal_irq_nr / 32; i++) {
void __iomem *base = irq_base(i);
saved_icmr[i] = __raw_readl(base + ICMR);
@@ -219,14 +206,14 @@ static int pxa_irq_resume(struct sys_device *dev)
{
int i;
- for (i = 0; i < pxa_internal_irq_nr; i += 32) {
+ for (i = 0; i < pxa_internal_irq_nr / 32; i++) {
void __iomem *base = irq_base(i);
__raw_writel(saved_icmr[i], base + ICMR);
__raw_writel(0, base + ICLR);
}
- if (!cpu_is_pxa25x())
+ if (cpu_has_ipr())
for (i = 0; i < pxa_internal_irq_nr; i++)
__raw_writel(saved_ipr[i], IRQ_BASE + IPR(i));
diff --git a/arch/arm/mach-pxa/lpd270.c b/arch/arm/mach-pxa/lpd270.c
index 8ab62a6..c9a3e77 100644
--- a/arch/arm/mach-pxa/lpd270.c
+++ b/arch/arm/mach-pxa/lpd270.c
@@ -95,9 +95,9 @@ static unsigned long lpd270_pin_config[] __initdata = {
static unsigned int lpd270_irq_enabled;
-static void lpd270_mask_irq(unsigned int irq)
+static void lpd270_mask_irq(struct irq_data *d)
{
- int lpd270_irq = irq - LPD270_IRQ(0);
+ int lpd270_irq = d->irq - LPD270_IRQ(0);
__raw_writew(~(1 << lpd270_irq), LPD270_INT_STATUS);
@@ -105,9 +105,9 @@ static void lpd270_mask_irq(unsigned int irq)
__raw_writew(lpd270_irq_enabled, LPD270_INT_MASK);
}
-static void lpd270_unmask_irq(unsigned int irq)
+static void lpd270_unmask_irq(struct irq_data *d)
{
- int lpd270_irq = irq - LPD270_IRQ(0);
+ int lpd270_irq = d->irq - LPD270_IRQ(0);
lpd270_irq_enabled |= 1 << lpd270_irq;
__raw_writew(lpd270_irq_enabled, LPD270_INT_MASK);
@@ -115,9 +115,9 @@ static void lpd270_unmask_irq(unsigned int irq)
static struct irq_chip lpd270_irq_chip = {
.name = "CPLD",
- .ack = lpd270_mask_irq,
- .mask = lpd270_mask_irq,
- .unmask = lpd270_unmask_irq,
+ .irq_ack = lpd270_mask_irq,
+ .irq_mask = lpd270_mask_irq,
+ .irq_unmask = lpd270_unmask_irq,
};
static void lpd270_irq_handler(unsigned int irq, struct irq_desc *desc)
@@ -126,7 +126,8 @@ static void lpd270_irq_handler(unsigned int irq, struct irq_desc *desc)
pending = __raw_readw(LPD270_INT_STATUS) & lpd270_irq_enabled;
do {
- desc->chip->ack(irq); /* clear useless edge notification */
+ /* clear useless edge notification */
+ desc->irq_data.chip->irq_ack(&desc->irq_data);
if (likely(pending)) {
irq = LPD270_IRQ(0) + __ffs(pending);
generic_handle_irq(irq);
diff --git a/arch/arm/mach-pxa/lubbock.c b/arch/arm/mach-pxa/lubbock.c
index 3072dbe..dca20de 100644
--- a/arch/arm/mach-pxa/lubbock.c
+++ b/arch/arm/mach-pxa/lubbock.c
@@ -122,15 +122,15 @@ EXPORT_SYMBOL(lubbock_set_misc_wr);
static unsigned long lubbock_irq_enabled;
-static void lubbock_mask_irq(unsigned int irq)
+static void lubbock_mask_irq(struct irq_data *d)
{
- int lubbock_irq = (irq - LUBBOCK_IRQ(0));
+ int lubbock_irq = (d->irq - LUBBOCK_IRQ(0));
LUB_IRQ_MASK_EN = (lubbock_irq_enabled &= ~(1 << lubbock_irq));
}
-static void lubbock_unmask_irq(unsigned int irq)
+static void lubbock_unmask_irq(struct irq_data *d)
{
- int lubbock_irq = (irq - LUBBOCK_IRQ(0));
+ int lubbock_irq = (d->irq - LUBBOCK_IRQ(0));
/* the irq can be acknowledged only if deasserted, so it's done here */
LUB_IRQ_SET_CLR &= ~(1 << lubbock_irq);
LUB_IRQ_MASK_EN = (lubbock_irq_enabled |= (1 << lubbock_irq));
@@ -138,16 +138,17 @@ static void lubbock_unmask_irq(unsigned int irq)
static struct irq_chip lubbock_irq_chip = {
.name = "FPGA",
- .ack = lubbock_mask_irq,
- .mask = lubbock_mask_irq,
- .unmask = lubbock_unmask_irq,
+ .irq_ack = lubbock_mask_irq,
+ .irq_mask = lubbock_mask_irq,
+ .irq_unmask = lubbock_unmask_irq,
};
static void lubbock_irq_handler(unsigned int irq, struct irq_desc *desc)
{
unsigned long pending = LUB_IRQ_SET_CLR & lubbock_irq_enabled;
do {
- desc->chip->ack(irq); /* clear our parent irq */
+ /* clear our parent irq */
+ desc->irq_data.chip->irq_ack(&desc->irq_data);
if (likely(pending)) {
irq = LUBBOCK_IRQ(0) + __ffs(pending);
generic_handle_irq(irq);
diff --git a/arch/arm/mach-pxa/mainstone.c b/arch/arm/mach-pxa/mainstone.c
index 740c035..d4b6f23 100644
--- a/arch/arm/mach-pxa/mainstone.c
+++ b/arch/arm/mach-pxa/mainstone.c
@@ -123,15 +123,15 @@ static unsigned long mainstone_pin_config[] = {
static unsigned long mainstone_irq_enabled;
-static void mainstone_mask_irq(unsigned int irq)
+static void mainstone_mask_irq(struct irq_data *d)
{
- int mainstone_irq = (irq - MAINSTONE_IRQ(0));
+ int mainstone_irq = (d->irq - MAINSTONE_IRQ(0));
MST_INTMSKENA = (mainstone_irq_enabled &= ~(1 << mainstone_irq));
}
-static void mainstone_unmask_irq(unsigned int irq)
+static void mainstone_unmask_irq(struct irq_data *d)
{
- int mainstone_irq = (irq - MAINSTONE_IRQ(0));
+ int mainstone_irq = (d->irq - MAINSTONE_IRQ(0));
/* the irq can be acknowledged only if deasserted, so it's done here */
MST_INTSETCLR &= ~(1 << mainstone_irq);
MST_INTMSKENA = (mainstone_irq_enabled |= (1 << mainstone_irq));
@@ -139,16 +139,17 @@ static void mainstone_unmask_irq(unsigned int irq)
static struct irq_chip mainstone_irq_chip = {
.name = "FPGA",
- .ack = mainstone_mask_irq,
- .mask = mainstone_mask_irq,
- .unmask = mainstone_unmask_irq,
+ .irq_ack = mainstone_mask_irq,
+ .irq_mask = mainstone_mask_irq,
+ .irq_unmask = mainstone_unmask_irq,
};
static void mainstone_irq_handler(unsigned int irq, struct irq_desc *desc)
{
unsigned long pending = MST_INTSETCLR & mainstone_irq_enabled;
do {
- desc->chip->ack(irq); /* clear useless edge notification */
+ /* clear useless edge notification */
+ desc->irq_data.chip->irq_ack(&desc->irq_data);
if (likely(pending)) {
irq = MAINSTONE_IRQ(0) + __ffs(pending);
generic_handle_irq(irq);
diff --git a/arch/arm/mach-pxa/pcm990-baseboard.c b/arch/arm/mach-pxa/pcm990-baseboard.c
index f33647a..90820fa 100644
--- a/arch/arm/mach-pxa/pcm990-baseboard.c
+++ b/arch/arm/mach-pxa/pcm990-baseboard.c
@@ -241,23 +241,23 @@ static struct platform_device pcm990_backlight_device = {
static unsigned long pcm990_irq_enabled;
-static void pcm990_mask_ack_irq(unsigned int irq)
+static void pcm990_mask_ack_irq(struct irq_data *d)
{
- int pcm990_irq = (irq - PCM027_IRQ(0));
+ int pcm990_irq = (d->irq - PCM027_IRQ(0));
PCM990_INTMSKENA = (pcm990_irq_enabled &= ~(1 << pcm990_irq));
}
-static void pcm990_unmask_irq(unsigned int irq)
+static void pcm990_unmask_irq(struct irq_data *d)
{
- int pcm990_irq = (irq - PCM027_IRQ(0));
+ int pcm990_irq = (d->irq - PCM027_IRQ(0));
/* the irq can be acknowledged only if deasserted, so it's done here */
PCM990_INTSETCLR |= 1 << pcm990_irq;
PCM990_INTMSKENA = (pcm990_irq_enabled |= (1 << pcm990_irq));
}
static struct irq_chip pcm990_irq_chip = {
- .mask_ack = pcm990_mask_ack_irq,
- .unmask = pcm990_unmask_irq,
+ .irq_mask_ack = pcm990_mask_ack_irq,
+ .irq_unmask = pcm990_unmask_irq,
};
static void pcm990_irq_handler(unsigned int irq, struct irq_desc *desc)
@@ -265,7 +265,8 @@ static void pcm990_irq_handler(unsigned int irq, struct irq_desc *desc)
unsigned long pending = (~PCM990_INTSETCLR) & pcm990_irq_enabled;
do {
- desc->chip->ack(irq); /* clear our parent IRQ */
+ /* clear our parent IRQ */
+ desc->irq_data.chip->irq_ack(&desc->irq_data);
if (likely(pending)) {
irq = PCM027_IRQ(0) + __ffs(pending);
generic_handle_irq(irq);
diff --git a/arch/arm/mach-pxa/pxa25x.c b/arch/arm/mach-pxa/pxa25x.c
index 3f5241c..fbc5b77 100644
--- a/arch/arm/mach-pxa/pxa25x.c
+++ b/arch/arm/mach-pxa/pxa25x.c
@@ -22,6 +22,7 @@
#include <linux/platform_device.h>
#include <linux/suspend.h>
#include <linux/sysdev.h>
+#include <linux/irq.h>
#include <asm/mach/map.h>
#include <mach/hardware.h>
@@ -282,15 +283,15 @@ static inline void pxa25x_init_pm(void) {}
/* PXA25x: supports wakeup from GPIO0..GPIO15 and RTC alarm
*/
-static int pxa25x_set_wake(unsigned int irq, unsigned int on)
+static int pxa25x_set_wake(struct irq_data *d, unsigned int on)
{
- int gpio = IRQ_TO_GPIO(irq);
+ int gpio = IRQ_TO_GPIO(d->irq);
uint32_t mask = 0;
if (gpio >= 0 && gpio < 85)
return gpio_set_wake(gpio, on);
- if (irq == IRQ_RTCAlrm) {
+ if (d->irq == IRQ_RTCAlrm) {
mask = PWER_RTC;
goto set_pwer;
}
diff --git a/arch/arm/mach-pxa/pxa27x.c b/arch/arm/mach-pxa/pxa27x.c
index b2130b7..987301f 100644
--- a/arch/arm/mach-pxa/pxa27x.c
+++ b/arch/arm/mach-pxa/pxa27x.c
@@ -18,6 +18,7 @@
#include <linux/platform_device.h>
#include <linux/sysdev.h>
#include <linux/io.h>
+#include <linux/irq.h>
#include <asm/mach/map.h>
#include <mach/hardware.h>
@@ -343,18 +344,18 @@ static inline void pxa27x_init_pm(void) {}
/* PXA27x: Various gpios can issue wakeup events. This logic only
* handles the simple cases, not the WEMUX2 and WEMUX3 options
*/
-static int pxa27x_set_wake(unsigned int irq, unsigned int on)
+static int pxa27x_set_wake(struct irq_data *d, unsigned int on)
{
- int gpio = IRQ_TO_GPIO(irq);
+ int gpio = IRQ_TO_GPIO(d->irq);
uint32_t mask;
if (gpio >= 0 && gpio < 128)
return gpio_set_wake(gpio, on);
- if (irq == IRQ_KEYPAD)
+ if (d->irq == IRQ_KEYPAD)
return keypad_set_wake(on);
- switch (irq) {
+ switch (d->irq) {
case IRQ_RTCAlrm:
mask = PWER_RTC;
break;
diff --git a/arch/arm/mach-pxa/pxa3xx.c b/arch/arm/mach-pxa/pxa3xx.c
index e14818f..a7a19e1 100644
--- a/arch/arm/mach-pxa/pxa3xx.c
+++ b/arch/arm/mach-pxa/pxa3xx.c
@@ -229,11 +229,11 @@ static void __init pxa3xx_init_pm(void)
pxa_cpu_pm_fns = &pxa3xx_cpu_pm_fns;
}
-static int pxa3xx_set_wake(unsigned int irq, unsigned int on)
+static int pxa3xx_set_wake(struct irq_data *d, unsigned int on)
{
unsigned long flags, mask = 0;
- switch (irq) {
+ switch (d->irq) {
case IRQ_SSP3:
mask = ADXER_MFP_WSSP3;
break;
@@ -322,40 +322,40 @@ static inline void pxa3xx_init_pm(void) {}
#define pxa3xx_set_wake NULL
#endif
-static void pxa_ack_ext_wakeup(unsigned int irq)
+static void pxa_ack_ext_wakeup(struct irq_data *d)
{
- PECR |= PECR_IS(irq - IRQ_WAKEUP0);
+ PECR |= PECR_IS(d->irq - IRQ_WAKEUP0);
}
-static void pxa_mask_ext_wakeup(unsigned int irq)
+static void pxa_mask_ext_wakeup(struct irq_data *d)
{
- ICMR2 &= ~(1 << ((irq - PXA_IRQ(0)) & 0x1f));
- PECR &= ~PECR_IE(irq - IRQ_WAKEUP0);
+ ICMR2 &= ~(1 << ((d->irq - PXA_IRQ(0)) & 0x1f));
+ PECR &= ~PECR_IE(d->irq - IRQ_WAKEUP0);
}
-static void pxa_unmask_ext_wakeup(unsigned int irq)
+static void pxa_unmask_ext_wakeup(struct irq_data *d)
{
- ICMR2 |= 1 << ((irq - PXA_IRQ(0)) & 0x1f);
- PECR |= PECR_IE(irq - IRQ_WAKEUP0);
+ ICMR2 |= 1 << ((d->irq - PXA_IRQ(0)) & 0x1f);
+ PECR |= PECR_IE(d->irq - IRQ_WAKEUP0);
}
-static int pxa_set_ext_wakeup_type(unsigned int irq, unsigned int flow_type)
+static int pxa_set_ext_wakeup_type(struct irq_data *d, unsigned int flow_type)
{
if (flow_type & IRQ_TYPE_EDGE_RISING)
- PWER |= 1 << (irq - IRQ_WAKEUP0);
+ PWER |= 1 << (d->irq - IRQ_WAKEUP0);
if (flow_type & IRQ_TYPE_EDGE_FALLING)
- PWER |= 1 << (irq - IRQ_WAKEUP0 + 2);
+ PWER |= 1 << (d->irq - IRQ_WAKEUP0 + 2);
return 0;
}
static struct irq_chip pxa_ext_wakeup_chip = {
.name = "WAKEUP",
- .ack = pxa_ack_ext_wakeup,
- .mask = pxa_mask_ext_wakeup,
- .unmask = pxa_unmask_ext_wakeup,
- .set_type = pxa_set_ext_wakeup_type,
+ .irq_ack = pxa_ack_ext_wakeup,
+ .irq_mask = pxa_mask_ext_wakeup,
+ .irq_unmask = pxa_unmask_ext_wakeup,
+ .irq_set_type = pxa_set_ext_wakeup_type,
};
static void __init pxa_init_ext_wakeup_irq(set_wake_t fn)
@@ -368,7 +368,7 @@ static void __init pxa_init_ext_wakeup_irq(set_wake_t fn)
set_irq_flags(irq, IRQF_VALID);
}
- pxa_ext_wakeup_chip.set_wake = fn;
+ pxa_ext_wakeup_chip.irq_set_wake = fn;
}
void __init pxa3xx_init_irq(void)
diff --git a/arch/arm/mach-pxa/spitz.c b/arch/arm/mach-pxa/spitz.c
index 0bc9387..b49a2c2 100644
--- a/arch/arm/mach-pxa/spitz.c
+++ b/arch/arm/mach-pxa/spitz.c
@@ -25,6 +25,7 @@
#include <linux/spi/corgi_lcd.h>
#include <linux/spi/pxa2xx_spi.h>
#include <linux/mtd/sharpsl.h>
+#include <linux/mtd/physmap.h>
#include <linux/input/matrix_keypad.h>
#include <linux/regulator/machine.h>
#include <linux/io.h>
diff --git a/arch/arm/mach-pxa/viper.c b/arch/arm/mach-pxa/viper.c
index de69b20..49eeeab 100644
--- a/arch/arm/mach-pxa/viper.c
+++ b/arch/arm/mach-pxa/viper.c
@@ -249,9 +249,9 @@ static inline int viper_bit_to_irq(int bit)
return viper_isa_irqs[bit] + PXA_ISA_IRQ(0);
}
-static void viper_ack_irq(unsigned int irq)
+static void viper_ack_irq(struct irq_data *d)
{
- int viper_irq = viper_irq_to_bitmask(irq);
+ int viper_irq = viper_irq_to_bitmask(d->irq);
if (viper_irq & 0xff)
VIPER_LO_IRQ_STATUS = viper_irq;
@@ -259,14 +259,14 @@ static void viper_ack_irq(unsigned int irq)
VIPER_HI_IRQ_STATUS = (viper_irq >> 8);
}
-static void viper_mask_irq(unsigned int irq)
+static void viper_mask_irq(struct irq_data *d)
{
- viper_irq_enabled_mask &= ~(viper_irq_to_bitmask(irq));
+ viper_irq_enabled_mask &= ~(viper_irq_to_bitmask(d->irq));
}
-static void viper_unmask_irq(unsigned int irq)
+static void viper_unmask_irq(struct irq_data *d)
{
- viper_irq_enabled_mask |= viper_irq_to_bitmask(irq);
+ viper_irq_enabled_mask |= viper_irq_to_bitmask(d->irq);
}
static inline unsigned long viper_irq_pending(void)
@@ -283,7 +283,7 @@ static void viper_irq_handler(unsigned int irq, struct irq_desc *desc)
do {
/* we're in a chained irq handler,
* so ack the interrupt by hand */
- desc->chip->ack(irq);
+ desc->irq_data.chip->irq_ack(&desc->irq_data);
if (likely(pending)) {
irq = viper_bit_to_irq(__ffs(pending));
@@ -294,10 +294,10 @@ static void viper_irq_handler(unsigned int irq, struct irq_desc *desc)
}
static struct irq_chip viper_irq_chip = {
- .name = "ISA",
- .ack = viper_ack_irq,
- .mask = viper_mask_irq,
- .unmask = viper_unmask_irq
+ .name = "ISA",
+ .irq_ack = viper_ack_irq,
+ .irq_mask = viper_mask_irq,
+ .irq_unmask = viper_unmask_irq
};
static void __init viper_init_irq(void)
diff --git a/arch/arm/mach-pxa/zeus.c b/arch/arm/mach-pxa/zeus.c
index bf034c7..f4b053b 100644
--- a/arch/arm/mach-pxa/zeus.c
+++ b/arch/arm/mach-pxa/zeus.c
@@ -83,19 +83,19 @@ static inline int zeus_bit_to_irq(int bit)
return zeus_isa_irqs[bit] + PXA_ISA_IRQ(0);
}
-static void zeus_ack_irq(unsigned int irq)
+static void zeus_ack_irq(struct irq_data *d)
{
- __raw_writew(zeus_irq_to_bitmask(irq), ZEUS_CPLD_ISA_IRQ);
+ __raw_writew(zeus_irq_to_bitmask(d->irq), ZEUS_CPLD_ISA_IRQ);
}
-static void zeus_mask_irq(unsigned int irq)
+static void zeus_mask_irq(struct irq_data *d)
{
- zeus_irq_enabled_mask &= ~(zeus_irq_to_bitmask(irq));
+ zeus_irq_enabled_mask &= ~(zeus_irq_to_bitmask(d->irq));
}
-static void zeus_unmask_irq(unsigned int irq)
+static void zeus_unmask_irq(struct irq_data *d)
{
- zeus_irq_enabled_mask |= zeus_irq_to_bitmask(irq);
+ zeus_irq_enabled_mask |= zeus_irq_to_bitmask(d->irq);
}
static inline unsigned long zeus_irq_pending(void)
@@ -111,7 +111,7 @@ static void zeus_irq_handler(unsigned int irq, struct irq_desc *desc)
do {
/* we're in a chained irq handler,
* so ack the interrupt by hand */
- desc->chip->ack(gpio_to_irq(ZEUS_ISA_GPIO));
+ desc->irq_data.chip->irq_ack(&desc->irq_data);
if (likely(pending)) {
irq = zeus_bit_to_irq(__ffs(pending));
@@ -122,10 +122,10 @@ static void zeus_irq_handler(unsigned int irq, struct irq_desc *desc)
}
static struct irq_chip zeus_irq_chip = {
- .name = "ISA",
- .ack = zeus_ack_irq,
- .mask = zeus_mask_irq,
- .unmask = zeus_unmask_irq,
+ .name = "ISA",
+ .irq_ack = zeus_ack_irq,
+ .irq_mask = zeus_mask_irq,
+ .irq_unmask = zeus_unmask_irq,
};
static void __init zeus_init_irq(void)
@@ -830,8 +830,8 @@ static void __init zeus_init(void)
pr_info("Zeus CPLD V%dI%d\n", (system_rev & 0xf0) >> 4, (system_rev & 0x0f));
/* Fix timings for dm9000s (CS1/CS2)*/
- msc0 = __raw_readl(MSC0) & 0x0000ffff | (dm9000_msc << 16);
- msc1 = __raw_readl(MSC1) & 0xffff0000 | dm9000_msc;
+ msc0 = (__raw_readl(MSC0) & 0x0000ffff) | (dm9000_msc << 16);
+ msc1 = (__raw_readl(MSC1) & 0xffff0000) | dm9000_msc;
__raw_writel(msc0, MSC0);
__raw_writel(msc1, MSC1);
diff --git a/arch/arm/mach-rpc/irq.c b/arch/arm/mach-rpc/irq.c
index 9dd15d6..d29cd9b 100644
--- a/arch/arm/mach-rpc/irq.c
+++ b/arch/arm/mach-rpc/irq.c
@@ -6,110 +6,110 @@
#include <asm/hardware/iomd.h>
#include <asm/irq.h>
-static void iomd_ack_irq_a(unsigned int irq)
+static void iomd_ack_irq_a(struct irq_data *d)
{
unsigned int val, mask;
- mask = 1 << irq;
+ mask = 1 << d->irq;
val = iomd_readb(IOMD_IRQMASKA);
iomd_writeb(val & ~mask, IOMD_IRQMASKA);
iomd_writeb(mask, IOMD_IRQCLRA);
}
-static void iomd_mask_irq_a(unsigned int irq)
+static void iomd_mask_irq_a(struct irq_data *d)
{
unsigned int val, mask;
- mask = 1 << irq;
+ mask = 1 << d->irq;
val = iomd_readb(IOMD_IRQMASKA);
iomd_writeb(val & ~mask, IOMD_IRQMASKA);
}
-static void iomd_unmask_irq_a(unsigned int irq)
+static void iomd_unmask_irq_a(struct irq_data *d)
{
unsigned int val, mask;
- mask = 1 << irq;
+ mask = 1 << d->irq;
val = iomd_readb(IOMD_IRQMASKA);
iomd_writeb(val | mask, IOMD_IRQMASKA);
}
static struct irq_chip iomd_a_chip = {
- .ack = iomd_ack_irq_a,
- .mask = iomd_mask_irq_a,
- .unmask = iomd_unmask_irq_a,
+ .irq_ack = iomd_ack_irq_a,
+ .irq_mask = iomd_mask_irq_a,
+ .irq_unmask = iomd_unmask_irq_a,
};
-static void iomd_mask_irq_b(unsigned int irq)
+static void iomd_mask_irq_b(struct irq_data *d)
{
unsigned int val, mask;
- mask = 1 << (irq & 7);
+ mask = 1 << (d->irq & 7);
val = iomd_readb(IOMD_IRQMASKB);
iomd_writeb(val & ~mask, IOMD_IRQMASKB);
}
-static void iomd_unmask_irq_b(unsigned int irq)
+static void iomd_unmask_irq_b(struct irq_data *d)
{
unsigned int val, mask;
- mask = 1 << (irq & 7);
+ mask = 1 << (d->irq & 7);
val = iomd_readb(IOMD_IRQMASKB);
iomd_writeb(val | mask, IOMD_IRQMASKB);
}
static struct irq_chip iomd_b_chip = {
- .ack = iomd_mask_irq_b,
- .mask = iomd_mask_irq_b,
- .unmask = iomd_unmask_irq_b,
+ .irq_ack = iomd_mask_irq_b,
+ .irq_mask = iomd_mask_irq_b,
+ .irq_unmask = iomd_unmask_irq_b,
};
-static void iomd_mask_irq_dma(unsigned int irq)
+static void iomd_mask_irq_dma(struct irq_data *d)
{
unsigned int val, mask;
- mask = 1 << (irq & 7);
+ mask = 1 << (d->irq & 7);
val = iomd_readb(IOMD_DMAMASK);
iomd_writeb(val & ~mask, IOMD_DMAMASK);
}
-static void iomd_unmask_irq_dma(unsigned int irq)
+static void iomd_unmask_irq_dma(struct irq_data *d)
{
unsigned int val, mask;
- mask = 1 << (irq & 7);
+ mask = 1 << (d->irq & 7);
val = iomd_readb(IOMD_DMAMASK);
iomd_writeb(val | mask, IOMD_DMAMASK);
}
static struct irq_chip iomd_dma_chip = {
- .ack = iomd_mask_irq_dma,
- .mask = iomd_mask_irq_dma,
- .unmask = iomd_unmask_irq_dma,
+ .irq_ack = iomd_mask_irq_dma,
+ .irq_mask = iomd_mask_irq_dma,
+ .irq_unmask = iomd_unmask_irq_dma,
};
-static void iomd_mask_irq_fiq(unsigned int irq)
+static void iomd_mask_irq_fiq(struct irq_data *d)
{
unsigned int val, mask;
- mask = 1 << (irq & 7);
+ mask = 1 << (d->irq & 7);
val = iomd_readb(IOMD_FIQMASK);
iomd_writeb(val & ~mask, IOMD_FIQMASK);
}
-static void iomd_unmask_irq_fiq(unsigned int irq)
+static void iomd_unmask_irq_fiq(struct irq_data *d)
{
unsigned int val, mask;
- mask = 1 << (irq & 7);
+ mask = 1 << (d->irq & 7);
val = iomd_readb(IOMD_FIQMASK);
iomd_writeb(val | mask, IOMD_FIQMASK);
}
static struct irq_chip iomd_fiq_chip = {
- .ack = iomd_mask_irq_fiq,
- .mask = iomd_mask_irq_fiq,
- .unmask = iomd_unmask_irq_fiq,
+ .irq_ack = iomd_mask_irq_fiq,
+ .irq_mask = iomd_mask_irq_fiq,
+ .irq_unmask = iomd_unmask_irq_fiq,
};
void __init rpc_init_irq(void)
diff --git a/arch/arm/mach-s3c2410/bast-irq.c b/arch/arm/mach-s3c2410/bast-irq.c
index 217b102..606cb6b 100644
--- a/arch/arm/mach-s3c2410/bast-irq.c
+++ b/arch/arm/mach-s3c2410/bast-irq.c
@@ -75,38 +75,38 @@ static unsigned char bast_pc104_irqmasks[] = {
static unsigned char bast_pc104_irqs[] = { 3, 5, 7, 10 };
static void
-bast_pc104_mask(unsigned int irqno)
+bast_pc104_mask(struct irq_data *data)
{
unsigned long temp;
temp = __raw_readb(BAST_VA_PC104_IRQMASK);
- temp &= ~bast_pc104_irqmasks[irqno];
+ temp &= ~bast_pc104_irqmasks[data->irq];
__raw_writeb(temp, BAST_VA_PC104_IRQMASK);
}
static void
-bast_pc104_maskack(unsigned int irqno)
+bast_pc104_maskack(struct irq_data *data)
{
struct irq_desc *desc = irq_desc + IRQ_ISA;
- bast_pc104_mask(irqno);
- desc->chip->ack(IRQ_ISA);
+ bast_pc104_mask(data);
+ desc->irq_data.chip->irq_ack(&desc->irq_data);
}
static void
-bast_pc104_unmask(unsigned int irqno)
+bast_pc104_unmask(struct irq_data *data)
{
unsigned long temp;
temp = __raw_readb(BAST_VA_PC104_IRQMASK);
- temp |= bast_pc104_irqmasks[irqno];
+ temp |= bast_pc104_irqmasks[data->irq];
__raw_writeb(temp, BAST_VA_PC104_IRQMASK);
}
static struct irq_chip bast_pc104_chip = {
- .mask = bast_pc104_mask,
- .unmask = bast_pc104_unmask,
- .ack = bast_pc104_maskack
+ .irq_mask = bast_pc104_mask,
+ .irq_unmask = bast_pc104_unmask,
+ .irq_ack = bast_pc104_maskack
};
static void
@@ -123,7 +123,7 @@ bast_irq_pc104_demux(unsigned int irq,
/* ack if we get an irq with nothing (ie, startup) */
desc = irq_desc + IRQ_ISA;
- desc->chip->ack(IRQ_ISA);
+ desc->irq_data.chip->irq_ack(&desc->irq_data);
} else {
/* handle the IRQ */
diff --git a/arch/arm/mach-s3c2410/include/mach/irqs.h b/arch/arm/mach-s3c2410/include/mach/irqs.h
index 11bb0f0..e5a68ea 100644
--- a/arch/arm/mach-s3c2410/include/mach/irqs.h
+++ b/arch/arm/mach-s3c2410/include/mach/irqs.h
@@ -152,8 +152,8 @@
#define IRQ_S3C2416_HSMMC0 S3C2410_IRQ(21) /* S3C2416/S3C2450 */
-#define IRQ_HSMMC0 IRQ_S3C2443_HSMMC
-#define IRQ_HSMMC1 IRQ_S3C2416_HSMMC0
+#define IRQ_HSMMC0 IRQ_S3C2416_HSMMC0
+#define IRQ_HSMMC1 IRQ_S3C2443_HSMMC
#define IRQ_S3C2443_LCD1 S3C2410_IRQSUB(14)
#define IRQ_S3C2443_LCD2 S3C2410_IRQSUB(15)
diff --git a/arch/arm/mach-s3c2410/include/mach/map.h b/arch/arm/mach-s3c2410/include/mach/map.h
index cd3983a..25bbf5a 100644
--- a/arch/arm/mach-s3c2410/include/mach/map.h
+++ b/arch/arm/mach-s3c2410/include/mach/map.h
@@ -112,8 +112,8 @@
#define S3C_PA_IIC S3C2410_PA_IIC
#define S3C_PA_UART S3C24XX_PA_UART
#define S3C_PA_USBHOST S3C2410_PA_USBHOST
-#define S3C_PA_HSMMC0 S3C2443_PA_HSMMC
-#define S3C_PA_HSMMC1 S3C2416_PA_HSMMC0
+#define S3C_PA_HSMMC0 S3C2416_PA_HSMMC0
+#define S3C_PA_HSMMC1 S3C2443_PA_HSMMC
#define S3C_PA_WDT S3C2410_PA_WATCHDOG
#define S3C_PA_NAND S3C24XX_PA_NAND
diff --git a/arch/arm/mach-s3c2410/include/mach/regs-s3c2443-clock.h b/arch/arm/mach-s3c2410/include/mach/regs-s3c2443-clock.h
index 101aeea..44494a5 100644
--- a/arch/arm/mach-s3c2410/include/mach/regs-s3c2443-clock.h
+++ b/arch/arm/mach-s3c2410/include/mach/regs-s3c2443-clock.h
@@ -86,6 +86,7 @@
#define S3C2443_HCLKCON_LCDC (1<<9)
#define S3C2443_HCLKCON_USBH (1<<11)
#define S3C2443_HCLKCON_USBD (1<<12)
+#define S3C2416_HCLKCON_HSMMC0 (1<<15)
#define S3C2443_HCLKCON_HSMMC (1<<16)
#define S3C2443_HCLKCON_CFC (1<<17)
#define S3C2443_HCLKCON_SSMC (1<<18)
diff --git a/arch/arm/mach-s3c2412/irq.c b/arch/arm/mach-s3c2412/irq.c
index 6000ca9..eddb52b 100644
--- a/arch/arm/mach-s3c2412/irq.c
+++ b/arch/arm/mach-s3c2412/irq.c
@@ -49,9 +49,9 @@
*/
static void
-s3c2412_irq_mask(unsigned int irqno)
+s3c2412_irq_mask(struct irq_data *data)
{
- unsigned long bitval = 1UL << (irqno - IRQ_EINT0);
+ unsigned long bitval = 1UL << (data->irq - IRQ_EINT0);
unsigned long mask;
mask = __raw_readl(S3C2410_INTMSK);
@@ -62,9 +62,9 @@ s3c2412_irq_mask(unsigned int irqno)
}
static inline void
-s3c2412_irq_ack(unsigned int irqno)
+s3c2412_irq_ack(struct irq_data *data)
{
- unsigned long bitval = 1UL << (irqno - IRQ_EINT0);
+ unsigned long bitval = 1UL << (data->irq - IRQ_EINT0);
__raw_writel(bitval, S3C2412_EINTPEND);
__raw_writel(bitval, S3C2410_SRCPND);
@@ -72,9 +72,9 @@ s3c2412_irq_ack(unsigned int irqno)
}
static inline void
-s3c2412_irq_maskack(unsigned int irqno)
+s3c2412_irq_maskack(struct irq_data *data)
{
- unsigned long bitval = 1UL << (irqno - IRQ_EINT0);
+ unsigned long bitval = 1UL << (data->irq - IRQ_EINT0);
unsigned long mask;
mask = __raw_readl(S3C2410_INTMSK);
@@ -89,9 +89,9 @@ s3c2412_irq_maskack(unsigned int irqno)
}
static void
-s3c2412_irq_unmask(unsigned int irqno)
+s3c2412_irq_unmask(struct irq_data *data)
{
- unsigned long bitval = 1UL << (irqno - IRQ_EINT0);
+ unsigned long bitval = 1UL << (data->irq - IRQ_EINT0);
unsigned long mask;
mask = __raw_readl(S3C2412_EINTMASK);
@@ -102,11 +102,11 @@ s3c2412_irq_unmask(unsigned int irqno)
}
static struct irq_chip s3c2412_irq_eint0t4 = {
- .ack = s3c2412_irq_ack,
- .mask = s3c2412_irq_mask,
- .unmask = s3c2412_irq_unmask,
- .set_wake = s3c_irq_wake,
- .set_type = s3c_irqext_type,
+ .irq_ack = s3c2412_irq_ack,
+ .irq_mask = s3c2412_irq_mask,
+ .irq_unmask = s3c2412_irq_unmask,
+ .irq_set_wake = s3c_irq_wake,
+ .irq_set_type = s3c_irqext_type,
};
#define INTBIT(x) (1 << ((x) - S3C2410_IRQSUB(0)))
@@ -132,29 +132,29 @@ static void s3c2412_irq_demux_cfsdi(unsigned int irq, struct irq_desc *desc)
#define INTMSK_CFSDI (1UL << (IRQ_S3C2412_CFSDI - IRQ_EINT0))
#define SUBMSK_CFSDI INTMSK_SUB(IRQ_S3C2412_SDI, IRQ_S3C2412_CF)
-static void s3c2412_irq_cfsdi_mask(unsigned int irqno)
+static void s3c2412_irq_cfsdi_mask(struct irq_data *data)
{
- s3c_irqsub_mask(irqno, INTMSK_CFSDI, SUBMSK_CFSDI);
+ s3c_irqsub_mask(data->irq, INTMSK_CFSDI, SUBMSK_CFSDI);
}
-static void s3c2412_irq_cfsdi_unmask(unsigned int irqno)
+static void s3c2412_irq_cfsdi_unmask(struct irq_data *data)
{
- s3c_irqsub_unmask(irqno, INTMSK_CFSDI);
+ s3c_irqsub_unmask(data->irq, INTMSK_CFSDI);
}
-static void s3c2412_irq_cfsdi_ack(unsigned int irqno)
+static void s3c2412_irq_cfsdi_ack(struct irq_data *data)
{
- s3c_irqsub_maskack(irqno, INTMSK_CFSDI, SUBMSK_CFSDI);
+ s3c_irqsub_maskack(data->irq, INTMSK_CFSDI, SUBMSK_CFSDI);
}
static struct irq_chip s3c2412_irq_cfsdi = {
.name = "s3c2412-cfsdi",
- .ack = s3c2412_irq_cfsdi_ack,
- .mask = s3c2412_irq_cfsdi_mask,
- .unmask = s3c2412_irq_cfsdi_unmask,
+ .irq_ack = s3c2412_irq_cfsdi_ack,
+ .irq_mask = s3c2412_irq_cfsdi_mask,
+ .irq_unmask = s3c2412_irq_cfsdi_unmask,
};
-static int s3c2412_irq_rtc_wake(unsigned int irqno, unsigned int state)
+static int s3c2412_irq_rtc_wake(struct irq_data *data, unsigned int state)
{
unsigned long pwrcfg;
@@ -165,7 +165,7 @@ static int s3c2412_irq_rtc_wake(unsigned int irqno, unsigned int state)
pwrcfg |= S3C2412_PWRCFG_RTC_MASKIRQ;
__raw_writel(pwrcfg, S3C2412_PWRCFG);
- return s3c_irq_chip.set_wake(irqno, state);
+ return s3c_irq_chip.irq_set_wake(data, state);
}
static struct irq_chip s3c2412_irq_rtc_chip;
@@ -193,7 +193,7 @@ static int s3c2412_irq_add(struct sys_device *sysdev)
/* change RTC IRQ's set wake method */
s3c2412_irq_rtc_chip = s3c_irq_chip;
- s3c2412_irq_rtc_chip.set_wake = s3c2412_irq_rtc_wake;
+ s3c2412_irq_rtc_chip.irq_set_wake = s3c2412_irq_rtc_wake;
set_irq_chip(IRQ_RTC, &s3c2412_irq_rtc_chip);
diff --git a/arch/arm/mach-s3c2416/Kconfig b/arch/arm/mach-s3c2416/Kconfig
index df8d149..69b48a7 100644
--- a/arch/arm/mach-s3c2416/Kconfig
+++ b/arch/arm/mach-s3c2416/Kconfig
@@ -31,6 +31,17 @@ config S3C2416_PM
help
Internal config node to apply S3C2416 power management
+config S3C2416_SETUP_SDHCI
+ bool
+ select S3C2416_SETUP_SDHCI_GPIO
+ help
+ Internal helper functions for S3C2416 based SDHCI systems
+
+config S3C2416_SETUP_SDHCI_GPIO
+ bool
+ help
+ Common setup code for SDHCI gpio.
+
menu "S3C2416 Machines"
config MACH_SMDK2416
@@ -42,6 +53,7 @@ config MACH_SMDK2416
select S3C_DEV_HSMMC1
select S3C_DEV_NAND
select S3C_DEV_USB_HOST
+ select S3C2416_SETUP_SDHCI
select S3C2416_PM if PM
help
Say Y here if you are using an SMDK2416
diff --git a/arch/arm/mach-s3c2416/Makefile b/arch/arm/mach-s3c2416/Makefile
index ef038d6..7b805b2 100644
--- a/arch/arm/mach-s3c2416/Makefile
+++ b/arch/arm/mach-s3c2416/Makefile
@@ -14,6 +14,10 @@ obj-$(CONFIG_CPU_S3C2416) += irq.o
obj-$(CONFIG_S3C2416_PM) += pm.o
#obj-$(CONFIG_S3C2416_DMA) += dma.o
+# Device setup
+obj-$(CONFIG_S3C2416_SETUP_SDHCI) += setup-sdhci.o
+obj-$(CONFIG_S3C2416_SETUP_SDHCI_GPIO) += setup-sdhci-gpio.o
+
# Machine support
obj-$(CONFIG_MACH_SMDK2416) += mach-smdk2416.o
diff --git a/arch/arm/mach-s3c2416/clock.c b/arch/arm/mach-s3c2416/clock.c
index 7ccf5a2..3b02d85 100644
--- a/arch/arm/mach-s3c2416/clock.c
+++ b/arch/arm/mach-s3c2416/clock.c
@@ -38,12 +38,11 @@ static unsigned int armdiv[8] = {
[7] = 8,
};
-/* ID to hardware numbering, 0 is HSMMC1, 1 is HSMMC0 */
static struct clksrc_clk hsmmc_div[] = {
[0] = {
.clk = {
.name = "hsmmc-div",
- .id = 1,
+ .id = 0,
.parent = &clk_esysclk.clk,
},
.reg_div = { .reg = S3C2416_CLKDIV2, .size = 2, .shift = 6 },
@@ -51,7 +50,7 @@ static struct clksrc_clk hsmmc_div[] = {
[1] = {
.clk = {
.name = "hsmmc-div",
- .id = 0,
+ .id = 1,
.parent = &clk_esysclk.clk,
},
.reg_div = { .reg = S3C2443_CLKDIV1, .size = 2, .shift = 6 },
@@ -61,7 +60,7 @@ static struct clksrc_clk hsmmc_div[] = {
static struct clksrc_clk hsmmc_mux[] = {
[0] = {
.clk = {
- .id = 1,
+ .id = 0,
.name = "hsmmc-if",
.ctrlbit = (1 << 6),
.enable = s3c2443_clkcon_enable_s,
@@ -77,7 +76,7 @@ static struct clksrc_clk hsmmc_mux[] = {
},
[1] = {
.clk = {
- .id = 0,
+ .id = 1,
.name = "hsmmc-if",
.ctrlbit = (1 << 12),
.enable = s3c2443_clkcon_enable_s,
@@ -93,6 +92,13 @@ static struct clksrc_clk hsmmc_mux[] = {
},
};
+static struct clk hsmmc0_clk = {
+ .name = "hsmmc",
+ .id = 0,
+ .parent = &clk_h,
+ .enable = s3c2443_clkcon_enable_h,
+ .ctrlbit = S3C2416_HCLKCON_HSMMC0,
+};
static inline unsigned int s3c2416_fclk_div(unsigned long clkcon0)
{
@@ -130,6 +136,8 @@ void __init s3c2416_init_clocks(int xtal)
for (ptr = 0; ptr < ARRAY_SIZE(clksrcs); ptr++)
s3c_register_clksrc(clksrcs[ptr], 1);
+ s3c24xx_register_clock(&hsmmc0_clk);
+
s3c_pwmclk_init();
}
diff --git a/arch/arm/mach-s3c2416/irq.c b/arch/arm/mach-s3c2416/irq.c
index 00174da..680fe38 100644
--- a/arch/arm/mach-s3c2416/irq.c
+++ b/arch/arm/mach-s3c2416/irq.c
@@ -77,28 +77,27 @@ static void s3c2416_irq_demux_wdtac97(unsigned int irq, struct irq_desc *desc)
#define INTMSK_WDTAC97 (1UL << (IRQ_WDT - IRQ_EINT0))
#define SUBMSK_WDTAC97 INTMSK(IRQ_S3C2443_WDT, IRQ_S3C2443_AC97)
-static void s3c2416_irq_wdtac97_mask(unsigned int irqno)
+static void s3c2416_irq_wdtac97_mask(struct irq_data *data)
{
- s3c_irqsub_mask(irqno, INTMSK_WDTAC97, SUBMSK_WDTAC97);
+ s3c_irqsub_mask(data->irq, INTMSK_WDTAC97, SUBMSK_WDTAC97);
}
-static void s3c2416_irq_wdtac97_unmask(unsigned int irqno)
+static void s3c2416_irq_wdtac97_unmask(struct irq_data *data)
{
- s3c_irqsub_unmask(irqno, INTMSK_WDTAC97);
+ s3c_irqsub_unmask(data->irq, INTMSK_WDTAC97);
}
-static void s3c2416_irq_wdtac97_ack(unsigned int irqno)
+static void s3c2416_irq_wdtac97_ack(struct irq_data *data)
{
- s3c_irqsub_maskack(irqno, INTMSK_WDTAC97, SUBMSK_WDTAC97);
+ s3c_irqsub_maskack(data->irq, INTMSK_WDTAC97, SUBMSK_WDTAC97);
}
static struct irq_chip s3c2416_irq_wdtac97 = {
- .mask = s3c2416_irq_wdtac97_mask,
- .unmask = s3c2416_irq_wdtac97_unmask,
- .ack = s3c2416_irq_wdtac97_ack,
+ .irq_mask = s3c2416_irq_wdtac97_mask,
+ .irq_unmask = s3c2416_irq_wdtac97_unmask,
+ .irq_ack = s3c2416_irq_wdtac97_ack,
};
-
/* LCD sub interrupts */
static void s3c2416_irq_demux_lcd(unsigned int irq, struct irq_desc *desc)
@@ -109,28 +108,27 @@ static void s3c2416_irq_demux_lcd(unsigned int irq, struct irq_desc *desc)
#define INTMSK_LCD (1UL << (IRQ_LCD - IRQ_EINT0))
#define SUBMSK_LCD INTMSK(IRQ_S3C2443_LCD1, IRQ_S3C2443_LCD4)
-static void s3c2416_irq_lcd_mask(unsigned int irqno)
+static void s3c2416_irq_lcd_mask(struct irq_data *data)
{
- s3c_irqsub_mask(irqno, INTMSK_LCD, SUBMSK_LCD);
+ s3c_irqsub_mask(data->irq, INTMSK_LCD, SUBMSK_LCD);
}
-static void s3c2416_irq_lcd_unmask(unsigned int irqno)
+static void s3c2416_irq_lcd_unmask(struct irq_data *data)
{
- s3c_irqsub_unmask(irqno, INTMSK_LCD);
+ s3c_irqsub_unmask(data->irq, INTMSK_LCD);
}
-static void s3c2416_irq_lcd_ack(unsigned int irqno)
+static void s3c2416_irq_lcd_ack(struct irq_data *data)
{
- s3c_irqsub_maskack(irqno, INTMSK_LCD, SUBMSK_LCD);
+ s3c_irqsub_maskack(data->irq, INTMSK_LCD, SUBMSK_LCD);
}
static struct irq_chip s3c2416_irq_lcd = {
- .mask = s3c2416_irq_lcd_mask,
- .unmask = s3c2416_irq_lcd_unmask,
- .ack = s3c2416_irq_lcd_ack,
+ .irq_mask = s3c2416_irq_lcd_mask,
+ .irq_unmask = s3c2416_irq_lcd_unmask,
+ .irq_ack = s3c2416_irq_lcd_ack,
};
-
/* DMA sub interrupts */
static void s3c2416_irq_demux_dma(unsigned int irq, struct irq_desc *desc)
@@ -142,28 +140,27 @@ static void s3c2416_irq_demux_dma(unsigned int irq, struct irq_desc *desc)
#define SUBMSK_DMA INTMSK(IRQ_S3C2443_DMA0, IRQ_S3C2443_DMA5)
-static void s3c2416_irq_dma_mask(unsigned int irqno)
+static void s3c2416_irq_dma_mask(struct irq_data *data)
{
- s3c_irqsub_mask(irqno, INTMSK_DMA, SUBMSK_DMA);
+ s3c_irqsub_mask(data->irq, INTMSK_DMA, SUBMSK_DMA);
}
-static void s3c2416_irq_dma_unmask(unsigned int irqno)
+static void s3c2416_irq_dma_unmask(struct irq_data *data)
{
- s3c_irqsub_unmask(irqno, INTMSK_DMA);
+ s3c_irqsub_unmask(data->irq, INTMSK_DMA);
}
-static void s3c2416_irq_dma_ack(unsigned int irqno)
+static void s3c2416_irq_dma_ack(struct irq_data *data)
{
- s3c_irqsub_maskack(irqno, INTMSK_DMA, SUBMSK_DMA);
+ s3c_irqsub_maskack(data->irq, INTMSK_DMA, SUBMSK_DMA);
}
static struct irq_chip s3c2416_irq_dma = {
- .mask = s3c2416_irq_dma_mask,
- .unmask = s3c2416_irq_dma_unmask,
- .ack = s3c2416_irq_dma_ack,
+ .irq_mask = s3c2416_irq_dma_mask,
+ .irq_unmask = s3c2416_irq_dma_unmask,
+ .irq_ack = s3c2416_irq_dma_ack,
};
-
/* UART3 sub interrupts */
static void s3c2416_irq_demux_uart3(unsigned int irq, struct irq_desc *desc)
@@ -174,28 +171,27 @@ static void s3c2416_irq_demux_uart3(unsigned int irq, struct irq_desc *desc)
#define INTMSK_UART3 (1UL << (IRQ_S3C2443_UART3 - IRQ_EINT0))
#define SUBMSK_UART3 (0x7 << (IRQ_S3C2443_RX3 - S3C2410_IRQSUB(0)))
-static void s3c2416_irq_uart3_mask(unsigned int irqno)
+static void s3c2416_irq_uart3_mask(struct irq_data *data)
{
- s3c_irqsub_mask(irqno, INTMSK_UART3, SUBMSK_UART3);
+ s3c_irqsub_mask(data->irq, INTMSK_UART3, SUBMSK_UART3);
}
-static void s3c2416_irq_uart3_unmask(unsigned int irqno)
+static void s3c2416_irq_uart3_unmask(struct irq_data *data)
{
- s3c_irqsub_unmask(irqno, INTMSK_UART3);
+ s3c_irqsub_unmask(data->irq, INTMSK_UART3);
}
-static void s3c2416_irq_uart3_ack(unsigned int irqno)
+static void s3c2416_irq_uart3_ack(struct irq_data *data)
{
- s3c_irqsub_maskack(irqno, INTMSK_UART3, SUBMSK_UART3);
+ s3c_irqsub_maskack(data->irq, INTMSK_UART3, SUBMSK_UART3);
}
static struct irq_chip s3c2416_irq_uart3 = {
- .mask = s3c2416_irq_uart3_mask,
- .unmask = s3c2416_irq_uart3_unmask,
- .ack = s3c2416_irq_uart3_ack,
+ .irq_mask = s3c2416_irq_uart3_mask,
+ .irq_unmask = s3c2416_irq_uart3_unmask,
+ .irq_ack = s3c2416_irq_uart3_ack,
};
-
/* IRQ initialisation code */
static int __init s3c2416_add_sub(unsigned int base,
diff --git a/arch/arm/mach-s3c2416/mach-smdk2416.c b/arch/arm/mach-s3c2416/mach-smdk2416.c
index 7fc3664..3f83177 100644
--- a/arch/arm/mach-s3c2416/mach-smdk2416.c
+++ b/arch/arm/mach-s3c2416/mach-smdk2416.c
@@ -46,6 +46,7 @@
#include <plat/devs.h>
#include <plat/cpu.h>
#include <plat/nand.h>
+#include <plat/sdhci.h>
#include <plat/regs-fb-v4.h>
#include <plat/fb.h>
@@ -110,6 +111,13 @@ static struct s3c2410_uartcfg smdk2416_uartcfgs[] __initdata = {
.ucon = UCON,
.ulcon = ULCON | 0x50,
.ufcon = UFCON,
+ },
+ [3] = {
+ .hwport = 3,
+ .flags = 0,
+ .ucon = UCON,
+ .ulcon = ULCON,
+ .ufcon = UFCON,
}
};
@@ -159,6 +167,18 @@ static struct s3c_fb_platdata smdk2416_fb_platdata = {
.vidcon1 = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC,
};
+static struct s3c_sdhci_platdata smdk2416_hsmmc0_pdata __initdata = {
+ .max_width = 4,
+ .cd_type = S3C_SDHCI_CD_GPIO,
+ .ext_cd_gpio = S3C2410_GPF(1),
+ .ext_cd_gpio_invert = 1,
+};
+
+static struct s3c_sdhci_platdata smdk2416_hsmmc1_pdata __initdata = {
+ .max_width = 4,
+ .cd_type = S3C_SDHCI_CD_NONE,
+};
+
static struct platform_device *smdk2416_devices[] __initdata = {
&s3c_device_fb,
&s3c_device_wdt,
@@ -180,6 +200,9 @@ static void __init smdk2416_machine_init(void)
s3c_i2c0_set_platdata(NULL);
s3c_fb_set_platdata(&smdk2416_fb_platdata);
+ s3c_sdhci0_set_platdata(&smdk2416_hsmmc0_pdata);
+ s3c_sdhci1_set_platdata(&smdk2416_hsmmc1_pdata);
+
gpio_request(S3C2410_GPB(4), "USBHost Power");
gpio_direction_output(S3C2410_GPB(4), 1);
diff --git a/arch/arm/mach-s3c2416/s3c2416.c b/arch/arm/mach-s3c2416/s3c2416.c
index 63f39cd..ba7fd87 100644
--- a/arch/arm/mach-s3c2416/s3c2416.c
+++ b/arch/arm/mach-s3c2416/s3c2416.c
@@ -53,6 +53,7 @@
#include <plat/s3c2416.h>
#include <plat/devs.h>
#include <plat/cpu.h>
+#include <plat/sdhci.h>
#include <plat/iic-core.h>
#include <plat/fb-core.h>
@@ -115,6 +116,10 @@ void __init s3c2416_map_io(void)
s3c24xx_gpiocfg_default.set_pull = s3c_gpio_setpull_updown;
s3c24xx_gpiocfg_default.get_pull = s3c_gpio_getpull_updown;
+ /* initialize device information early */
+ s3c2416_default_sdhci0();
+ s3c2416_default_sdhci1();
+
iotable_init(s3c2416_iodesc, ARRAY_SIZE(s3c2416_iodesc));
}
diff --git a/arch/arm/mach-s3c2416/setup-sdhci-gpio.c b/arch/arm/mach-s3c2416/setup-sdhci-gpio.c
new file mode 100644
index 0000000..f65cb3e
--- /dev/null
+++ b/arch/arm/mach-s3c2416/setup-sdhci-gpio.c
@@ -0,0 +1,34 @@
+/* linux/arch/arm/plat-s3c2416/setup-sdhci-gpio.c
+ *
+ * Copyright 2010 Promwad Innovation Company
+ * Yauhen Kharuzhy <yauhen.kharuzhy@promwad.com>
+ *
+ * S3C2416 - Helper functions for setting up SDHCI device(s) GPIO (HSMMC)
+ *
+ * Based on mach-s3c64xx/setup-sdhci-gpio.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+
+#include <mach/regs-gpio.h>
+#include <plat/gpio-cfg.h>
+
+void s3c2416_setup_sdhci0_cfg_gpio(struct platform_device *dev, int width)
+{
+ s3c_gpio_cfgrange_nopull(S3C2410_GPE(5), 2 + width, S3C_GPIO_SFN(2));
+}
+
+void s3c2416_setup_sdhci1_cfg_gpio(struct platform_device *dev, int width)
+{
+ s3c_gpio_cfgrange_nopull(S3C2410_GPL(0), width, S3C_GPIO_SFN(2));
+ s3c_gpio_cfgrange_nopull(S3C2410_GPL(8), 2, S3C_GPIO_SFN(2));
+}
diff --git a/arch/arm/mach-s3c2416/setup-sdhci.c b/arch/arm/mach-s3c2416/setup-sdhci.c
new file mode 100644
index 0000000..ed34fad
--- /dev/null
+++ b/arch/arm/mach-s3c2416/setup-sdhci.c
@@ -0,0 +1,61 @@
+/* linux/arch/arm/mach-s3c2416/setup-sdhci.c
+ *
+ * Copyright 2010 Promwad Innovation Company
+ * Yauhen Kharuzhy <yauhen.kharuzhy@promwad.com>
+ *
+ * S3C2416 - Helper functions for settign up SDHCI device(s) (HSMMC)
+ *
+ * Based on mach-s3c64xx/setup-sdhci.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+
+#include <linux/mmc/card.h>
+#include <linux/mmc/host.h>
+
+#include <plat/regs-sdhci.h>
+#include <plat/sdhci.h>
+
+/* clock sources for the mmc bus clock, order as for the ctrl2[5..4] */
+
+char *s3c2416_hsmmc_clksrcs[4] = {
+ [0] = "hsmmc",
+ [1] = "hsmmc",
+ [2] = "hsmmc-if",
+ /* [3] = "48m", - note not successfully used yet */
+};
+
+void s3c2416_setup_sdhci_cfg_card(struct platform_device *dev,
+ void __iomem *r,
+ struct mmc_ios *ios,
+ struct mmc_card *card)
+{
+ u32 ctrl2, ctrl3;
+
+ ctrl2 = __raw_readl(r + S3C_SDHCI_CONTROL2);
+ ctrl2 &= S3C_SDHCI_CTRL2_SELBASECLK_MASK;
+ ctrl2 |= (S3C64XX_SDHCI_CTRL2_ENSTAASYNCCLR |
+ S3C64XX_SDHCI_CTRL2_ENCMDCNFMSK |
+ S3C_SDHCI_CTRL2_ENFBCLKRX |
+ S3C_SDHCI_CTRL2_DFCNT_NONE |
+ S3C_SDHCI_CTRL2_ENCLKOUTHOLD);
+
+ if (ios->clock < 25 * 1000000)
+ ctrl3 = (S3C_SDHCI_CTRL3_FCSEL3 |
+ S3C_SDHCI_CTRL3_FCSEL2 |
+ S3C_SDHCI_CTRL3_FCSEL1 |
+ S3C_SDHCI_CTRL3_FCSEL0);
+ else
+ ctrl3 = (S3C_SDHCI_CTRL3_FCSEL1 | S3C_SDHCI_CTRL3_FCSEL0);
+
+ __raw_writel(ctrl2, r + S3C_SDHCI_CONTROL2);
+ __raw_writel(ctrl3, r + S3C_SDHCI_CONTROL3);
+}
diff --git a/arch/arm/mach-s3c2440/irq.c b/arch/arm/mach-s3c2440/irq.c
index 0c049b9..acad442 100644
--- a/arch/arm/mach-s3c2440/irq.c
+++ b/arch/arm/mach-s3c2440/irq.c
@@ -69,27 +69,27 @@ static void s3c_irq_demux_wdtac97(unsigned int irq,
#define INTMSK_WDT (1UL << (IRQ_WDT - IRQ_EINT0))
static void
-s3c_irq_wdtac97_mask(unsigned int irqno)
+s3c_irq_wdtac97_mask(struct irq_data *data)
{
- s3c_irqsub_mask(irqno, INTMSK_WDT, 3<<13);
+ s3c_irqsub_mask(data->irq, INTMSK_WDT, 3 << 13);
}
static void
-s3c_irq_wdtac97_unmask(unsigned int irqno)
+s3c_irq_wdtac97_unmask(struct irq_data *data)
{
- s3c_irqsub_unmask(irqno, INTMSK_WDT);
+ s3c_irqsub_unmask(data->irq, INTMSK_WDT);
}
static void
-s3c_irq_wdtac97_ack(unsigned int irqno)
+s3c_irq_wdtac97_ack(struct irq_data *data)
{
- s3c_irqsub_maskack(irqno, INTMSK_WDT, 3<<13);
+ s3c_irqsub_maskack(data->irq, INTMSK_WDT, 3 << 13);
}
static struct irq_chip s3c_irq_wdtac97 = {
- .mask = s3c_irq_wdtac97_mask,
- .unmask = s3c_irq_wdtac97_unmask,
- .ack = s3c_irq_wdtac97_ack,
+ .irq_mask = s3c_irq_wdtac97_mask,
+ .irq_unmask = s3c_irq_wdtac97_unmask,
+ .irq_ack = s3c_irq_wdtac97_ack,
};
static int s3c2440_irq_add(struct sys_device *sysdev)
diff --git a/arch/arm/mach-s3c2440/s3c244x-irq.c b/arch/arm/mach-s3c2440/s3c244x-irq.c
index a75c0c2..83daf4e 100644
--- a/arch/arm/mach-s3c2440/s3c244x-irq.c
+++ b/arch/arm/mach-s3c2440/s3c244x-irq.c
@@ -68,27 +68,27 @@ static void s3c_irq_demux_cam(unsigned int irq,
#define INTMSK_CAM (1UL << (IRQ_CAM - IRQ_EINT0))
static void
-s3c_irq_cam_mask(unsigned int irqno)
+s3c_irq_cam_mask(struct irq_data *data)
{
- s3c_irqsub_mask(irqno, INTMSK_CAM, 3<<11);
+ s3c_irqsub_mask(data->irq, INTMSK_CAM, 3 << 11);
}
static void
-s3c_irq_cam_unmask(unsigned int irqno)
+s3c_irq_cam_unmask(struct irq_data *data)
{
- s3c_irqsub_unmask(irqno, INTMSK_CAM);
+ s3c_irqsub_unmask(data->irq, INTMSK_CAM);
}
static void
-s3c_irq_cam_ack(unsigned int irqno)
+s3c_irq_cam_ack(struct irq_data *data)
{
- s3c_irqsub_maskack(irqno, INTMSK_CAM, 3<<11);
+ s3c_irqsub_maskack(data->irq, INTMSK_CAM, 3 << 11);
}
static struct irq_chip s3c_irq_cam = {
- .mask = s3c_irq_cam_mask,
- .unmask = s3c_irq_cam_unmask,
- .ack = s3c_irq_cam_ack,
+ .irq_mask = s3c_irq_cam_mask,
+ .irq_unmask = s3c_irq_cam_unmask,
+ .irq_ack = s3c_irq_cam_ack,
};
static int s3c244x_irq_add(struct sys_device *sysdev)
diff --git a/arch/arm/mach-s3c2443/Kconfig b/arch/arm/mach-s3c2443/Kconfig
index 31babec..d8eb868 100644
--- a/arch/arm/mach-s3c2443/Kconfig
+++ b/arch/arm/mach-s3c2443/Kconfig
@@ -10,6 +10,7 @@ config CPU_S3C2443
select CPU_LLSERIAL_S3C2440
select SAMSUNG_CLKSRC
select S3C2443_CLOCK
+ select S3C_GPIO_PULL_S3C2443
help
Support for the S3C2443 SoC from the S3C24XX line
@@ -25,7 +26,7 @@ config MACH_SMDK2443
bool "SMDK2443"
select CPU_S3C2443
select MACH_SMDK
- select S3C_DEV_HSMMC
+ select S3C_DEV_HSMMC1
help
Say Y here if you are using an SMDK2443
diff --git a/arch/arm/mach-s3c2443/clock.c b/arch/arm/mach-s3c2443/clock.c
index 0c3c0c8..f4ec6d5 100644
--- a/arch/arm/mach-s3c2443/clock.c
+++ b/arch/arm/mach-s3c2443/clock.c
@@ -196,7 +196,7 @@ static struct clksrc_clk clk_hsspi = {
static struct clksrc_clk clk_hsmmc_div = {
.clk = {
.name = "hsmmc-div",
- .id = -1,
+ .id = 1,
.parent = &clk_esysclk.clk,
},
.reg_div = { .reg = S3C2443_CLKDIV1, .size = 2, .shift = 6 },
@@ -231,7 +231,7 @@ static int s3c2443_enable_hsmmc(struct clk *clk, int enable)
static struct clk clk_hsmmc = {
.name = "hsmmc-if",
- .id = -1,
+ .id = 1,
.parent = &clk_hsmmc_div.clk,
.enable = s3c2443_enable_hsmmc,
.ops = &(struct clk_ops) {
diff --git a/arch/arm/mach-s3c2443/irq.c b/arch/arm/mach-s3c2443/irq.c
index 8934247..c7820f9 100644
--- a/arch/arm/mach-s3c2443/irq.c
+++ b/arch/arm/mach-s3c2443/irq.c
@@ -75,28 +75,27 @@ static void s3c2443_irq_demux_wdtac97(unsigned int irq, struct irq_desc *desc)
#define INTMSK_WDTAC97 (1UL << (IRQ_WDT - IRQ_EINT0))
#define SUBMSK_WDTAC97 INTMSK(IRQ_S3C2443_WDT, IRQ_S3C2443_AC97)
-static void s3c2443_irq_wdtac97_mask(unsigned int irqno)
+static void s3c2443_irq_wdtac97_mask(struct irq_data *data)
{
- s3c_irqsub_mask(irqno, INTMSK_WDTAC97, SUBMSK_WDTAC97);
+ s3c_irqsub_mask(data->irq, INTMSK_WDTAC97, SUBMSK_WDTAC97);
}
-static void s3c2443_irq_wdtac97_unmask(unsigned int irqno)
+static void s3c2443_irq_wdtac97_unmask(struct irq_data *data)
{
- s3c_irqsub_unmask(irqno, INTMSK_WDTAC97);
+ s3c_irqsub_unmask(data->irq, INTMSK_WDTAC97);
}
-static void s3c2443_irq_wdtac97_ack(unsigned int irqno)
+static void s3c2443_irq_wdtac97_ack(struct irq_data *data)
{
- s3c_irqsub_maskack(irqno, INTMSK_WDTAC97, SUBMSK_WDTAC97);
+ s3c_irqsub_maskack(data->irq, INTMSK_WDTAC97, SUBMSK_WDTAC97);
}
static struct irq_chip s3c2443_irq_wdtac97 = {
- .mask = s3c2443_irq_wdtac97_mask,
- .unmask = s3c2443_irq_wdtac97_unmask,
- .ack = s3c2443_irq_wdtac97_ack,
+ .irq_mask = s3c2443_irq_wdtac97_mask,
+ .irq_unmask = s3c2443_irq_wdtac97_unmask,
+ .irq_ack = s3c2443_irq_wdtac97_ack,
};
-
/* LCD sub interrupts */
static void s3c2443_irq_demux_lcd(unsigned int irq, struct irq_desc *desc)
@@ -107,28 +106,27 @@ static void s3c2443_irq_demux_lcd(unsigned int irq, struct irq_desc *desc)
#define INTMSK_LCD (1UL << (IRQ_LCD - IRQ_EINT0))
#define SUBMSK_LCD INTMSK(IRQ_S3C2443_LCD1, IRQ_S3C2443_LCD4)
-static void s3c2443_irq_lcd_mask(unsigned int irqno)
+static void s3c2443_irq_lcd_mask(struct irq_data *data)
{
- s3c_irqsub_mask(irqno, INTMSK_LCD, SUBMSK_LCD);
+ s3c_irqsub_mask(data->irq, INTMSK_LCD, SUBMSK_LCD);
}
-static void s3c2443_irq_lcd_unmask(unsigned int irqno)
+static void s3c2443_irq_lcd_unmask(struct irq_data *data)
{
- s3c_irqsub_unmask(irqno, INTMSK_LCD);
+ s3c_irqsub_unmask(data->irq, INTMSK_LCD);
}
-static void s3c2443_irq_lcd_ack(unsigned int irqno)
+static void s3c2443_irq_lcd_ack(struct irq_data *data)
{
- s3c_irqsub_maskack(irqno, INTMSK_LCD, SUBMSK_LCD);
+ s3c_irqsub_maskack(data->irq, INTMSK_LCD, SUBMSK_LCD);
}
static struct irq_chip s3c2443_irq_lcd = {
- .mask = s3c2443_irq_lcd_mask,
- .unmask = s3c2443_irq_lcd_unmask,
- .ack = s3c2443_irq_lcd_ack,
+ .irq_mask = s3c2443_irq_lcd_mask,
+ .irq_unmask = s3c2443_irq_lcd_unmask,
+ .irq_ack = s3c2443_irq_lcd_ack,
};
-
/* DMA sub interrupts */
static void s3c2443_irq_demux_dma(unsigned int irq, struct irq_desc *desc)
@@ -139,29 +137,27 @@ static void s3c2443_irq_demux_dma(unsigned int irq, struct irq_desc *desc)
#define INTMSK_DMA (1UL << (IRQ_S3C2443_DMA - IRQ_EINT0))
#define SUBMSK_DMA INTMSK(IRQ_S3C2443_DMA0, IRQ_S3C2443_DMA5)
-
-static void s3c2443_irq_dma_mask(unsigned int irqno)
+static void s3c2443_irq_dma_mask(struct irq_data *data)
{
- s3c_irqsub_mask(irqno, INTMSK_DMA, SUBMSK_DMA);
+ s3c_irqsub_mask(data->irq, INTMSK_DMA, SUBMSK_DMA);
}
-static void s3c2443_irq_dma_unmask(unsigned int irqno)
+static void s3c2443_irq_dma_unmask(struct irq_data *data)
{
- s3c_irqsub_unmask(irqno, INTMSK_DMA);
+ s3c_irqsub_unmask(data->irq, INTMSK_DMA);
}
-static void s3c2443_irq_dma_ack(unsigned int irqno)
+static void s3c2443_irq_dma_ack(struct irq_data *data)
{
- s3c_irqsub_maskack(irqno, INTMSK_DMA, SUBMSK_DMA);
+ s3c_irqsub_maskack(data->irq, INTMSK_DMA, SUBMSK_DMA);
}
static struct irq_chip s3c2443_irq_dma = {
- .mask = s3c2443_irq_dma_mask,
- .unmask = s3c2443_irq_dma_unmask,
- .ack = s3c2443_irq_dma_ack,
+ .irq_mask = s3c2443_irq_dma_mask,
+ .irq_unmask = s3c2443_irq_dma_unmask,
+ .irq_ack = s3c2443_irq_dma_ack,
};
-
/* UART3 sub interrupts */
static void s3c2443_irq_demux_uart3(unsigned int irq, struct irq_desc *desc)
@@ -172,28 +168,27 @@ static void s3c2443_irq_demux_uart3(unsigned int irq, struct irq_desc *desc)
#define INTMSK_UART3 (1UL << (IRQ_S3C2443_UART3 - IRQ_EINT0))
#define SUBMSK_UART3 (0x7 << (IRQ_S3C2443_RX3 - S3C2410_IRQSUB(0)))
-static void s3c2443_irq_uart3_mask(unsigned int irqno)
+static void s3c2443_irq_uart3_mask(struct irq_data *data)
{
- s3c_irqsub_mask(irqno, INTMSK_UART3, SUBMSK_UART3);
+ s3c_irqsub_mask(data->irq, INTMSK_UART3, SUBMSK_UART3);
}
-static void s3c2443_irq_uart3_unmask(unsigned int irqno)
+static void s3c2443_irq_uart3_unmask(struct irq_data *data)
{
- s3c_irqsub_unmask(irqno, INTMSK_UART3);
+ s3c_irqsub_unmask(data->irq, INTMSK_UART3);
}
-static void s3c2443_irq_uart3_ack(unsigned int irqno)
+static void s3c2443_irq_uart3_ack(struct irq_data *data)
{
- s3c_irqsub_maskack(irqno, INTMSK_UART3, SUBMSK_UART3);
+ s3c_irqsub_maskack(data->irq, INTMSK_UART3, SUBMSK_UART3);
}
static struct irq_chip s3c2443_irq_uart3 = {
- .mask = s3c2443_irq_uart3_mask,
- .unmask = s3c2443_irq_uart3_unmask,
- .ack = s3c2443_irq_uart3_ack,
+ .irq_mask = s3c2443_irq_uart3_mask,
+ .irq_unmask = s3c2443_irq_uart3_unmask,
+ .irq_ack = s3c2443_irq_uart3_ack,
};
-
/* CAM sub interrupts */
static void s3c2443_irq_demux_cam(unsigned int irq, struct irq_desc *desc)
@@ -204,25 +199,25 @@ static void s3c2443_irq_demux_cam(unsigned int irq, struct irq_desc *desc)
#define INTMSK_CAM (1UL << (IRQ_CAM - IRQ_EINT0))
#define SUBMSK_CAM INTMSK(IRQ_S3C2440_CAM_C, IRQ_S3C2440_CAM_P)
-static void s3c2443_irq_cam_mask(unsigned int irqno)
+static void s3c2443_irq_cam_mask(struct irq_data *data)
{
- s3c_irqsub_mask(irqno, INTMSK_CAM, SUBMSK_CAM);
+ s3c_irqsub_mask(data->irq, INTMSK_CAM, SUBMSK_CAM);
}
-static void s3c2443_irq_cam_unmask(unsigned int irqno)
+static void s3c2443_irq_cam_unmask(struct irq_data *data)
{
- s3c_irqsub_unmask(irqno, INTMSK_CAM);
+ s3c_irqsub_unmask(data->irq, INTMSK_CAM);
}
-static void s3c2443_irq_cam_ack(unsigned int irqno)
+static void s3c2443_irq_cam_ack(struct irq_data *data)
{
- s3c_irqsub_maskack(irqno, INTMSK_CAM, SUBMSK_CAM);
+ s3c_irqsub_maskack(data->irq, INTMSK_CAM, SUBMSK_CAM);
}
static struct irq_chip s3c2443_irq_cam = {
- .mask = s3c2443_irq_cam_mask,
- .unmask = s3c2443_irq_cam_unmask,
- .ack = s3c2443_irq_cam_ack,
+ .irq_mask = s3c2443_irq_cam_mask,
+ .irq_unmask = s3c2443_irq_cam_unmask,
+ .irq_ack = s3c2443_irq_cam_ack,
};
/* IRQ initialisation code */
diff --git a/arch/arm/mach-s3c2443/mach-smdk2443.c b/arch/arm/mach-s3c2443/mach-smdk2443.c
index 4337f0a..514275e 100644
--- a/arch/arm/mach-s3c2443/mach-smdk2443.c
+++ b/arch/arm/mach-s3c2443/mach-smdk2443.c
@@ -99,13 +99,20 @@ static struct s3c2410_uartcfg smdk2443_uartcfgs[] __initdata = {
.ucon = 0x3c5,
.ulcon = 0x43,
.ufcon = 0x51,
+ },
+ [3] = {
+ .hwport = 3,
+ .flags = 0,
+ .ucon = 0x3c5,
+ .ulcon = 0x03,
+ .ufcon = 0x51,
}
};
static struct platform_device *smdk2443_devices[] __initdata = {
&s3c_device_wdt,
&s3c_device_i2c0,
- &s3c_device_hsmmc0,
+ &s3c_device_hsmmc1,
#ifdef CONFIG_SND_SOC_SMDK2443_WM9710
&s3c_device_ac97,
#endif
diff --git a/arch/arm/mach-s3c2443/s3c2443.c b/arch/arm/mach-s3c2443/s3c2443.c
index 33d18dd..e6a28ba 100644
--- a/arch/arm/mach-s3c2443/s3c2443.c
+++ b/arch/arm/mach-s3c2443/s3c2443.c
@@ -16,6 +16,7 @@
#include <linux/list.h>
#include <linux/timer.h>
#include <linux/init.h>
+#include <linux/gpio.h>
#include <linux/platform_device.h>
#include <linux/serial_core.h>
#include <linux/sysdev.h>
@@ -32,6 +33,9 @@
#include <mach/regs-s3c2443-clock.h>
#include <mach/reset.h>
+#include <plat/gpio-core.h>
+#include <plat/gpio-cfg.h>
+#include <plat/gpio-cfg-helpers.h>
#include <plat/s3c2443.h>
#include <plat/devs.h>
#include <plat/cpu.h>
@@ -86,6 +90,9 @@ void __init s3c2443_init_uarts(struct s3c2410_uartcfg *cfg, int no)
void __init s3c2443_map_io(void)
{
+ s3c24xx_gpiocfg_default.set_pull = s3c_gpio_setpull_s3c2443;
+ s3c24xx_gpiocfg_default.get_pull = s3c_gpio_getpull_s3c2443;
+
iotable_init(s3c2443_iodesc, ARRAY_SIZE(s3c2443_iodesc));
}
diff --git a/arch/arm/mach-s3c64xx/clock.c b/arch/arm/mach-s3c64xx/clock.c
index 1c98d2ff..dd37820 100644
--- a/arch/arm/mach-s3c64xx/clock.c
+++ b/arch/arm/mach-s3c64xx/clock.c
@@ -127,7 +127,7 @@ int s3c64xx_sclk_ctrl(struct clk *clk, int enable)
return s3c64xx_gate(S3C_SCLK_GATE, clk, enable);
}
-static struct clk init_clocks_disable[] = {
+static struct clk init_clocks_off[] = {
{
.name = "nand",
.id = -1,
@@ -834,10 +834,6 @@ static struct clk *clks[] __initdata = {
void __init s3c64xx_register_clocks(unsigned long xtal,
unsigned armclk_divlimit)
{
- struct clk *clkp;
- int ret;
- int ptr;
-
armclk_mask = armclk_divlimit;
s3c24xx_register_baseclocks(xtal);
@@ -845,17 +841,8 @@ void __init s3c64xx_register_clocks(unsigned long xtal,
s3c_register_clocks(init_clocks, ARRAY_SIZE(init_clocks));
- clkp = init_clocks_disable;
- for (ptr = 0; ptr < ARRAY_SIZE(init_clocks_disable); ptr++, clkp++) {
-
- ret = s3c24xx_register_clock(clkp);
- if (ret < 0) {
- printk(KERN_ERR "Failed to register clock %s (%d)\n",
- clkp->name, ret);
- }
-
- (clkp->enable)(clkp, 0);
- }
+ s3c_register_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off));
+ s3c_disable_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off));
s3c24xx_register_clocks(clks1, ARRAY_SIZE(clks1));
s3c_register_clksrc(clksrcs, ARRAY_SIZE(clksrcs));
diff --git a/arch/arm/mach-s3c64xx/dma.c b/arch/arm/mach-s3c64xx/dma.c
index 372ea68..135db1b 100644
--- a/arch/arm/mach-s3c64xx/dma.c
+++ b/arch/arm/mach-s3c64xx/dma.c
@@ -212,6 +212,7 @@ static int s3c64xx_dma_start(struct s3c2410_dma_chan *chan)
config = readl(chan->regs + PL080S_CH_CONFIG);
config |= PL080_CONFIG_ENABLE;
+ config &= ~PL080_CONFIG_HALT;
pr_debug("%s: writing config %08x\n", __func__, config);
writel(config, chan->regs + PL080S_CH_CONFIG);
diff --git a/arch/arm/mach-s3c64xx/irq-eint.c b/arch/arm/mach-s3c64xx/irq-eint.c
index 5682d6a..2ead818 100644
--- a/arch/arm/mach-s3c64xx/irq-eint.c
+++ b/arch/arm/mach-s3c64xx/irq-eint.c
@@ -30,41 +30,41 @@
#include <plat/pm.h>
#define eint_offset(irq) ((irq) - IRQ_EINT(0))
-#define eint_irq_to_bit(irq) (1 << eint_offset(irq))
+#define eint_irq_to_bit(irq) ((u32)(1 << eint_offset(irq)))
-static inline void s3c_irq_eint_mask(unsigned int irq)
+static inline void s3c_irq_eint_mask(struct irq_data *data)
{
u32 mask;
mask = __raw_readl(S3C64XX_EINT0MASK);
- mask |= eint_irq_to_bit(irq);
+ mask |= (u32)data->chip_data;
__raw_writel(mask, S3C64XX_EINT0MASK);
}
-static void s3c_irq_eint_unmask(unsigned int irq)
+static void s3c_irq_eint_unmask(struct irq_data *data)
{
u32 mask;
mask = __raw_readl(S3C64XX_EINT0MASK);
- mask &= ~eint_irq_to_bit(irq);
+ mask &= ~((u32)data->chip_data);
__raw_writel(mask, S3C64XX_EINT0MASK);
}
-static inline void s3c_irq_eint_ack(unsigned int irq)
+static inline void s3c_irq_eint_ack(struct irq_data *data)
{
- __raw_writel(eint_irq_to_bit(irq), S3C64XX_EINT0PEND);
+ __raw_writel((u32)data->chip_data, S3C64XX_EINT0PEND);
}
-static void s3c_irq_eint_maskack(unsigned int irq)
+static void s3c_irq_eint_maskack(struct irq_data *data)
{
/* compiler should in-line these */
- s3c_irq_eint_mask(irq);
- s3c_irq_eint_ack(irq);
+ s3c_irq_eint_mask(data);
+ s3c_irq_eint_ack(data);
}
-static int s3c_irq_eint_set_type(unsigned int irq, unsigned int type)
+static int s3c_irq_eint_set_type(struct irq_data *data, unsigned int type)
{
- int offs = eint_offset(irq);
+ int offs = eint_offset(data->irq);
int pin, pin_val;
int shift;
u32 ctrl, mask;
@@ -140,12 +140,12 @@ static int s3c_irq_eint_set_type(unsigned int irq, unsigned int type)
static struct irq_chip s3c_irq_eint = {
.name = "s3c-eint",
- .mask = s3c_irq_eint_mask,
- .unmask = s3c_irq_eint_unmask,
- .mask_ack = s3c_irq_eint_maskack,
- .ack = s3c_irq_eint_ack,
- .set_type = s3c_irq_eint_set_type,
- .set_wake = s3c_irqext_wake,
+ .irq_mask = s3c_irq_eint_mask,
+ .irq_unmask = s3c_irq_eint_unmask,
+ .irq_mask_ack = s3c_irq_eint_maskack,
+ .irq_ack = s3c_irq_eint_ack,
+ .irq_set_type = s3c_irq_eint_set_type,
+ .irq_set_wake = s3c_irqext_wake,
};
/* s3c_irq_demux_eint
@@ -198,6 +198,7 @@ static int __init s3c64xx_init_irq_eint(void)
for (irq = IRQ_EINT(0); irq <= IRQ_EINT(27); irq++) {
set_irq_chip(irq, &s3c_irq_eint);
+ set_irq_chip_data(irq, (void *)eint_irq_to_bit(irq));
set_irq_handler(irq, handle_level_irq);
set_irq_flags(irq, IRQF_VALID);
}
diff --git a/arch/arm/mach-s5p6442/clock.c b/arch/arm/mach-s5p6442/clock.c
index 16d6e7e..fbbc7be 100644
--- a/arch/arm/mach-s5p6442/clock.c
+++ b/arch/arm/mach-s5p6442/clock.c
@@ -340,7 +340,7 @@ void __init_or_cpufreq s5p6442_setup_clocks(void)
clk_pclkd1.rate = pclkd1;
}
-static struct clk init_clocks_disable[] = {
+static struct clk init_clocks_off[] = {
{
.name = "pdma",
.id = -1,
@@ -408,23 +408,13 @@ static struct clk *clks[] __initdata = {
void __init s5p6442_register_clocks(void)
{
- struct clk *clkptr;
- int i, ret;
-
s3c24xx_register_clocks(clks, ARRAY_SIZE(clks));
s3c_register_clksrc(clksrcs, ARRAY_SIZE(clksrcs));
s3c_register_clocks(init_clocks, ARRAY_SIZE(init_clocks));
- clkptr = init_clocks_disable;
- for (i = 0; i < ARRAY_SIZE(init_clocks_disable); i++, clkptr++) {
- ret = s3c24xx_register_clock(clkptr);
- if (ret < 0) {
- printk(KERN_ERR "Fail to register clock %s (%d)\n",
- clkptr->name, ret);
- } else
- (clkptr->enable)(clkptr, 0);
- }
+ s3c_register_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off));
+ s3c_disable_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off));
s3c_pwmclk_init();
}
diff --git a/arch/arm/mach-s5p6442/include/mach/map.h b/arch/arm/mach-s5p6442/include/mach/map.h
index 31fb2e68..203dd5a 100644
--- a/arch/arm/mach-s5p6442/include/mach/map.h
+++ b/arch/arm/mach-s5p6442/include/mach/map.h
@@ -28,6 +28,9 @@
#define S5P6442_PA_VIC1 (0xE4100000)
#define S5P6442_PA_VIC2 (0xE4200000)
+#define S5P6442_PA_SROMC (0xE7000000)
+#define S5P_PA_SROMC S5P6442_PA_SROMC
+
#define S5P6442_PA_MDMA 0xE8000000
#define S5P6442_PA_PDMA 0xE9000000
diff --git a/arch/arm/mach-s5p6442/mach-smdk6442.c b/arch/arm/mach-s5p6442/mach-smdk6442.c
index 819fd80..eaf6b9c 100644
--- a/arch/arm/mach-s5p6442/mach-smdk6442.c
+++ b/arch/arm/mach-s5p6442/mach-smdk6442.c
@@ -12,6 +12,7 @@
#include <linux/types.h>
#include <linux/init.h>
#include <linux/serial_core.h>
+#include <linux/i2c.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
@@ -25,6 +26,7 @@
#include <plat/s5p6442.h>
#include <plat/devs.h>
#include <plat/cpu.h>
+#include <plat/iic.h>
/* Following are default values for UCON, ULCON and UFCON UART registers */
#define SMDK6442_UCON_DEFAULT (S3C2410_UCON_TXILEVEL | \
@@ -65,10 +67,16 @@ static struct s3c2410_uartcfg smdk6442_uartcfgs[] __initdata = {
};
static struct platform_device *smdk6442_devices[] __initdata = {
+ &s3c_device_i2c0,
+ &samsung_asoc_dma,
&s5p6442_device_iis0,
&s3c_device_wdt,
};
+static struct i2c_board_info smdk6442_i2c_devs0[] __initdata = {
+ { I2C_BOARD_INFO("wm8580", 0x1b), },
+};
+
static void __init smdk6442_map_io(void)
{
s5p_init_io(NULL, 0, S5P_VA_CHIPID);
@@ -78,6 +86,9 @@ static void __init smdk6442_map_io(void)
static void __init smdk6442_machine_init(void)
{
+ s3c_i2c0_set_platdata(NULL);
+ i2c_register_board_info(0, smdk6442_i2c_devs0,
+ ARRAY_SIZE(smdk6442_i2c_devs0));
platform_add_devices(smdk6442_devices, ARRAY_SIZE(smdk6442_devices));
}
diff --git a/arch/arm/mach-s5p6442/setup-i2c0.c b/arch/arm/mach-s5p6442/setup-i2c0.c
index 662695d..aad8565 100644
--- a/arch/arm/mach-s5p6442/setup-i2c0.c
+++ b/arch/arm/mach-s5p6442/setup-i2c0.c
@@ -14,12 +14,15 @@
#include <linux/kernel.h>
#include <linux/types.h>
+#include <linux/gpio.h>
struct platform_device; /* don't need the contents */
+#include <plat/gpio-cfg.h>
#include <plat/iic.h>
void s3c_i2c0_cfg_gpio(struct platform_device *dev)
{
- /* Will be populated later */
+ s3c_gpio_cfgall_range(S5P6442_GPD1(0), 2,
+ S3C_GPIO_SFN(2), S3C_GPIO_PULL_UP);
}
diff --git a/arch/arm/mach-s5p64x0/Makefile b/arch/arm/mach-s5p64x0/Makefile
index 2655829..ae6bf6f 100644
--- a/arch/arm/mach-s5p64x0/Makefile
+++ b/arch/arm/mach-s5p64x0/Makefile
@@ -12,9 +12,9 @@ obj- :=
# Core support for S5P64X0 system
-obj-$(CONFIG_ARCH_S5P64X0) += cpu.o init.o clock.o dma.o
+obj-$(CONFIG_ARCH_S5P64X0) += cpu.o init.o clock.o dma.o gpiolib.o
obj-$(CONFIG_ARCH_S5P64X0) += setup-i2c0.o
-obj-$(CONFIG_CPU_S5P6440) += clock-s5p6440.o gpio.o
+obj-$(CONFIG_CPU_S5P6440) += clock-s5p6440.o
obj-$(CONFIG_CPU_S5P6450) += clock-s5p6450.o
# machine support
diff --git a/arch/arm/mach-s5p64x0/clock-s5p6440.c b/arch/arm/mach-s5p64x0/clock-s5p6440.c
index 409c5fc..9f12c2e 100644
--- a/arch/arm/mach-s5p64x0/clock-s5p6440.c
+++ b/arch/arm/mach-s5p64x0/clock-s5p6440.c
@@ -133,7 +133,7 @@ static struct clksrc_clk clk_pclk_low = {
* recommended to keep the following clocks disabled until the driver requests
* for enabling the clock.
*/
-static struct clk init_clocks_disable[] = {
+static struct clk init_clocks_off[] = {
{
.name = "nand",
.id = -1,
@@ -419,7 +419,7 @@ static struct clksrc_sources clkset_audio = {
static struct clksrc_clk clksrcs[] = {
{
.clk = {
- .name = "mmc_bus",
+ .name = "sclk_mmc",
.id = 0,
.ctrlbit = (1 << 24),
.enable = s5p64x0_sclk_ctrl,
@@ -429,7 +429,7 @@ static struct clksrc_clk clksrcs[] = {
.reg_div = { .reg = S5P64X0_CLK_DIV1, .shift = 0, .size = 4 },
}, {
.clk = {
- .name = "mmc_bus",
+ .name = "sclk_mmc",
.id = 1,
.ctrlbit = (1 << 25),
.enable = s5p64x0_sclk_ctrl,
@@ -439,7 +439,7 @@ static struct clksrc_clk clksrcs[] = {
.reg_div = { .reg = S5P64X0_CLK_DIV1, .shift = 4, .size = 4 },
}, {
.clk = {
- .name = "mmc_bus",
+ .name = "sclk_mmc",
.id = 2,
.ctrlbit = (1 << 26),
.enable = s5p64x0_sclk_ctrl,
@@ -602,8 +602,6 @@ static struct clk *clks[] __initdata = {
void __init s5p6440_register_clocks(void)
{
- struct clk *clkp;
- int ret;
int ptr;
s3c24xx_register_clocks(clks, ARRAY_SIZE(clks));
@@ -614,16 +612,8 @@ void __init s5p6440_register_clocks(void)
s3c_register_clksrc(clksrcs, ARRAY_SIZE(clksrcs));
s3c_register_clocks(init_clocks, ARRAY_SIZE(init_clocks));
- clkp = init_clocks_disable;
- for (ptr = 0; ptr < ARRAY_SIZE(init_clocks_disable); ptr++, clkp++) {
-
- ret = s3c24xx_register_clock(clkp);
- if (ret < 0) {
- printk(KERN_ERR "Failed to register clock %s (%d)\n",
- clkp->name, ret);
- }
- (clkp->enable)(clkp, 0);
- }
+ s3c_register_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off));
+ s3c_disable_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off));
s3c_pwmclk_init();
}
diff --git a/arch/arm/mach-s5p64x0/clock-s5p6450.c b/arch/arm/mach-s5p64x0/clock-s5p6450.c
index 7fc6abd..4eec457 100644
--- a/arch/arm/mach-s5p64x0/clock-s5p6450.c
+++ b/arch/arm/mach-s5p64x0/clock-s5p6450.c
@@ -181,7 +181,7 @@ static struct clksrc_clk clk_pclk_low = {
* recommended to keep the following clocks disabled until the driver requests
* for enabling the clock.
*/
-static struct clk init_clocks_disable[] = {
+static struct clk init_clocks_off[] = {
{
.name = "usbhost",
.id = -1,
@@ -231,6 +231,12 @@ static struct clk init_clocks_disable[] = {
.enable = s5p64x0_pclk_ctrl,
.ctrlbit = (1 << 5),
}, {
+ .name = "rtc",
+ .id = -1,
+ .parent = &clk_pclk_low.clk,
+ .enable = s5p64x0_pclk_ctrl,
+ .ctrlbit = (1 << 6),
+ }, {
.name = "adc",
.id = -1,
.parent = &clk_pclk_low.clk,
@@ -261,6 +267,18 @@ static struct clk init_clocks_disable[] = {
.enable = s5p64x0_pclk_ctrl,
.ctrlbit = (1 << 26),
}, {
+ .name = "iis",
+ .id = 1,
+ .parent = &clk_pclk_low.clk,
+ .enable = s5p64x0_pclk_ctrl,
+ .ctrlbit = (1 << 15),
+ }, {
+ .name = "iis",
+ .id = 2,
+ .parent = &clk_pclk_low.clk,
+ .enable = s5p64x0_pclk_ctrl,
+ .ctrlbit = (1 << 16),
+ }, {
.name = "i2c",
.id = 1,
.parent = &clk_pclk_low.clk,
@@ -633,8 +651,6 @@ void __init_or_cpufreq s5p6450_setup_clocks(void)
void __init s5p6450_register_clocks(void)
{
- struct clk *clkp;
- int ret;
int ptr;
for (ptr = 0; ptr < ARRAY_SIZE(sysclks); ptr++)
@@ -643,16 +659,8 @@ void __init s5p6450_register_clocks(void)
s3c_register_clksrc(clksrcs, ARRAY_SIZE(clksrcs));
s3c_register_clocks(init_clocks, ARRAY_SIZE(init_clocks));
- clkp = init_clocks_disable;
- for (ptr = 0; ptr < ARRAY_SIZE(init_clocks_disable); ptr++, clkp++) {
-
- ret = s3c24xx_register_clock(clkp);
- if (ret < 0) {
- printk(KERN_ERR "Failed to register clock %s (%d)\n",
- clkp->name, ret);
- }
- (clkp->enable)(clkp, 0);
- }
+ s3c_register_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off));
+ s3c_disable_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off));
s3c_pwmclk_init();
}
diff --git a/arch/arm/mach-s5p64x0/dev-audio.c b/arch/arm/mach-s5p64x0/dev-audio.c
index 14f89e73..35f1f22 100644
--- a/arch/arm/mach-s5p64x0/dev-audio.c
+++ b/arch/arm/mach-s5p64x0/dev-audio.c
@@ -24,13 +24,13 @@ static const char *rclksrc[] = {
[1] = "sclk_audio2",
};
-static int s5p64x0_cfg_i2s(struct platform_device *pdev)
+static int s5p6440_cfg_i2s(struct platform_device *pdev)
{
- /* configure GPIO for i2s port */
switch (pdev->id) {
case 0:
- s3c_gpio_cfgpin_range(S5P6440_GPR(4), 5, S3C_GPIO_SFN(5));
- s3c_gpio_cfgpin_range(S5P6440_GPR(13), 2, S3C_GPIO_SFN(5));
+ s3c_gpio_cfgpin_range(S5P6440_GPC(4), 2, S3C_GPIO_SFN(5));
+ s3c_gpio_cfgpin(S5P6440_GPC(7), S3C_GPIO_SFN(5));
+ s3c_gpio_cfgpin_range(S5P6440_GPH(6), 4, S3C_GPIO_SFN(5));
break;
default:
printk(KERN_ERR "Invalid Device %d\n", pdev->id);
@@ -40,8 +40,8 @@ static int s5p64x0_cfg_i2s(struct platform_device *pdev)
return 0;
}
-static struct s3c_audio_pdata s5p64x0_i2s_pdata = {
- .cfg_gpio = s5p64x0_cfg_i2s,
+static struct s3c_audio_pdata s5p6440_i2s_pdata = {
+ .cfg_gpio = s5p6440_cfg_i2s,
.type = {
.i2s = {
.quirks = QUIRK_PRI_6CHAN,
@@ -50,7 +50,7 @@ static struct s3c_audio_pdata s5p64x0_i2s_pdata = {
},
};
-static struct resource s5p64x0_iis0_resource[] = {
+static struct resource s5p64x0_i2s0_resource[] = {
[0] = {
.start = S5P64X0_PA_I2S,
.end = S5P64X0_PA_I2S + 0x100 - 1,
@@ -71,20 +71,117 @@ static struct resource s5p64x0_iis0_resource[] = {
struct platform_device s5p6440_device_iis = {
.name = "samsung-i2s",
.id = 0,
- .num_resources = ARRAY_SIZE(s5p64x0_iis0_resource),
- .resource = s5p64x0_iis0_resource,
+ .num_resources = ARRAY_SIZE(s5p64x0_i2s0_resource),
+ .resource = s5p64x0_i2s0_resource,
.dev = {
- .platform_data = &s5p64x0_i2s_pdata,
+ .platform_data = &s5p6440_i2s_pdata,
+ },
+};
+
+static int s5p6450_cfg_i2s(struct platform_device *pdev)
+{
+ switch (pdev->id) {
+ case 0:
+ s3c_gpio_cfgpin_range(S5P6450_GPR(4), 5, S3C_GPIO_SFN(5));
+ s3c_gpio_cfgpin_range(S5P6450_GPR(13), 2, S3C_GPIO_SFN(5));
+ break;
+ case 1:
+ s3c_gpio_cfgpin(S5P6440_GPB(4), S3C_GPIO_SFN(5));
+ s3c_gpio_cfgpin_range(S5P6450_GPC(0), 4, S3C_GPIO_SFN(5));
+ break;
+ case 2:
+ s3c_gpio_cfgpin_range(S5P6450_GPK(0), 5, S3C_GPIO_SFN(5));
+ break;
+ default:
+ printk(KERN_ERR "Invalid Device %d\n", pdev->id);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static struct s3c_audio_pdata s5p6450_i2s0_pdata = {
+ .cfg_gpio = s5p6450_cfg_i2s,
+ .type = {
+ .i2s = {
+ .quirks = QUIRK_PRI_6CHAN,
+ .src_clk = rclksrc,
+ },
},
};
struct platform_device s5p6450_device_iis0 = {
.name = "samsung-i2s",
.id = 0,
- .num_resources = ARRAY_SIZE(s5p64x0_iis0_resource),
- .resource = s5p64x0_iis0_resource,
+ .num_resources = ARRAY_SIZE(s5p64x0_i2s0_resource),
+ .resource = s5p64x0_i2s0_resource,
+ .dev = {
+ .platform_data = &s5p6450_i2s0_pdata,
+ },
+};
+
+static struct s3c_audio_pdata s5p6450_i2s_pdata = {
+ .cfg_gpio = s5p6450_cfg_i2s,
+ .type = {
+ .i2s = {
+ .src_clk = rclksrc,
+ },
+ },
+};
+
+static struct resource s5p6450_i2s1_resource[] = {
+ [0] = {
+ .start = S5P6450_PA_I2S1,
+ .end = S5P6450_PA_I2S1 + 0x100 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = DMACH_I2S1_TX,
+ .end = DMACH_I2S1_TX,
+ .flags = IORESOURCE_DMA,
+ },
+ [2] = {
+ .start = DMACH_I2S1_RX,
+ .end = DMACH_I2S1_RX,
+ .flags = IORESOURCE_DMA,
+ },
+};
+
+struct platform_device s5p6450_device_iis1 = {
+ .name = "samsung-i2s",
+ .id = 1,
+ .num_resources = ARRAY_SIZE(s5p6450_i2s1_resource),
+ .resource = s5p6450_i2s1_resource,
+ .dev = {
+ .platform_data = &s5p6450_i2s_pdata,
+ },
+};
+
+static struct resource s5p6450_i2s2_resource[] = {
+ [0] = {
+ .start = S5P6450_PA_I2S2,
+ .end = S5P6450_PA_I2S2 + 0x100 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = DMACH_I2S2_TX,
+ .end = DMACH_I2S2_TX,
+ .flags = IORESOURCE_DMA,
+ },
+ [2] = {
+ .start = DMACH_I2S2_RX,
+ .end = DMACH_I2S2_RX,
+ .flags = IORESOURCE_DMA,
+ },
+};
+
+struct platform_device s5p6450_device_iis2 = {
+ .name = "samsung-i2s",
+ .id = 2,
+ .num_resources = ARRAY_SIZE(s5p6450_i2s2_resource),
+ .resource = s5p6450_i2s2_resource,
.dev = {
- .platform_data = &s5p64x0_i2s_pdata,
+ .platform_data = &s5p6450_i2s_pdata,
},
};
diff --git a/arch/arm/mach-s5p64x0/gpio.c b/arch/arm/mach-s5p64x0/gpiolib.c
index 39159dd..e7fb3b0 100644
--- a/arch/arm/mach-s5p64x0/gpio.c
+++ b/arch/arm/mach-s5p64x0/gpiolib.c
@@ -1,4 +1,4 @@
-/* linux/arch/arm/mach-s5p64x0/gpio.c
+/* linux/arch/arm/mach-s5p64x0/gpiolib.c
*
* Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
* http://www.samsung.com
@@ -17,13 +17,12 @@
#include <mach/map.h>
#include <mach/regs-gpio.h>
+#include <mach/regs-clock.h>
#include <plat/gpio-core.h>
#include <plat/gpio-cfg.h>
#include <plat/gpio-cfg-helpers.h>
-/* To be implemented S5P6450 GPIO */
-
/*
* S5P6440 GPIO bank summary:
*
@@ -40,6 +39,25 @@
* P 8 2Bit Yes 8
* R 15 4Bit[2] Yes 8
*
+ * S5P6450 GPIO bank summary:
+ *
+ * Bank GPIOs Style SlpCon ExtInt Group
+ * A 6 4Bit Yes 1
+ * B 7 4Bit Yes 1
+ * C 8 4Bit Yes 2
+ * D 8 4Bit Yes None
+ * F 2 2Bit Yes None
+ * G 14 4Bit[2] Yes 5
+ * H 10 4Bit[2] Yes 6
+ * I 16 2Bit Yes None
+ * J 12 2Bit Yes None
+ * K 5 4Bit Yes None
+ * N 16 2Bit No IRQ_EINT
+ * P 11 2Bit Yes 8
+ * Q 14 2Bit Yes None
+ * R 15 4Bit[2] Yes None
+ * S 8 2Bit Yes None
+ *
* [1] BANKF pins 14,15 do not form part of the external interrupt sources
* [2] BANK has two control registers, GPxCON0 and GPxCON1
*/
@@ -190,7 +208,7 @@ static struct s3c_gpio_cfg s5p64x0_gpio_cfgs[] = {
static struct s3c_gpio_chip s5p6440_gpio_4bit[] = {
{
- .base = S5P6440_GPA_BASE,
+ .base = S5P64X0_GPA_BASE,
.config = &s5p64x0_gpio_cfgs[1],
.chip = {
.base = S5P6440_GPA(0),
@@ -198,7 +216,7 @@ static struct s3c_gpio_chip s5p6440_gpio_4bit[] = {
.label = "GPA",
},
}, {
- .base = S5P6440_GPB_BASE,
+ .base = S5P64X0_GPB_BASE,
.config = &s5p64x0_gpio_cfgs[1],
.chip = {
.base = S5P6440_GPB(0),
@@ -206,7 +224,7 @@ static struct s3c_gpio_chip s5p6440_gpio_4bit[] = {
.label = "GPB",
},
}, {
- .base = S5P6440_GPC_BASE,
+ .base = S5P64X0_GPC_BASE,
.config = &s5p64x0_gpio_cfgs[1],
.chip = {
.base = S5P6440_GPC(0),
@@ -214,7 +232,7 @@ static struct s3c_gpio_chip s5p6440_gpio_4bit[] = {
.label = "GPC",
},
}, {
- .base = S5P6440_GPG_BASE,
+ .base = S5P64X0_GPG_BASE,
.config = &s5p64x0_gpio_cfgs[1],
.chip = {
.base = S5P6440_GPG(0),
@@ -226,7 +244,7 @@ static struct s3c_gpio_chip s5p6440_gpio_4bit[] = {
static struct s3c_gpio_chip s5p6440_gpio_4bit2[] = {
{
- .base = S5P6440_GPH_BASE + 0x4,
+ .base = S5P64X0_GPH_BASE + 0x4,
.config = &s5p64x0_gpio_cfgs[1],
.chip = {
.base = S5P6440_GPH(0),
@@ -238,7 +256,7 @@ static struct s3c_gpio_chip s5p6440_gpio_4bit2[] = {
static struct s3c_gpio_chip s5p6440_gpio_rbank_4bit2[] = {
{
- .base = S5P6440_GPR_BASE + 0x4,
+ .base = S5P64X0_GPR_BASE + 0x4,
.config = &s5p64x0_gpio_cfgs[2],
.chip = {
.base = S5P6440_GPR(0),
@@ -250,7 +268,7 @@ static struct s3c_gpio_chip s5p6440_gpio_rbank_4bit2[] = {
static struct s3c_gpio_chip s5p6440_gpio_2bit[] = {
{
- .base = S5P6440_GPF_BASE,
+ .base = S5P64X0_GPF_BASE,
.config = &s5p64x0_gpio_cfgs[5],
.chip = {
.base = S5P6440_GPF(0),
@@ -258,7 +276,7 @@ static struct s3c_gpio_chip s5p6440_gpio_2bit[] = {
.label = "GPF",
},
}, {
- .base = S5P6440_GPI_BASE,
+ .base = S5P64X0_GPI_BASE,
.config = &s5p64x0_gpio_cfgs[3],
.chip = {
.base = S5P6440_GPI(0),
@@ -266,7 +284,7 @@ static struct s3c_gpio_chip s5p6440_gpio_2bit[] = {
.label = "GPI",
},
}, {
- .base = S5P6440_GPJ_BASE,
+ .base = S5P64X0_GPJ_BASE,
.config = &s5p64x0_gpio_cfgs[3],
.chip = {
.base = S5P6440_GPJ(0),
@@ -274,7 +292,7 @@ static struct s3c_gpio_chip s5p6440_gpio_2bit[] = {
.label = "GPJ",
},
}, {
- .base = S5P6440_GPN_BASE,
+ .base = S5P64X0_GPN_BASE,
.config = &s5p64x0_gpio_cfgs[4],
.chip = {
.base = S5P6440_GPN(0),
@@ -282,7 +300,7 @@ static struct s3c_gpio_chip s5p6440_gpio_2bit[] = {
.label = "GPN",
},
}, {
- .base = S5P6440_GPP_BASE,
+ .base = S5P64X0_GPP_BASE,
.config = &s5p64x0_gpio_cfgs[5],
.chip = {
.base = S5P6440_GPP(0),
@@ -292,6 +310,142 @@ static struct s3c_gpio_chip s5p6440_gpio_2bit[] = {
},
};
+static struct s3c_gpio_chip s5p6450_gpio_4bit[] = {
+ {
+ .base = S5P64X0_GPA_BASE,
+ .config = &s5p64x0_gpio_cfgs[1],
+ .chip = {
+ .base = S5P6450_GPA(0),
+ .ngpio = S5P6450_GPIO_A_NR,
+ .label = "GPA",
+ },
+ }, {
+ .base = S5P64X0_GPB_BASE,
+ .config = &s5p64x0_gpio_cfgs[1],
+ .chip = {
+ .base = S5P6450_GPB(0),
+ .ngpio = S5P6450_GPIO_B_NR,
+ .label = "GPB",
+ },
+ }, {
+ .base = S5P64X0_GPC_BASE,
+ .config = &s5p64x0_gpio_cfgs[1],
+ .chip = {
+ .base = S5P6450_GPC(0),
+ .ngpio = S5P6450_GPIO_C_NR,
+ .label = "GPC",
+ },
+ }, {
+ .base = S5P6450_GPD_BASE,
+ .config = &s5p64x0_gpio_cfgs[1],
+ .chip = {
+ .base = S5P6450_GPD(0),
+ .ngpio = S5P6450_GPIO_D_NR,
+ .label = "GPD",
+ },
+ }, {
+ .base = S5P6450_GPK_BASE,
+ .config = &s5p64x0_gpio_cfgs[1],
+ .chip = {
+ .base = S5P6450_GPK(0),
+ .ngpio = S5P6450_GPIO_K_NR,
+ .label = "GPK",
+ },
+ },
+};
+
+static struct s3c_gpio_chip s5p6450_gpio_4bit2[] = {
+ {
+ .base = S5P64X0_GPG_BASE + 0x4,
+ .config = &s5p64x0_gpio_cfgs[1],
+ .chip = {
+ .base = S5P6450_GPG(0),
+ .ngpio = S5P6450_GPIO_G_NR,
+ .label = "GPG",
+ },
+ }, {
+ .base = S5P64X0_GPH_BASE + 0x4,
+ .config = &s5p64x0_gpio_cfgs[1],
+ .chip = {
+ .base = S5P6450_GPH(0),
+ .ngpio = S5P6450_GPIO_H_NR,
+ .label = "GPH",
+ },
+ },
+};
+
+static struct s3c_gpio_chip s5p6450_gpio_rbank_4bit2[] = {
+ {
+ .base = S5P64X0_GPR_BASE + 0x4,
+ .config = &s5p64x0_gpio_cfgs[2],
+ .chip = {
+ .base = S5P6450_GPR(0),
+ .ngpio = S5P6450_GPIO_R_NR,
+ .label = "GPR",
+ },
+ },
+};
+
+static struct s3c_gpio_chip s5p6450_gpio_2bit[] = {
+ {
+ .base = S5P64X0_GPF_BASE,
+ .config = &s5p64x0_gpio_cfgs[5],
+ .chip = {
+ .base = S5P6450_GPF(0),
+ .ngpio = S5P6450_GPIO_F_NR,
+ .label = "GPF",
+ },
+ }, {
+ .base = S5P64X0_GPI_BASE,
+ .config = &s5p64x0_gpio_cfgs[3],
+ .chip = {
+ .base = S5P6450_GPI(0),
+ .ngpio = S5P6450_GPIO_I_NR,
+ .label = "GPI",
+ },
+ }, {
+ .base = S5P64X0_GPJ_BASE,
+ .config = &s5p64x0_gpio_cfgs[3],
+ .chip = {
+ .base = S5P6450_GPJ(0),
+ .ngpio = S5P6450_GPIO_J_NR,
+ .label = "GPJ",
+ },
+ }, {
+ .base = S5P64X0_GPN_BASE,
+ .config = &s5p64x0_gpio_cfgs[4],
+ .chip = {
+ .base = S5P6450_GPN(0),
+ .ngpio = S5P6450_GPIO_N_NR,
+ .label = "GPN",
+ },
+ }, {
+ .base = S5P64X0_GPP_BASE,
+ .config = &s5p64x0_gpio_cfgs[5],
+ .chip = {
+ .base = S5P6450_GPP(0),
+ .ngpio = S5P6450_GPIO_P_NR,
+ .label = "GPP",
+ },
+ }, {
+ .base = S5P6450_GPQ_BASE,
+ .config = &s5p64x0_gpio_cfgs[4],
+ .chip = {
+ .base = S5P6450_GPQ(0),
+ .ngpio = S5P6450_GPIO_Q_NR,
+ .label = "GPQ",
+ },
+ }, {
+ .base = S5P6450_GPS_BASE,
+ .config = &s5p64x0_gpio_cfgs[5],
+ .chip = {
+ .base = S5P6450_GPS(0),
+ .ngpio = S5P6450_GPIO_S_NR,
+ .label = "GPS",
+ },
+ },
+};
+
void __init s5p64x0_gpiolib_set_cfg(struct s3c_gpio_cfg *chipcfg, int nr_chips)
{
for (; nr_chips > 0; nr_chips--, chipcfg++) {
@@ -317,26 +471,41 @@ static void __init s5p64x0_gpio_add_rbank_4bit2(struct s3c_gpio_chip *chip,
}
}
-static int __init s5p6440_gpiolib_init(void)
+static int __init s5p64x0_gpiolib_init(void)
{
- struct s3c_gpio_chip *chips = s5p6440_gpio_2bit;
- int nr_chips = ARRAY_SIZE(s5p6440_gpio_2bit);
+ unsigned int chipid;
+
+ chipid = __raw_readl(S5P64X0_SYS_ID);
s5p64x0_gpiolib_set_cfg(s5p64x0_gpio_cfgs,
ARRAY_SIZE(s5p64x0_gpio_cfgs));
- for (; nr_chips > 0; nr_chips--, chips++)
- s3c_gpiolib_add(chips);
+ if ((chipid & 0xff000) == 0x50000) {
+ samsung_gpiolib_add_2bit_chips(s5p6450_gpio_2bit,
+ ARRAY_SIZE(s5p6450_gpio_2bit));
+
+ samsung_gpiolib_add_4bit_chips(s5p6450_gpio_4bit,
+ ARRAY_SIZE(s5p6450_gpio_4bit));
- samsung_gpiolib_add_4bit_chips(s5p6440_gpio_4bit,
- ARRAY_SIZE(s5p6440_gpio_4bit));
+ samsung_gpiolib_add_4bit2_chips(s5p6450_gpio_4bit2,
+ ARRAY_SIZE(s5p6450_gpio_4bit2));
- samsung_gpiolib_add_4bit2_chips(s5p6440_gpio_4bit2,
- ARRAY_SIZE(s5p6440_gpio_4bit2));
+ s5p64x0_gpio_add_rbank_4bit2(s5p6450_gpio_rbank_4bit2,
+ ARRAY_SIZE(s5p6450_gpio_rbank_4bit2));
+ } else {
+ samsung_gpiolib_add_2bit_chips(s5p6440_gpio_2bit,
+ ARRAY_SIZE(s5p6440_gpio_2bit));
- s5p64x0_gpio_add_rbank_4bit2(s5p6440_gpio_rbank_4bit2,
- ARRAY_SIZE(s5p6440_gpio_rbank_4bit2));
+ samsung_gpiolib_add_4bit_chips(s5p6440_gpio_4bit,
+ ARRAY_SIZE(s5p6440_gpio_4bit));
+
+ samsung_gpiolib_add_4bit2_chips(s5p6440_gpio_4bit2,
+ ARRAY_SIZE(s5p6440_gpio_4bit2));
+
+ s5p64x0_gpio_add_rbank_4bit2(s5p6440_gpio_rbank_4bit2,
+ ARRAY_SIZE(s5p6440_gpio_rbank_4bit2));
+ }
return 0;
}
-arch_initcall(s5p6440_gpiolib_init);
+core_initcall(s5p64x0_gpiolib_init);
diff --git a/arch/arm/mach-s5p64x0/include/mach/map.h b/arch/arm/mach-s5p64x0/include/mach/map.h
index 31e5341..a9365e5 100644
--- a/arch/arm/mach-s5p64x0/include/mach/map.h
+++ b/arch/arm/mach-s5p64x0/include/mach/map.h
@@ -29,6 +29,9 @@
#define S5P64X0_PA_VIC0 (0xE4000000)
#define S5P64X0_PA_VIC1 (0xE4100000)
+#define S5P64X0_PA_SROMC (0xE7000000)
+#define S5P_PA_SROMC S5P64X0_PA_SROMC
+
#define S5P64X0_PA_PDMA (0xE9000000)
#define S5P64X0_PA_TIMER (0xEA000000)
@@ -63,6 +66,8 @@
#define S5P64X0_PA_HSMMC(x) (0xED800000 + ((x) * 0x100000))
#define S5P64X0_PA_I2S (0xF2000000)
+#define S5P6450_PA_I2S1 0xF2800000
+#define S5P6450_PA_I2S2 0xF2900000
#define S5P64X0_PA_PCM (0xF2100000)
diff --git a/arch/arm/mach-s5p64x0/include/mach/regs-gpio.h b/arch/arm/mach-s5p64x0/include/mach/regs-gpio.h
index 85f448e..0953ef6 100644
--- a/arch/arm/mach-s5p64x0/include/mach/regs-gpio.h
+++ b/arch/arm/mach-s5p64x0/include/mach/regs-gpio.h
@@ -15,48 +15,23 @@
#include <mach/map.h>
-/* Will be implemented S5P6442 GPIOlib */
-
/* Base addresses for each of the banks */
-#define S5P6440_GPA_BASE (S5P_VA_GPIO + 0x0000)
-#define S5P6440_GPB_BASE (S5P_VA_GPIO + 0x0020)
-#define S5P6440_GPC_BASE (S5P_VA_GPIO + 0x0040)
-#define S5P6440_GPF_BASE (S5P_VA_GPIO + 0x00A0)
-#define S5P6440_GPG_BASE (S5P_VA_GPIO + 0x00C0)
-#define S5P6440_GPH_BASE (S5P_VA_GPIO + 0x00E0)
-#define S5P6440_GPI_BASE (S5P_VA_GPIO + 0x0100)
-#define S5P6440_GPJ_BASE (S5P_VA_GPIO + 0x0120)
-#define S5P6440_GPN_BASE (S5P_VA_GPIO + 0x0830)
-#define S5P6440_GPP_BASE (S5P_VA_GPIO + 0x0160)
-#define S5P6440_GPR_BASE (S5P_VA_GPIO + 0x0290)
-
-#define S5P6440_EINT0CON0 (S5P_VA_GPIO + 0x900)
-#define S5P6440_EINT0FLTCON0 (S5P_VA_GPIO + 0x910)
-#define S5P6440_EINT0FLTCON1 (S5P_VA_GPIO + 0x914)
-#define S5P6440_EINT0MASK (S5P_VA_GPIO + 0x920)
-#define S5P6440_EINT0PEND (S5P_VA_GPIO + 0x924)
-
-/* for LCD */
-
-#define S5P6440_SPCON_LCD_SEL_RGB (1 << 0)
-#define S5P6440_SPCON_LCD_SEL_MASK (3 << 0)
-
-/*
- * These set of macros are not really useful for the
- * GPF/GPI/GPJ/GPN/GPP, useful for others set of GPIO's (4 bit)
- */
-
-#define S5P6440_GPIO_CONMASK(__gpio) (0xf << ((__gpio) * 4))
-#define S5P6440_GPIO_INPUT(__gpio) (0x0 << ((__gpio) * 4))
-#define S5P6440_GPIO_OUTPUT(__gpio) (0x1 << ((__gpio) * 4))
-
-/*
- * Use these macros for GPF/GPI/GPJ/GPN/GPP set of GPIO (2 bit)
- */
-
-#define S5P6440_GPIO2_CONMASK(__gpio) (0x3 << ((__gpio) * 2))
-#define S5P6440_GPIO2_INPUT(__gpio) (0x0 << ((__gpio) * 2))
-#define S5P6440_GPIO2_OUTPUT(__gpio) (0x1 << ((__gpio) * 2))
+#define S5P64X0_GPA_BASE (S5P_VA_GPIO + 0x0000)
+#define S5P64X0_GPB_BASE (S5P_VA_GPIO + 0x0020)
+#define S5P64X0_GPC_BASE (S5P_VA_GPIO + 0x0040)
+#define S5P64X0_GPF_BASE (S5P_VA_GPIO + 0x00A0)
+#define S5P64X0_GPG_BASE (S5P_VA_GPIO + 0x00C0)
+#define S5P64X0_GPH_BASE (S5P_VA_GPIO + 0x00E0)
+#define S5P64X0_GPI_BASE (S5P_VA_GPIO + 0x0100)
+#define S5P64X0_GPJ_BASE (S5P_VA_GPIO + 0x0120)
+#define S5P64X0_GPN_BASE (S5P_VA_GPIO + 0x0830)
+#define S5P64X0_GPP_BASE (S5P_VA_GPIO + 0x0160)
+#define S5P64X0_GPR_BASE (S5P_VA_GPIO + 0x0290)
+
+#define S5P6450_GPD_BASE (S5P_VA_GPIO + 0x0060)
+#define S5P6450_GPK_BASE (S5P_VA_GPIO + 0x0140)
+#define S5P6450_GPQ_BASE (S5P_VA_GPIO + 0x0180)
+#define S5P6450_GPS_BASE (S5P_VA_GPIO + 0x0300)
#endif /* __ASM_ARCH_REGS_GPIO_H */
diff --git a/arch/arm/mach-s5p64x0/mach-smdk6440.c b/arch/arm/mach-s5p64x0/mach-smdk6440.c
index 87c3f03..e5beb84 100644
--- a/arch/arm/mach-s5p64x0/mach-smdk6440.c
+++ b/arch/arm/mach-s5p64x0/mach-smdk6440.c
@@ -95,6 +95,7 @@ static struct platform_device *smdk6440_devices[] __initdata = {
&s3c_device_i2c1,
&s3c_device_ts,
&s3c_device_wdt,
+ &samsung_asoc_dma,
&s5p6440_device_iis,
};
@@ -117,6 +118,7 @@ static struct s3c2410_platform_i2c s5p6440_i2c1_data __initdata = {
static struct i2c_board_info smdk6440_i2c_devs0[] __initdata = {
{ I2C_BOARD_INFO("24c08", 0x50), },
+ { I2C_BOARD_INFO("wm8580", 0x1b), },
};
static struct i2c_board_info smdk6440_i2c_devs1[] __initdata = {
diff --git a/arch/arm/mach-s5p64x0/mach-smdk6450.c b/arch/arm/mach-s5p64x0/mach-smdk6450.c
index d609f5a..3a20de0 100644
--- a/arch/arm/mach-s5p64x0/mach-smdk6450.c
+++ b/arch/arm/mach-s5p64x0/mach-smdk6450.c
@@ -113,6 +113,7 @@ static struct platform_device *smdk6450_devices[] __initdata = {
&s3c_device_i2c1,
&s3c_device_ts,
&s3c_device_wdt,
+ &samsung_asoc_dma,
&s5p6450_device_iis0,
/* s5p6450_device_spi0 will be added */
};
@@ -135,6 +136,7 @@ static struct s3c2410_platform_i2c s5p6450_i2c1_data __initdata = {
};
static struct i2c_board_info smdk6450_i2c_devs0[] __initdata = {
+ { I2C_BOARD_INFO("wm8580", 0x1b), },
{ I2C_BOARD_INFO("24c08", 0x50), }, /* Samsung KS24C080C EEPROM */
};
diff --git a/arch/arm/mach-s5pc100/clock.c b/arch/arm/mach-s5pc100/clock.c
index 2d4a761..0305e9b 100644
--- a/arch/arm/mach-s5pc100/clock.c
+++ b/arch/arm/mach-s5pc100/clock.c
@@ -396,7 +396,7 @@ static int s5pc100_sclk1_ctrl(struct clk *clk, int enable)
* recommended to keep the following clocks disabled until the driver requests
* for enabling the clock.
*/
-static struct clk init_clocks_disable[] = {
+static struct clk init_clocks_off[] = {
{
.name = "cssys",
.id = -1,
@@ -1381,8 +1381,6 @@ static struct clk *clks[] __initdata = {
void __init s5pc100_register_clocks(void)
{
- struct clk *clkp;
- int ret;
int ptr;
s3c24xx_register_clocks(clks, ARRAY_SIZE(clks));
@@ -1393,16 +1391,8 @@ void __init s5pc100_register_clocks(void)
s3c_register_clksrc(clksrcs, ARRAY_SIZE(clksrcs));
s3c_register_clocks(init_clocks, ARRAY_SIZE(init_clocks));
- clkp = init_clocks_disable;
- for (ptr = 0; ptr < ARRAY_SIZE(init_clocks_disable); ptr++, clkp++) {
-
- ret = s3c24xx_register_clock(clkp);
- if (ret < 0) {
- printk(KERN_ERR "Failed to register clock %s (%d)\n",
- clkp->name, ret);
- }
- (clkp->enable)(clkp, 0);
- }
+ s3c_register_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off));
+ s3c_disable_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off));
s3c_pwmclk_init();
}
diff --git a/arch/arm/mach-s5pc100/include/mach/map.h b/arch/arm/mach-s5pc100/include/mach/map.h
index 32e9cab..328467b 100644
--- a/arch/arm/mach-s5pc100/include/mach/map.h
+++ b/arch/arm/mach-s5pc100/include/mach/map.h
@@ -55,6 +55,8 @@
#define S5PC100_VA_VIC_OFFSET 0x10000
#define S5PC1XX_VA_VIC(x) (S5PC100_VA_VIC + ((x) * S5PC100_VA_VIC_OFFSET))
+#define S5PC100_PA_SROMC (0xE7000000)
+#define S5P_PA_SROMC S5PC100_PA_SROMC
#define S5PC100_PA_ONENAND (0xE7100000)
diff --git a/arch/arm/mach-s5pv210/Kconfig b/arch/arm/mach-s5pv210/Kconfig
index 862f239..53aabef 100644
--- a/arch/arm/mach-s5pv210/Kconfig
+++ b/arch/arm/mach-s5pv210/Kconfig
@@ -118,6 +118,7 @@ menu "S5PV210 Machines"
config MACH_SMDKV210
bool "SMDKV210"
select CPU_S5PV210
+ select S3C_DEV_FB
select S3C_DEV_HSMMC
select S3C_DEV_HSMMC1
select S3C_DEV_HSMMC2
@@ -130,6 +131,7 @@ config MACH_SMDKV210
select SAMSUNG_DEV_IDE
select SAMSUNG_DEV_KEYPAD
select SAMSUNG_DEV_TS
+ select S5PV210_SETUP_FB_24BPP
select S5PV210_SETUP_I2C1
select S5PV210_SETUP_I2C2
select S5PV210_SETUP_IDE
diff --git a/arch/arm/mach-s5pv210/clock.c b/arch/arm/mach-s5pv210/clock.c
index b774ff1..2d59949 100644
--- a/arch/arm/mach-s5pv210/clock.c
+++ b/arch/arm/mach-s5pv210/clock.c
@@ -309,7 +309,7 @@ static struct clk_ops clk_fout_apll_ops = {
.get_rate = s5pv210_clk_fout_apll_get_rate,
};
-static struct clk init_clocks_disable[] = {
+static struct clk init_clocks_off[] = {
{
.name = "pdma",
.id = 0,
@@ -525,6 +525,12 @@ static struct clk init_clocks[] = {
.parent = &clk_pclk_psys.clk,
.enable = s5pv210_clk_ip3_ctrl,
.ctrlbit = (1 << 20),
+ }, {
+ .name = "sromc",
+ .id = -1,
+ .parent = &clk_hclk_psys.clk,
+ .enable = s5pv210_clk_ip1_ctrl,
+ .ctrlbit = (1 << 26),
},
};
@@ -1220,13 +1226,9 @@ static struct clk *clks[] __initdata = {
void __init s5pv210_register_clocks(void)
{
- struct clk *clkp;
- int ret;
int ptr;
- ret = s3c24xx_register_clocks(clks, ARRAY_SIZE(clks));
- if (ret > 0)
- printk(KERN_ERR "Failed to register %u clocks\n", ret);
+ s3c24xx_register_clocks(clks, ARRAY_SIZE(clks));
for (ptr = 0; ptr < ARRAY_SIZE(sysclks); ptr++)
s3c_register_clksrc(sysclks[ptr], 1);
@@ -1234,15 +1236,8 @@ void __init s5pv210_register_clocks(void)
s3c_register_clksrc(clksrcs, ARRAY_SIZE(clksrcs));
s3c_register_clocks(init_clocks, ARRAY_SIZE(init_clocks));
- clkp = init_clocks_disable;
- for (ptr = 0; ptr < ARRAY_SIZE(init_clocks_disable); ptr++, clkp++) {
- ret = s3c24xx_register_clock(clkp);
- if (ret < 0) {
- printk(KERN_ERR "Failed to register clock %s (%d)\n",
- clkp->name, ret);
- }
- (clkp->enable)(clkp, 0);
- }
+ s3c_register_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off));
+ s3c_disable_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off));
s3c_pwmclk_init();
}
diff --git a/arch/arm/mach-s5pv210/cpu.c b/arch/arm/mach-s5pv210/cpu.c
index 8eb480e..61e6c24 100644
--- a/arch/arm/mach-s5pv210/cpu.c
+++ b/arch/arm/mach-s5pv210/cpu.c
@@ -81,11 +81,6 @@ static struct map_desc s5pv210_iodesc[] __initdata = {
.length = SZ_512K,
.type = MT_DEVICE,
}, {
- .virtual = (unsigned long)S5P_VA_SROMC,
- .pfn = __phys_to_pfn(S5PV210_PA_SROMC),
- .length = SZ_4K,
- .type = MT_DEVICE,
- }, {
.virtual = (unsigned long)S5P_VA_DMC0,
.pfn = __phys_to_pfn(S5PV210_PA_DMC0),
.length = SZ_4K,
diff --git a/arch/arm/mach-s5pv210/include/mach/irqs.h b/arch/arm/mach-s5pv210/include/mach/irqs.h
index 119b95f..26710b3 100644
--- a/arch/arm/mach-s5pv210/include/mach/irqs.h
+++ b/arch/arm/mach-s5pv210/include/mach/irqs.h
@@ -65,7 +65,7 @@
#define IRQ_HSMMC0 S5P_IRQ_VIC1(26)
#define IRQ_HSMMC1 S5P_IRQ_VIC1(27)
#define IRQ_HSMMC2 S5P_IRQ_VIC1(28)
-#define IRQ_MIPICSI S5P_IRQ_VIC1(29)
+#define IRQ_MIPI_CSIS S5P_IRQ_VIC1(29)
#define IRQ_MIPIDSI S5P_IRQ_VIC1(30)
#define IRQ_ONENAND_AUDI S5P_IRQ_VIC1(31)
@@ -132,5 +132,6 @@
#define IRQ_LCD_FIFO IRQ_LCD0
#define IRQ_LCD_VSYNC IRQ_LCD1
#define IRQ_LCD_SYSTEM IRQ_LCD2
+#define IRQ_MIPI_CSIS0 IRQ_MIPI_CSIS
#endif /* ASM_ARCH_IRQS_H */
diff --git a/arch/arm/mach-s5pv210/include/mach/map.h b/arch/arm/mach-s5pv210/include/mach/map.h
index 861d7fe..3611492 100644
--- a/arch/arm/mach-s5pv210/include/mach/map.h
+++ b/arch/arm/mach-s5pv210/include/mach/map.h
@@ -16,6 +16,8 @@
#include <plat/map-base.h>
#include <plat/map-s5p.h>
+#define S5PV210_PA_SROM_BANK5 (0xA8000000)
+
#define S5PC110_PA_ONENAND (0xB0000000)
#define S5P_PA_ONENAND S5PC110_PA_ONENAND
@@ -60,6 +62,7 @@
#define S3C_VA_UARTx(x) (S3C_VA_UART + ((x) * S3C_UART_OFFSET))
#define S5PV210_PA_SROMC (0xE8000000)
+#define S5P_PA_SROMC S5PV210_PA_SROMC
#define S5PV210_PA_CFCON (0xE8200000)
@@ -107,6 +110,8 @@
#define S5PV210_PA_DMC0 (0xF0000000)
#define S5PV210_PA_DMC1 (0xF1400000)
+#define S5PV210_PA_MIPI_CSIS 0xFA600000
+
/* compatibiltiy defines. */
#define S3C_PA_UART S5PV210_PA_UART
#define S3C_PA_HSMMC0 S5PV210_PA_HSMMC(0)
@@ -123,6 +128,7 @@
#define S5P_PA_FIMC0 S5PV210_PA_FIMC0
#define S5P_PA_FIMC1 S5PV210_PA_FIMC1
#define S5P_PA_FIMC2 S5PV210_PA_FIMC2
+#define S5P_PA_MIPI_CSIS0 S5PV210_PA_MIPI_CSIS
#define SAMSUNG_PA_ADC S5PV210_PA_ADC
#define SAMSUNG_PA_CFCON S5PV210_PA_CFCON
diff --git a/arch/arm/mach-s5pv210/include/mach/regs-clock.h b/arch/arm/mach-s5pv210/include/mach/regs-clock.h
index ebaabe0..4c45b74 100644
--- a/arch/arm/mach-s5pv210/include/mach/regs-clock.h
+++ b/arch/arm/mach-s5pv210/include/mach/regs-clock.h
@@ -161,7 +161,7 @@
#define S5P_MDNIE_SEL S5P_CLKREG(0x7008)
#define S5P_MIPI_PHY_CON0 S5P_CLKREG(0x7200)
#define S5P_MIPI_PHY_CON1 S5P_CLKREG(0x7204)
-#define S5P_MIPI_CONTROL S5P_CLKREG(0xE814)
+#define S5P_MIPI_DPHY_CONTROL S5P_CLKREG(0xE814)
#define S5P_IDLE_CFG_TL_MASK (3 << 30)
#define S5P_IDLE_CFG_TM_MASK (3 << 28)
@@ -195,9 +195,6 @@
#define S5P_OTHERS_RET_UART (1 << 28)
#define S5P_OTHERS_USB_SIG_MASK (1 << 16)
-/* MIPI */
-#define S5P_MIPI_DPHY_EN (3)
-
/* S5P_DAC_CONTROL */
#define S5P_DAC_ENABLE (1)
#define S5P_DAC_DISABLE (0)
diff --git a/arch/arm/mach-s5pv210/mach-smdkc110.c b/arch/arm/mach-s5pv210/mach-smdkc110.c
index 5dd1681..ce11a02 100644
--- a/arch/arm/mach-s5pv210/mach-smdkc110.c
+++ b/arch/arm/mach-s5pv210/mach-smdkc110.c
@@ -81,6 +81,7 @@ static struct s3c_ide_platdata smdkc110_ide_pdata __initdata = {
};
static struct platform_device *smdkc110_devices[] __initdata = {
+ &samsung_asoc_dma,
&s5pv210_device_iis0,
&s5pv210_device_ac97,
&s5pv210_device_spdif,
@@ -94,6 +95,7 @@ static struct platform_device *smdkc110_devices[] __initdata = {
static struct i2c_board_info smdkc110_i2c_devs0[] __initdata = {
{ I2C_BOARD_INFO("24c08", 0x50), }, /* Samsung S524AD0XD1 */
+ { I2C_BOARD_INFO("wm8580", 0x1b), },
};
static struct i2c_board_info smdkc110_i2c_devs1[] __initdata = {
diff --git a/arch/arm/mach-s5pv210/mach-smdkv210.c b/arch/arm/mach-s5pv210/mach-smdkv210.c
index 1fbc45b..bc9fdb5 100644
--- a/arch/arm/mach-s5pv210/mach-smdkv210.c
+++ b/arch/arm/mach-s5pv210/mach-smdkv210.c
@@ -14,16 +14,25 @@
#include <linux/init.h>
#include <linux/serial_core.h>
#include <linux/sysdev.h>
+#include <linux/dm9000.h>
+#include <linux/fb.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
#include <asm/setup.h>
#include <asm/mach-types.h>
+#include <video/platform_lcd.h>
+
#include <mach/map.h>
#include <mach/regs-clock.h>
+#include <mach/regs-fb.h>
#include <plat/regs-serial.h>
+#include <plat/regs-srom.h>
+#include <plat/gpio-cfg.h>
#include <plat/s5pv210.h>
#include <plat/devs.h>
#include <plat/cpu.h>
@@ -33,6 +42,7 @@
#include <plat/iic.h>
#include <plat/keypad.h>
#include <plat/pm.h>
+#include <plat/fb.h>
/* Following are default values for UCON, ULCON and UFCON UART registers */
#define SMDKV210_UCON_DEFAULT (S3C2410_UCON_TXILEVEL | \
@@ -102,12 +112,106 @@ static struct samsung_keypad_platdata smdkv210_keypad_data __initdata = {
.cols = 8,
};
+static struct resource smdkv210_dm9000_resources[] = {
+ [0] = {
+ .start = S5PV210_PA_SROM_BANK5,
+ .end = S5PV210_PA_SROM_BANK5,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = S5PV210_PA_SROM_BANK5 + 2,
+ .end = S5PV210_PA_SROM_BANK5 + 2,
+ .flags = IORESOURCE_MEM,
+ },
+ [2] = {
+ .start = IRQ_EINT(9),
+ .end = IRQ_EINT(9),
+ .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
+ },
+};
+
+static struct dm9000_plat_data smdkv210_dm9000_platdata = {
+ .flags = DM9000_PLATF_16BITONLY | DM9000_PLATF_NO_EEPROM,
+ .dev_addr = { 0x00, 0x09, 0xc0, 0xff, 0xec, 0x48 },
+};
+
+struct platform_device smdkv210_dm9000 = {
+ .name = "dm9000",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(smdkv210_dm9000_resources),
+ .resource = smdkv210_dm9000_resources,
+ .dev = {
+ .platform_data = &smdkv210_dm9000_platdata,
+ },
+};
+
+static void smdkv210_lte480wv_set_power(struct plat_lcd_data *pd,
+ unsigned int power)
+{
+ if (power) {
+#if !defined(CONFIG_BACKLIGHT_PWM)
+ gpio_request(S5PV210_GPD0(3), "GPD0");
+ gpio_direction_output(S5PV210_GPD0(3), 1);
+ gpio_free(S5PV210_GPD0(3));
+#endif
+
+ /* fire nRESET on power up */
+ gpio_request(S5PV210_GPH0(6), "GPH0");
+
+ gpio_direction_output(S5PV210_GPH0(6), 1);
+
+ gpio_set_value(S5PV210_GPH0(6), 0);
+ mdelay(10);
+
+ gpio_set_value(S5PV210_GPH0(6), 1);
+ mdelay(10);
+
+ gpio_free(S5PV210_GPH0(6));
+ } else {
+#if !defined(CONFIG_BACKLIGHT_PWM)
+ gpio_request(S5PV210_GPD0(3), "GPD0");
+ gpio_direction_output(S5PV210_GPD0(3), 0);
+ gpio_free(S5PV210_GPD0(3));
+#endif
+ }
+}
+
+static struct plat_lcd_data smdkv210_lcd_lte480wv_data = {
+ .set_power = smdkv210_lte480wv_set_power,
+};
+
+static struct platform_device smdkv210_lcd_lte480wv = {
+ .name = "platform-lcd",
+ .dev.parent = &s3c_device_fb.dev,
+ .dev.platform_data = &smdkv210_lcd_lte480wv_data,
+};
+
+static struct s3c_fb_pd_win smdkv210_fb_win0 = {
+ .win_mode = {
+ .left_margin = 13,
+ .right_margin = 8,
+ .upper_margin = 7,
+ .lower_margin = 5,
+ .hsync_len = 3,
+ .vsync_len = 1,
+ .xres = 800,
+ .yres = 480,
+ },
+ .max_bpp = 32,
+ .default_bpp = 24,
+};
+
+static struct s3c_fb_platdata smdkv210_lcd0_pdata __initdata = {
+ .win[0] = &smdkv210_fb_win0,
+ .vidcon0 = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB,
+ .vidcon1 = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC,
+ .setup_gpio = s5pv210_fb_gpio_setup_24bpp,
+};
+
static struct platform_device *smdkv210_devices[] __initdata = {
- &s5pv210_device_iis0,
- &s5pv210_device_ac97,
- &s5pv210_device_spdif,
&s3c_device_adc,
&s3c_device_cfcon,
+ &s3c_device_fb,
&s3c_device_hsmmc0,
&s3c_device_hsmmc1,
&s3c_device_hsmmc2,
@@ -115,14 +219,38 @@ static struct platform_device *smdkv210_devices[] __initdata = {
&s3c_device_i2c0,
&s3c_device_i2c1,
&s3c_device_i2c2,
- &samsung_device_keypad,
&s3c_device_rtc,
&s3c_device_ts,
&s3c_device_wdt,
+ &s5pv210_device_ac97,
+ &s5pv210_device_iis0,
+ &s5pv210_device_spdif,
+ &samsung_asoc_dma,
+ &samsung_device_keypad,
+ &smdkv210_dm9000,
+ &smdkv210_lcd_lte480wv,
};
+static void __init smdkv210_dm9000_init(void)
+{
+ unsigned int tmp;
+
+ gpio_request(S5PV210_MP01(5), "nCS5");
+ s3c_gpio_cfgpin(S5PV210_MP01(5), S3C_GPIO_SFN(2));
+ gpio_free(S5PV210_MP01(5));
+
+ tmp = (5 << S5P_SROM_BCX__TACC__SHIFT);
+ __raw_writel(tmp, S5P_SROM_BC5);
+
+ tmp = __raw_readl(S5P_SROM_BW);
+ tmp &= (S5P_SROM_BW__CS_MASK << S5P_SROM_BW__NCS5__SHIFT);
+ tmp |= (1 << S5P_SROM_BW__NCS5__SHIFT);
+ __raw_writel(tmp, S5P_SROM_BW);
+}
+
static struct i2c_board_info smdkv210_i2c_devs0[] __initdata = {
{ I2C_BOARD_INFO("24c08", 0x50), }, /* Samsung S524AD0XD1 */
+ { I2C_BOARD_INFO("wm8580", 0x1b), },
};
static struct i2c_board_info smdkv210_i2c_devs1[] __initdata = {
@@ -150,6 +278,8 @@ static void __init smdkv210_machine_init(void)
{
s3c_pm_init();
+ smdkv210_dm9000_init();
+
samsung_keypad_set_platdata(&smdkv210_keypad_data);
s3c24xx_ts_set_platdata(&s3c_ts_platform);
@@ -165,6 +295,8 @@ static void __init smdkv210_machine_init(void)
s3c_ide_set_platdata(&smdkv210_ide_pdata);
+ s3c_fb_set_platdata(&smdkv210_lcd0_pdata);
+
platform_add_devices(smdkv210_devices, ARRAY_SIZE(smdkv210_devices));
}
diff --git a/arch/arm/mach-s5pv310/Kconfig b/arch/arm/mach-s5pv310/Kconfig
index d64efe0..09c4c21 100644
--- a/arch/arm/mach-s5pv310/Kconfig
+++ b/arch/arm/mach-s5pv310/Kconfig
@@ -15,6 +15,11 @@ config CPU_S5PV310
help
Enable S5PV310 CPU support
+config S5PV310_DEV_PD
+ bool
+ help
+ Compile in platform device definitions for Power Domain
+
config S5PV310_SETUP_I2C1
bool
help
@@ -61,6 +66,11 @@ config S5PV310_SETUP_SDHCI_GPIO
help
Common setup code for SDHCI gpio.
+config S5PV310_DEV_SYSMMU
+ bool
+ help
+ Common setup code for SYSTEM MMU in S5PV310
+
# machine support
menu "S5PC210 Machines"
@@ -70,11 +80,15 @@ config MACH_SMDKC210
select CPU_S5PV310
select S3C_DEV_RTC
select S3C_DEV_WDT
+ select S3C_DEV_I2C1
select S3C_DEV_HSMMC
select S3C_DEV_HSMMC1
select S3C_DEV_HSMMC2
select S3C_DEV_HSMMC3
+ select S5PV310_DEV_PD
+ select S5PV310_SETUP_I2C1
select S5PV310_SETUP_SDHCI
+ select S5PV310_DEV_SYSMMU
help
Machine support for Samsung SMDKC210
S5PC210(MCP) is one of package option of S5PV310
@@ -83,6 +97,10 @@ config MACH_UNIVERSAL_C210
bool "Mobile UNIVERSAL_C210 Board"
select CPU_S5PV310
select S5P_DEV_ONENAND
+ select S3C_DEV_HSMMC
+ select S3C_DEV_HSMMC2
+ select S3C_DEV_HSMMC3
+ select S5PV310_SETUP_SDHCI
select S3C_DEV_I2C1
select S5PV310_SETUP_I2C1
help
@@ -98,10 +116,13 @@ config MACH_SMDKV310
select CPU_S5PV310
select S3C_DEV_RTC
select S3C_DEV_WDT
+ select S3C_DEV_I2C1
select S3C_DEV_HSMMC
select S3C_DEV_HSMMC1
select S3C_DEV_HSMMC2
select S3C_DEV_HSMMC3
+ select S5PV310_DEV_PD
+ select S5PV310_SETUP_I2C1
select S5PV310_SETUP_SDHCI
help
Machine support for Samsung SMDKV310
diff --git a/arch/arm/mach-s5pv310/Makefile b/arch/arm/mach-s5pv310/Makefile
index 61e3cb6..036fb38 100644
--- a/arch/arm/mach-s5pv310/Makefile
+++ b/arch/arm/mach-s5pv310/Makefile
@@ -14,6 +14,7 @@ obj- :=
obj-$(CONFIG_CPU_S5PV310) += cpu.o init.o clock.o irq-combiner.o
obj-$(CONFIG_CPU_S5PV310) += setup-i2c0.o time.o gpiolib.o irq-eint.o dma.o
+obj-$(CONFIG_CPU_FREQ) += cpufreq.o
obj-$(CONFIG_SMP) += platsmp.o headsmp.o
obj-$(CONFIG_LOCAL_TIMERS) += localtimer.o
@@ -27,7 +28,10 @@ obj-$(CONFIG_MACH_UNIVERSAL_C210) += mach-universal_c210.o
# device support
-obj-y += dev-audio.o
+obj-y += dev-audio.o
+obj-$(CONFIG_S5PV310_DEV_PD) += dev-pd.o
+obj-$(CONFIG_S5PV310_DEV_SYSMMU) += dev-sysmmu.o
+
obj-$(CONFIG_S5PV310_SETUP_I2C1) += setup-i2c1.o
obj-$(CONFIG_S5PV310_SETUP_I2C2) += setup-i2c2.o
obj-$(CONFIG_S5PV310_SETUP_I2C3) += setup-i2c3.o
diff --git a/arch/arm/mach-s5pv310/clock.c b/arch/arm/mach-s5pv310/clock.c
index 58c9d33..fc7c2f8 100644
--- a/arch/arm/mach-s5pv310/clock.c
+++ b/arch/arm/mach-s5pv310/clock.c
@@ -244,7 +244,7 @@ static struct clksrc_clk clk_mout_corebus = {
.id = -1,
},
.sources = &clkset_mout_corebus,
- .reg_src = { .reg = S5P_CLKSRC_CORE, .shift = 4, .size = 1 },
+ .reg_src = { .reg = S5P_CLKSRC_DMC, .shift = 4, .size = 1 },
};
static struct clksrc_clk clk_sclk_dmc = {
@@ -253,7 +253,7 @@ static struct clksrc_clk clk_sclk_dmc = {
.id = -1,
.parent = &clk_mout_corebus.clk,
},
- .reg_div = { .reg = S5P_CLKDIV_CORE0, .shift = 12, .size = 3 },
+ .reg_div = { .reg = S5P_CLKDIV_DMC0, .shift = 12, .size = 3 },
};
static struct clksrc_clk clk_aclk_cored = {
@@ -262,7 +262,7 @@ static struct clksrc_clk clk_aclk_cored = {
.id = -1,
.parent = &clk_sclk_dmc.clk,
},
- .reg_div = { .reg = S5P_CLKDIV_CORE0, .shift = 16, .size = 3 },
+ .reg_div = { .reg = S5P_CLKDIV_DMC0, .shift = 16, .size = 3 },
};
static struct clksrc_clk clk_aclk_corep = {
@@ -271,7 +271,7 @@ static struct clksrc_clk clk_aclk_corep = {
.id = -1,
.parent = &clk_aclk_cored.clk,
},
- .reg_div = { .reg = S5P_CLKDIV_CORE0, .shift = 20, .size = 3 },
+ .reg_div = { .reg = S5P_CLKDIV_DMC0, .shift = 20, .size = 3 },
};
static struct clksrc_clk clk_aclk_acp = {
@@ -280,7 +280,7 @@ static struct clksrc_clk clk_aclk_acp = {
.id = -1,
.parent = &clk_mout_corebus.clk,
},
- .reg_div = { .reg = S5P_CLKDIV_CORE0, .shift = 0, .size = 3 },
+ .reg_div = { .reg = S5P_CLKDIV_DMC0, .shift = 0, .size = 3 },
};
static struct clksrc_clk clk_pclk_acp = {
@@ -289,7 +289,7 @@ static struct clksrc_clk clk_pclk_acp = {
.id = -1,
.parent = &clk_aclk_acp.clk,
},
- .reg_div = { .reg = S5P_CLKDIV_CORE0, .shift = 4, .size = 3 },
+ .reg_div = { .reg = S5P_CLKDIV_DMC0, .shift = 4, .size = 3 },
};
/* Core list of CMU_TOP side */
@@ -384,7 +384,7 @@ static struct clksrc_clk clk_sclk_vpll = {
.reg_src = { .reg = S5P_CLKSRC_TOP0, .shift = 8, .size = 1 },
};
-static struct clk init_clocks_disable[] = {
+static struct clk init_clocks_off[] = {
{
.name = "timers",
.id = -1,
@@ -467,6 +467,16 @@ static struct clk init_clocks_disable[] = {
.enable = s5pv310_clk_ip_fsys_ctrl,
.ctrlbit = (1 << 10),
}, {
+ .name = "pdma",
+ .id = 0,
+ .enable = s5pv310_clk_ip_fsys_ctrl,
+ .ctrlbit = (1 << 0),
+ }, {
+ .name = "pdma",
+ .id = 1,
+ .enable = s5pv310_clk_ip_fsys_ctrl,
+ .ctrlbit = (1 << 1),
+ }, {
.name = "adc",
.id = -1,
.enable = s5pv310_clk_ip_peril_ctrl,
@@ -507,6 +517,26 @@ static struct clk init_clocks_disable[] = {
.enable = s5pv310_clk_ip_peril_ctrl,
.ctrlbit = (1 << 18),
}, {
+ .name = "iis",
+ .id = 0,
+ .enable = s5pv310_clk_ip_peril_ctrl,
+ .ctrlbit = (1 << 19),
+ }, {
+ .name = "iis",
+ .id = 1,
+ .enable = s5pv310_clk_ip_peril_ctrl,
+ .ctrlbit = (1 << 20),
+ }, {
+ .name = "iis",
+ .id = 2,
+ .enable = s5pv310_clk_ip_peril_ctrl,
+ .ctrlbit = (1 << 21),
+ }, {
+ .name = "ac97",
+ .id = -1,
+ .enable = s5pv310_clk_ip_peril_ctrl,
+ .ctrlbit = (1 << 27),
+ }, {
.name = "fimg2d",
.id = -1,
.enable = s5pv310_clk_ip_image_ctrl,
@@ -990,6 +1020,17 @@ static struct clksrc_clk *sysclks[] = {
&clk_dout_mmc4,
};
+static int xtal_rate;
+
+static unsigned long s5pv310_fout_apll_get_rate(struct clk *clk)
+{
+ return s5p_get_pll45xx(xtal_rate, __raw_readl(S5P_APLL_CON0), pll_4508);
+}
+
+static struct clk_ops s5pv310_fout_apll_ops = {
+ .get_rate = s5pv310_fout_apll_get_rate,
+};
+
void __init_or_cpufreq s5pv310_setup_clocks(void)
{
struct clk *xtal_clk;
@@ -1013,6 +1054,9 @@ void __init_or_cpufreq s5pv310_setup_clocks(void)
BUG_ON(IS_ERR(xtal_clk));
xtal = clk_get_rate(xtal_clk);
+
+ xtal_rate = xtal;
+
clk_put(xtal_clk);
printk(KERN_DEBUG "%s: xtal is %ld\n", __func__, xtal);
@@ -1026,7 +1070,7 @@ void __init_or_cpufreq s5pv310_setup_clocks(void)
vpll = s5p_get_pll46xx(vpllsrc, __raw_readl(S5P_VPLL_CON0),
__raw_readl(S5P_VPLL_CON1), pll_4650);
- clk_fout_apll.rate = apll;
+ clk_fout_apll.ops = &s5pv310_fout_apll_ops;
clk_fout_mpll.rate = mpll;
clk_fout_epll.rate = epll;
clk_fout_vpll.rate = vpll;
@@ -1061,13 +1105,9 @@ static struct clk *clks[] __initdata = {
void __init s5pv310_register_clocks(void)
{
- struct clk *clkp;
- int ret;
int ptr;
- ret = s3c24xx_register_clocks(clks, ARRAY_SIZE(clks));
- if (ret > 0)
- printk(KERN_ERR "Failed to register %u clocks\n", ret);
+ s3c24xx_register_clocks(clks, ARRAY_SIZE(clks));
for (ptr = 0; ptr < ARRAY_SIZE(sysclks); ptr++)
s3c_register_clksrc(sysclks[ptr], 1);
@@ -1075,15 +1115,8 @@ void __init s5pv310_register_clocks(void)
s3c_register_clksrc(clksrcs, ARRAY_SIZE(clksrcs));
s3c_register_clocks(init_clocks, ARRAY_SIZE(init_clocks));
- clkp = init_clocks_disable;
- for (ptr = 0; ptr < ARRAY_SIZE(init_clocks_disable); ptr++, clkp++) {
- ret = s3c24xx_register_clock(clkp);
- if (ret < 0) {
- printk(KERN_ERR "Failed to register clock %s (%d)\n",
- clkp->name, ret);
- }
- (clkp->enable)(clkp, 0);
- }
+ s3c_register_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off));
+ s3c_disable_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off));
s3c_pwmclk_init();
}
diff --git a/arch/arm/mach-s5pv310/cpu.c b/arch/arm/mach-s5pv310/cpu.c
index 72ab289..0db0fb6 100644
--- a/arch/arm/mach-s5pv310/cpu.c
+++ b/arch/arm/mach-s5pv310/cpu.c
@@ -41,6 +41,11 @@ static struct map_desc s5pv310_iodesc[] __initdata = {
.length = SZ_128K,
.type = MT_DEVICE,
}, {
+ .virtual = (unsigned long)S5P_VA_PMU,
+ .pfn = __phys_to_pfn(S5PV310_PA_PMU),
+ .length = SZ_64K,
+ .type = MT_DEVICE,
+ }, {
.virtual = (unsigned long)S5P_VA_COMBINER_BASE,
.pfn = __phys_to_pfn(S5PV310_PA_COMBINER),
.length = SZ_4K,
@@ -71,6 +76,11 @@ static struct map_desc s5pv310_iodesc[] __initdata = {
.length = SZ_256,
.type = MT_DEVICE,
}, {
+ .virtual = (unsigned long)S5P_VA_DMC0,
+ .pfn = __phys_to_pfn(S5PV310_PA_DMC0),
+ .length = SZ_4K,
+ .type = MT_DEVICE,
+ }, {
.virtual = (unsigned long)S3C_VA_UART,
.pfn = __phys_to_pfn(S3C_PA_UART),
.length = SZ_512K,
@@ -123,6 +133,15 @@ void __init s5pv310_init_irq(void)
gic_init(0, IRQ_LOCALTIMER, S5P_VA_GIC_DIST, S5P_VA_GIC_CPU);
for (irq = 0; irq < MAX_COMBINER_NR; irq++) {
+
+ /*
+ * From SPI(0) to SPI(39) and SPI(51), SPI(53) are
+ * connected to the interrupt combiner. These irqs
+ * should be initialized to support cascade interrupt.
+ */
+ if ((irq >= 40) && !(irq == 51) && !(irq == 53))
+ continue;
+
combiner_init(irq, (void __iomem *)S5P_VA_COMBINER(irq),
COMBINER_IRQ(irq, 0));
combiner_cascade_irq(irq, IRQ_SPI(irq));
@@ -164,7 +183,7 @@ static int __init s5pv310_l2x0_cache_init(void)
__raw_writel(L2X0_DYNAMIC_CLK_GATING_EN | L2X0_STNDBY_MODE_EN,
S5P_VA_L2CC + L2X0_POWER_CTRL);
- l2x0_init(S5P_VA_L2CC, 0x7C070001, 0xC200ffff);
+ l2x0_init(S5P_VA_L2CC, 0x7C470001, 0xC200ffff);
return 0;
}
diff --git a/arch/arm/mach-s5pv310/cpufreq.c b/arch/arm/mach-s5pv310/cpufreq.c
new file mode 100644
index 0000000..b04cbc7
--- /dev/null
+++ b/arch/arm/mach-s5pv310/cpufreq.c
@@ -0,0 +1,580 @@
+/* linux/arch/arm/mach-s5pv310/cpufreq.c
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * S5PV310 - CPU frequency scaling support
+ *
+ * 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/types.h>
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/regulator/consumer.h>
+#include <linux/cpufreq.h>
+
+#include <mach/map.h>
+#include <mach/regs-clock.h>
+#include <mach/regs-mem.h>
+
+#include <plat/clock.h>
+#include <plat/pm.h>
+
+static struct clk *cpu_clk;
+static struct clk *moutcore;
+static struct clk *mout_mpll;
+static struct clk *mout_apll;
+
+#ifdef CONFIG_REGULATOR
+static struct regulator *arm_regulator;
+static struct regulator *int_regulator;
+#endif
+
+static struct cpufreq_freqs freqs;
+static unsigned int memtype;
+
+enum s5pv310_memory_type {
+ DDR2 = 4,
+ LPDDR2,
+ DDR3,
+};
+
+enum cpufreq_level_index {
+ L0, L1, L2, L3, CPUFREQ_LEVEL_END,
+};
+
+static struct cpufreq_frequency_table s5pv310_freq_table[] = {
+ {L0, 1000*1000},
+ {L1, 800*1000},
+ {L2, 400*1000},
+ {L3, 100*1000},
+ {0, CPUFREQ_TABLE_END},
+};
+
+static unsigned int clkdiv_cpu0[CPUFREQ_LEVEL_END][7] = {
+ /*
+ * Clock divider value for following
+ * { DIVCORE, DIVCOREM0, DIVCOREM1, DIVPERIPH,
+ * DIVATB, DIVPCLK_DBG, DIVAPLL }
+ */
+
+ /* ARM L0: 1000MHz */
+ { 0, 3, 7, 3, 3, 0, 1 },
+
+ /* ARM L1: 800MHz */
+ { 0, 3, 7, 3, 3, 0, 1 },
+
+ /* ARM L2: 400MHz */
+ { 0, 1, 3, 1, 3, 0, 1 },
+
+ /* ARM L3: 100MHz */
+ { 0, 0, 1, 0, 3, 1, 1 },
+};
+
+static unsigned int clkdiv_cpu1[CPUFREQ_LEVEL_END][2] = {
+ /*
+ * Clock divider value for following
+ * { DIVCOPY, DIVHPM }
+ */
+
+ /* ARM L0: 1000MHz */
+ { 3, 0 },
+
+ /* ARM L1: 800MHz */
+ { 3, 0 },
+
+ /* ARM L2: 400MHz */
+ { 3, 0 },
+
+ /* ARM L3: 100MHz */
+ { 3, 0 },
+};
+
+static unsigned int clkdiv_dmc0[CPUFREQ_LEVEL_END][8] = {
+ /*
+ * Clock divider value for following
+ * { DIVACP, DIVACP_PCLK, DIVDPHY, DIVDMC, DIVDMCD
+ * DIVDMCP, DIVCOPY2, DIVCORE_TIMERS }
+ */
+
+ /* DMC L0: 400MHz */
+ { 3, 1, 1, 1, 1, 1, 3, 1 },
+
+ /* DMC L1: 400MHz */
+ { 3, 1, 1, 1, 1, 1, 3, 1 },
+
+ /* DMC L2: 266.7MHz */
+ { 7, 1, 1, 2, 1, 1, 3, 1 },
+
+ /* DMC L3: 200MHz */
+ { 7, 1, 1, 3, 1, 1, 3, 1 },
+};
+
+static unsigned int clkdiv_top[CPUFREQ_LEVEL_END][5] = {
+ /*
+ * Clock divider value for following
+ * { DIVACLK200, DIVACLK100, DIVACLK160, DIVACLK133, DIVONENAND }
+ */
+
+ /* ACLK200 L0: 200MHz */
+ { 3, 7, 4, 5, 1 },
+
+ /* ACLK200 L1: 200MHz */
+ { 3, 7, 4, 5, 1 },
+
+ /* ACLK200 L2: 160MHz */
+ { 4, 7, 5, 7, 1 },
+
+ /* ACLK200 L3: 133.3MHz */
+ { 5, 7, 7, 7, 1 },
+};
+
+static unsigned int clkdiv_lr_bus[CPUFREQ_LEVEL_END][2] = {
+ /*
+ * Clock divider value for following
+ * { DIVGDL/R, DIVGPL/R }
+ */
+
+ /* ACLK_GDL/R L0: 200MHz */
+ { 3, 1 },
+
+ /* ACLK_GDL/R L1: 200MHz */
+ { 3, 1 },
+
+ /* ACLK_GDL/R L2: 160MHz */
+ { 4, 1 },
+
+ /* ACLK_GDL/R L3: 133.3MHz */
+ { 5, 1 },
+};
+
+struct cpufreq_voltage_table {
+ unsigned int index; /* any */
+ unsigned int arm_volt; /* uV */
+ unsigned int int_volt;
+};
+
+static struct cpufreq_voltage_table s5pv310_volt_table[CPUFREQ_LEVEL_END] = {
+ {
+ .index = L0,
+ .arm_volt = 1200000,
+ .int_volt = 1100000,
+ }, {
+ .index = L1,
+ .arm_volt = 1100000,
+ .int_volt = 1100000,
+ }, {
+ .index = L2,
+ .arm_volt = 1000000,
+ .int_volt = 1000000,
+ }, {
+ .index = L3,
+ .arm_volt = 900000,
+ .int_volt = 1000000,
+ },
+};
+
+static unsigned int s5pv310_apll_pms_table[CPUFREQ_LEVEL_END] = {
+ /* APLL FOUT L0: 1000MHz */
+ ((250 << 16) | (6 << 8) | 1),
+
+ /* APLL FOUT L1: 800MHz */
+ ((200 << 16) | (6 << 8) | 1),
+
+ /* APLL FOUT L2 : 400MHz */
+ ((200 << 16) | (6 << 8) | 2),
+
+ /* APLL FOUT L3: 100MHz */
+ ((200 << 16) | (6 << 8) | 4),
+};
+
+int s5pv310_verify_speed(struct cpufreq_policy *policy)
+{
+ return cpufreq_frequency_table_verify(policy, s5pv310_freq_table);
+}
+
+unsigned int s5pv310_getspeed(unsigned int cpu)
+{
+ return clk_get_rate(cpu_clk) / 1000;
+}
+
+void s5pv310_set_clkdiv(unsigned int div_index)
+{
+ unsigned int tmp;
+
+ /* Change Divider - CPU0 */
+
+ tmp = __raw_readl(S5P_CLKDIV_CPU);
+
+ tmp &= ~(S5P_CLKDIV_CPU0_CORE_MASK | S5P_CLKDIV_CPU0_COREM0_MASK |
+ S5P_CLKDIV_CPU0_COREM1_MASK | S5P_CLKDIV_CPU0_PERIPH_MASK |
+ S5P_CLKDIV_CPU0_ATB_MASK | S5P_CLKDIV_CPU0_PCLKDBG_MASK |
+ S5P_CLKDIV_CPU0_APLL_MASK);
+
+ tmp |= ((clkdiv_cpu0[div_index][0] << S5P_CLKDIV_CPU0_CORE_SHIFT) |
+ (clkdiv_cpu0[div_index][1] << S5P_CLKDIV_CPU0_COREM0_SHIFT) |
+ (clkdiv_cpu0[div_index][2] << S5P_CLKDIV_CPU0_COREM1_SHIFT) |
+ (clkdiv_cpu0[div_index][3] << S5P_CLKDIV_CPU0_PERIPH_SHIFT) |
+ (clkdiv_cpu0[div_index][4] << S5P_CLKDIV_CPU0_ATB_SHIFT) |
+ (clkdiv_cpu0[div_index][5] << S5P_CLKDIV_CPU0_PCLKDBG_SHIFT) |
+ (clkdiv_cpu0[div_index][6] << S5P_CLKDIV_CPU0_APLL_SHIFT));
+
+ __raw_writel(tmp, S5P_CLKDIV_CPU);
+
+ do {
+ tmp = __raw_readl(S5P_CLKDIV_STATCPU);
+ } while (tmp & 0x1111111);
+
+ /* Change Divider - CPU1 */
+
+ tmp = __raw_readl(S5P_CLKDIV_CPU1);
+
+ tmp &= ~((0x7 << 4) | 0x7);
+
+ tmp |= ((clkdiv_cpu1[div_index][0] << 4) |
+ (clkdiv_cpu1[div_index][1] << 0));
+
+ __raw_writel(tmp, S5P_CLKDIV_CPU1);
+
+ do {
+ tmp = __raw_readl(S5P_CLKDIV_STATCPU1);
+ } while (tmp & 0x11);
+
+ /* Change Divider - DMC0 */
+
+ tmp = __raw_readl(S5P_CLKDIV_DMC0);
+
+ tmp &= ~(S5P_CLKDIV_DMC0_ACP_MASK | S5P_CLKDIV_DMC0_ACPPCLK_MASK |
+ S5P_CLKDIV_DMC0_DPHY_MASK | S5P_CLKDIV_DMC0_DMC_MASK |
+ S5P_CLKDIV_DMC0_DMCD_MASK | S5P_CLKDIV_DMC0_DMCP_MASK |
+ S5P_CLKDIV_DMC0_COPY2_MASK | S5P_CLKDIV_DMC0_CORETI_MASK);
+
+ tmp |= ((clkdiv_dmc0[div_index][0] << S5P_CLKDIV_DMC0_ACP_SHIFT) |
+ (clkdiv_dmc0[div_index][1] << S5P_CLKDIV_DMC0_ACPPCLK_SHIFT) |
+ (clkdiv_dmc0[div_index][2] << S5P_CLKDIV_DMC0_DPHY_SHIFT) |
+ (clkdiv_dmc0[div_index][3] << S5P_CLKDIV_DMC0_DMC_SHIFT) |
+ (clkdiv_dmc0[div_index][4] << S5P_CLKDIV_DMC0_DMCD_SHIFT) |
+ (clkdiv_dmc0[div_index][5] << S5P_CLKDIV_DMC0_DMCP_SHIFT) |
+ (clkdiv_dmc0[div_index][6] << S5P_CLKDIV_DMC0_COPY2_SHIFT) |
+ (clkdiv_dmc0[div_index][7] << S5P_CLKDIV_DMC0_CORETI_SHIFT));
+
+ __raw_writel(tmp, S5P_CLKDIV_DMC0);
+
+ do {
+ tmp = __raw_readl(S5P_CLKDIV_STAT_DMC0);
+ } while (tmp & 0x11111111);
+
+ /* Change Divider - TOP */
+
+ tmp = __raw_readl(S5P_CLKDIV_TOP);
+
+ tmp &= ~(S5P_CLKDIV_TOP_ACLK200_MASK | S5P_CLKDIV_TOP_ACLK100_MASK |
+ S5P_CLKDIV_TOP_ACLK160_MASK | S5P_CLKDIV_TOP_ACLK133_MASK |
+ S5P_CLKDIV_TOP_ONENAND_MASK);
+
+ tmp |= ((clkdiv_top[div_index][0] << S5P_CLKDIV_TOP_ACLK200_SHIFT) |
+ (clkdiv_top[div_index][1] << S5P_CLKDIV_TOP_ACLK100_SHIFT) |
+ (clkdiv_top[div_index][2] << S5P_CLKDIV_TOP_ACLK160_SHIFT) |
+ (clkdiv_top[div_index][3] << S5P_CLKDIV_TOP_ACLK133_SHIFT) |
+ (clkdiv_top[div_index][4] << S5P_CLKDIV_TOP_ONENAND_SHIFT));
+
+ __raw_writel(tmp, S5P_CLKDIV_TOP);
+
+ do {
+ tmp = __raw_readl(S5P_CLKDIV_STAT_TOP);
+ } while (tmp & 0x11111);
+
+ /* Change Divider - LEFTBUS */
+
+ tmp = __raw_readl(S5P_CLKDIV_LEFTBUS);
+
+ tmp &= ~(S5P_CLKDIV_BUS_GDLR_MASK | S5P_CLKDIV_BUS_GPLR_MASK);
+
+ tmp |= ((clkdiv_lr_bus[div_index][0] << S5P_CLKDIV_BUS_GDLR_SHIFT) |
+ (clkdiv_lr_bus[div_index][1] << S5P_CLKDIV_BUS_GPLR_SHIFT));
+
+ __raw_writel(tmp, S5P_CLKDIV_LEFTBUS);
+
+ do {
+ tmp = __raw_readl(S5P_CLKDIV_STAT_LEFTBUS);
+ } while (tmp & 0x11);
+
+ /* Change Divider - RIGHTBUS */
+
+ tmp = __raw_readl(S5P_CLKDIV_RIGHTBUS);
+
+ tmp &= ~(S5P_CLKDIV_BUS_GDLR_MASK | S5P_CLKDIV_BUS_GPLR_MASK);
+
+ tmp |= ((clkdiv_lr_bus[div_index][0] << S5P_CLKDIV_BUS_GDLR_SHIFT) |
+ (clkdiv_lr_bus[div_index][1] << S5P_CLKDIV_BUS_GPLR_SHIFT));
+
+ __raw_writel(tmp, S5P_CLKDIV_RIGHTBUS);
+
+ do {
+ tmp = __raw_readl(S5P_CLKDIV_STAT_RIGHTBUS);
+ } while (tmp & 0x11);
+}
+
+static void s5pv310_set_apll(unsigned int index)
+{
+ unsigned int tmp;
+
+ /* 1. MUX_CORE_SEL = MPLL, ARMCLK uses MPLL for lock time */
+ clk_set_parent(moutcore, mout_mpll);
+
+ do {
+ tmp = (__raw_readl(S5P_CLKMUX_STATCPU)
+ >> S5P_CLKSRC_CPU_MUXCORE_SHIFT);
+ tmp &= 0x7;
+ } while (tmp != 0x2);
+
+ /* 2. Set APLL Lock time */
+ __raw_writel(S5P_APLL_LOCKTIME, S5P_APLL_LOCK);
+
+ /* 3. Change PLL PMS values */
+ tmp = __raw_readl(S5P_APLL_CON0);
+ tmp &= ~((0x3ff << 16) | (0x3f << 8) | (0x7 << 0));
+ tmp |= s5pv310_apll_pms_table[index];
+ __raw_writel(tmp, S5P_APLL_CON0);
+
+ /* 4. wait_lock_time */
+ do {
+ tmp = __raw_readl(S5P_APLL_CON0);
+ } while (!(tmp & (0x1 << S5P_APLLCON0_LOCKED_SHIFT)));
+
+ /* 5. MUX_CORE_SEL = APLL */
+ clk_set_parent(moutcore, mout_apll);
+
+ do {
+ tmp = __raw_readl(S5P_CLKMUX_STATCPU);
+ tmp &= S5P_CLKMUX_STATCPU_MUXCORE_MASK;
+ } while (tmp != (0x1 << S5P_CLKSRC_CPU_MUXCORE_SHIFT));
+}
+
+static void s5pv310_set_frequency(unsigned int old_index, unsigned int new_index)
+{
+ unsigned int tmp;
+
+ if (old_index > new_index) {
+ /* The frequency changing to L0 needs to change apll */
+ if (freqs.new == s5pv310_freq_table[L0].frequency) {
+ /* 1. Change the system clock divider values */
+ s5pv310_set_clkdiv(new_index);
+
+ /* 2. Change the apll m,p,s value */
+ s5pv310_set_apll(new_index);
+ } else {
+ /* 1. Change the system clock divider values */
+ s5pv310_set_clkdiv(new_index);
+
+ /* 2. Change just s value in apll m,p,s value */
+ tmp = __raw_readl(S5P_APLL_CON0);
+ tmp &= ~(0x7 << 0);
+ tmp |= (s5pv310_apll_pms_table[new_index] & 0x7);
+ __raw_writel(tmp, S5P_APLL_CON0);
+ }
+ }
+
+ else if (old_index < new_index) {
+ /* The frequency changing from L0 needs to change apll */
+ if (freqs.old == s5pv310_freq_table[L0].frequency) {
+ /* 1. Change the apll m,p,s value */
+ s5pv310_set_apll(new_index);
+
+ /* 2. Change the system clock divider values */
+ s5pv310_set_clkdiv(new_index);
+ } else {
+ /* 1. Change just s value in apll m,p,s value */
+ tmp = __raw_readl(S5P_APLL_CON0);
+ tmp &= ~(0x7 << 0);
+ tmp |= (s5pv310_apll_pms_table[new_index] & 0x7);
+ __raw_writel(tmp, S5P_APLL_CON0);
+
+ /* 2. Change the system clock divider values */
+ s5pv310_set_clkdiv(new_index);
+ }
+ }
+}
+
+static int s5pv310_target(struct cpufreq_policy *policy,
+ unsigned int target_freq,
+ unsigned int relation)
+{
+ unsigned int index, old_index;
+ unsigned int arm_volt, int_volt;
+
+ freqs.old = s5pv310_getspeed(policy->cpu);
+
+ if (cpufreq_frequency_table_target(policy, s5pv310_freq_table,
+ freqs.old, relation, &old_index))
+ return -EINVAL;
+
+ if (cpufreq_frequency_table_target(policy, s5pv310_freq_table,
+ target_freq, relation, &index))
+ return -EINVAL;
+
+ freqs.new = s5pv310_freq_table[index].frequency;
+ freqs.cpu = policy->cpu;
+
+ if (freqs.new == freqs.old)
+ return 0;
+
+ /* get the voltage value */
+ arm_volt = s5pv310_volt_table[index].arm_volt;
+ int_volt = s5pv310_volt_table[index].int_volt;
+
+ cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+
+ /* control regulator */
+ if (freqs.new > freqs.old) {
+ /* Voltage up */
+#ifdef CONFIG_REGULATOR
+ regulator_set_voltage(arm_regulator, arm_volt, arm_volt);
+ regulator_set_voltage(int_regulator, int_volt, int_volt);
+#endif
+ }
+
+ /* Clock Configuration Procedure */
+ s5pv310_set_frequency(old_index, index);
+
+ /* control regulator */
+ if (freqs.new < freqs.old) {
+ /* Voltage down */
+#ifdef CONFIG_REGULATOR
+ regulator_set_voltage(arm_regulator, arm_volt, arm_volt);
+ regulator_set_voltage(int_regulator, int_volt, int_volt);
+#endif
+ }
+
+ cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int s5pv310_cpufreq_suspend(struct cpufreq_policy *policy,
+ pm_message_t pmsg)
+{
+ return 0;
+}
+
+static int s5pv310_cpufreq_resume(struct cpufreq_policy *policy)
+{
+ return 0;
+}
+#endif
+
+static int s5pv310_cpufreq_cpu_init(struct cpufreq_policy *policy)
+{
+ policy->cur = policy->min = policy->max = s5pv310_getspeed(policy->cpu);
+
+ cpufreq_frequency_table_get_attr(s5pv310_freq_table, policy->cpu);
+
+ /* set the transition latency value */
+ policy->cpuinfo.transition_latency = 100000;
+
+ /*
+ * S5PV310 multi-core processors has 2 cores
+ * that the frequency cannot be set independently.
+ * Each cpu is bound to the same speed.
+ * So the affected cpu is all of the cpus.
+ */
+ cpumask_setall(policy->cpus);
+
+ return cpufreq_frequency_table_cpuinfo(policy, s5pv310_freq_table);
+}
+
+static struct cpufreq_driver s5pv310_driver = {
+ .flags = CPUFREQ_STICKY,
+ .verify = s5pv310_verify_speed,
+ .target = s5pv310_target,
+ .get = s5pv310_getspeed,
+ .init = s5pv310_cpufreq_cpu_init,
+ .name = "s5pv310_cpufreq",
+#ifdef CONFIG_PM
+ .suspend = s5pv310_cpufreq_suspend,
+ .resume = s5pv310_cpufreq_resume,
+#endif
+};
+
+static int __init s5pv310_cpufreq_init(void)
+{
+ cpu_clk = clk_get(NULL, "armclk");
+ if (IS_ERR(cpu_clk))
+ return PTR_ERR(cpu_clk);
+
+ moutcore = clk_get(NULL, "moutcore");
+ if (IS_ERR(moutcore))
+ goto out;
+
+ mout_mpll = clk_get(NULL, "mout_mpll");
+ if (IS_ERR(mout_mpll))
+ goto out;
+
+ mout_apll = clk_get(NULL, "mout_apll");
+ if (IS_ERR(mout_apll))
+ goto out;
+
+#ifdef CONFIG_REGULATOR
+ arm_regulator = regulator_get(NULL, "vdd_arm");
+ if (IS_ERR(arm_regulator)) {
+ printk(KERN_ERR "failed to get resource %s\n", "vdd_arm");
+ goto out;
+ }
+
+ int_regulator = regulator_get(NULL, "vdd_int");
+ if (IS_ERR(int_regulator)) {
+ printk(KERN_ERR "failed to get resource %s\n", "vdd_int");
+ goto out;
+ }
+#endif
+
+ /*
+ * Check DRAM type.
+ * Because DVFS level is different according to DRAM type.
+ */
+ memtype = __raw_readl(S5P_VA_DMC0 + S5P_DMC0_MEMCON_OFFSET);
+ memtype = (memtype >> S5P_DMC0_MEMTYPE_SHIFT);
+ memtype &= S5P_DMC0_MEMTYPE_MASK;
+
+ if ((memtype < DDR2) && (memtype > DDR3)) {
+ printk(KERN_ERR "%s: wrong memtype= 0x%x\n", __func__, memtype);
+ goto out;
+ } else {
+ printk(KERN_DEBUG "%s: memtype= 0x%x\n", __func__, memtype);
+ }
+
+ return cpufreq_register_driver(&s5pv310_driver);
+
+out:
+ if (!IS_ERR(cpu_clk))
+ clk_put(cpu_clk);
+
+ if (!IS_ERR(moutcore))
+ clk_put(moutcore);
+
+ if (!IS_ERR(mout_mpll))
+ clk_put(mout_mpll);
+
+ if (!IS_ERR(mout_apll))
+ clk_put(mout_apll);
+
+#ifdef CONFIG_REGULATOR
+ if (!IS_ERR(arm_regulator))
+ regulator_put(arm_regulator);
+
+ if (!IS_ERR(int_regulator))
+ regulator_put(int_regulator);
+#endif
+
+ printk(KERN_ERR "%s: failed initialization\n", __func__);
+
+ return -EINVAL;
+}
+late_initcall(s5pv310_cpufreq_init);
diff --git a/arch/arm/mach-s5pv310/dev-pd.c b/arch/arm/mach-s5pv310/dev-pd.c
new file mode 100644
index 0000000..58a50c2
--- /dev/null
+++ b/arch/arm/mach-s5pv310/dev-pd.c
@@ -0,0 +1,139 @@
+/* linux/arch/arm/mach-s5pv310/dev-pd.c
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * S5PV310 - Power Domain support
+ *
+ * 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/io.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+
+#include <mach/regs-pmu.h>
+
+#include <plat/pd.h>
+
+static int s5pv310_pd_enable(struct device *dev)
+{
+ struct samsung_pd_info *pdata = dev->platform_data;
+ u32 timeout;
+
+ __raw_writel(S5P_INT_LOCAL_PWR_EN, pdata->base);
+
+ /* Wait max 1ms */
+ timeout = 10;
+ while ((__raw_readl(pdata->base + 0x4) & S5P_INT_LOCAL_PWR_EN)
+ != S5P_INT_LOCAL_PWR_EN) {
+ if (timeout == 0) {
+ printk(KERN_ERR "Power domain %s enable failed.\n",
+ dev_name(dev));
+ return -ETIMEDOUT;
+ }
+ timeout--;
+ udelay(100);
+ }
+
+ return 0;
+}
+
+static int s5pv310_pd_disable(struct device *dev)
+{
+ struct samsung_pd_info *pdata = dev->platform_data;
+ u32 timeout;
+
+ __raw_writel(0, pdata->base);
+
+ /* Wait max 1ms */
+ timeout = 10;
+ while (__raw_readl(pdata->base + 0x4) & S5P_INT_LOCAL_PWR_EN) {
+ if (timeout == 0) {
+ printk(KERN_ERR "Power domain %s disable failed.\n",
+ dev_name(dev));
+ return -ETIMEDOUT;
+ }
+ timeout--;
+ udelay(100);
+ }
+
+ return 0;
+}
+
+struct platform_device s5pv310_device_pd[] = {
+ {
+ .name = "samsung-pd",
+ .id = 0,
+ .dev = {
+ .platform_data = &(struct samsung_pd_info) {
+ .enable = s5pv310_pd_enable,
+ .disable = s5pv310_pd_disable,
+ .base = S5P_PMU_MFC_CONF,
+ },
+ },
+ }, {
+ .name = "samsung-pd",
+ .id = 1,
+ .dev = {
+ .platform_data = &(struct samsung_pd_info) {
+ .enable = s5pv310_pd_enable,
+ .disable = s5pv310_pd_disable,
+ .base = S5P_PMU_G3D_CONF,
+ },
+ },
+ }, {
+ .name = "samsung-pd",
+ .id = 2,
+ .dev = {
+ .platform_data = &(struct samsung_pd_info) {
+ .enable = s5pv310_pd_enable,
+ .disable = s5pv310_pd_disable,
+ .base = S5P_PMU_LCD0_CONF,
+ },
+ },
+ }, {
+ .name = "samsung-pd",
+ .id = 3,
+ .dev = {
+ .platform_data = &(struct samsung_pd_info) {
+ .enable = s5pv310_pd_enable,
+ .disable = s5pv310_pd_disable,
+ .base = S5P_PMU_LCD1_CONF,
+ },
+ },
+ }, {
+ .name = "samsung-pd",
+ .id = 4,
+ .dev = {
+ .platform_data = &(struct samsung_pd_info) {
+ .enable = s5pv310_pd_enable,
+ .disable = s5pv310_pd_disable,
+ .base = S5P_PMU_TV_CONF,
+ },
+ },
+ }, {
+ .name = "samsung-pd",
+ .id = 5,
+ .dev = {
+ .platform_data = &(struct samsung_pd_info) {
+ .enable = s5pv310_pd_enable,
+ .disable = s5pv310_pd_disable,
+ .base = S5P_PMU_CAM_CONF,
+ },
+ },
+ }, {
+ .name = "samsung-pd",
+ .id = 6,
+ .dev = {
+ .platform_data = &(struct samsung_pd_info) {
+ .enable = s5pv310_pd_enable,
+ .disable = s5pv310_pd_disable,
+ .base = S5P_PMU_GPS_CONF,
+ },
+ },
+ },
+};
diff --git a/arch/arm/mach-s5pv310/dev-sysmmu.c b/arch/arm/mach-s5pv310/dev-sysmmu.c
new file mode 100644
index 0000000..e1bb200
--- /dev/null
+++ b/arch/arm/mach-s5pv310/dev-sysmmu.c
@@ -0,0 +1,187 @@
+/* linux/arch/arm/mach-s5pv310/dev-sysmmu.c
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ * http://www.samsung.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/platform_device.h>
+#include <linux/dma-mapping.h>
+
+#include <mach/map.h>
+#include <mach/irqs.h>
+
+static struct resource s5pv310_sysmmu_resource[] = {
+ [0] = {
+ .start = S5PV310_PA_SYSMMU_MDMA,
+ .end = S5PV310_PA_SYSMMU_MDMA + SZ_64K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = IRQ_SYSMMU_MDMA0_0,
+ .end = IRQ_SYSMMU_MDMA0_0,
+ .flags = IORESOURCE_IRQ,
+ },
+ [2] = {
+ .start = S5PV310_PA_SYSMMU_SSS,
+ .end = S5PV310_PA_SYSMMU_SSS + SZ_64K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [3] = {
+ .start = IRQ_SYSMMU_SSS_0,
+ .end = IRQ_SYSMMU_SSS_0,
+ .flags = IORESOURCE_IRQ,
+ },
+ [4] = {
+ .start = S5PV310_PA_SYSMMU_FIMC0,
+ .end = S5PV310_PA_SYSMMU_FIMC0 + SZ_64K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [5] = {
+ .start = IRQ_SYSMMU_FIMC0_0,
+ .end = IRQ_SYSMMU_FIMC0_0,
+ .flags = IORESOURCE_IRQ,
+ },
+ [6] = {
+ .start = S5PV310_PA_SYSMMU_FIMC1,
+ .end = S5PV310_PA_SYSMMU_FIMC1 + SZ_64K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [7] = {
+ .start = IRQ_SYSMMU_FIMC1_0,
+ .end = IRQ_SYSMMU_FIMC1_0,
+ .flags = IORESOURCE_IRQ,
+ },
+ [8] = {
+ .start = S5PV310_PA_SYSMMU_FIMC2,
+ .end = S5PV310_PA_SYSMMU_FIMC2 + SZ_64K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [9] = {
+ .start = IRQ_SYSMMU_FIMC2_0,
+ .end = IRQ_SYSMMU_FIMC2_0,
+ .flags = IORESOURCE_IRQ,
+ },
+ [10] = {
+ .start = S5PV310_PA_SYSMMU_FIMC3,
+ .end = S5PV310_PA_SYSMMU_FIMC3 + SZ_64K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [11] = {
+ .start = IRQ_SYSMMU_FIMC3_0,
+ .end = IRQ_SYSMMU_FIMC3_0,
+ .flags = IORESOURCE_IRQ,
+ },
+ [12] = {
+ .start = S5PV310_PA_SYSMMU_JPEG,
+ .end = S5PV310_PA_SYSMMU_JPEG + SZ_64K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [13] = {
+ .start = IRQ_SYSMMU_JPEG_0,
+ .end = IRQ_SYSMMU_JPEG_0,
+ .flags = IORESOURCE_IRQ,
+ },
+ [14] = {
+ .start = S5PV310_PA_SYSMMU_FIMD0,
+ .end = S5PV310_PA_SYSMMU_FIMD0 + SZ_64K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [15] = {
+ .start = IRQ_SYSMMU_LCD0_M0_0,
+ .end = IRQ_SYSMMU_LCD0_M0_0,
+ .flags = IORESOURCE_IRQ,
+ },
+ [16] = {
+ .start = S5PV310_PA_SYSMMU_FIMD1,
+ .end = S5PV310_PA_SYSMMU_FIMD1 + SZ_64K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [17] = {
+ .start = IRQ_SYSMMU_LCD1_M1_0,
+ .end = IRQ_SYSMMU_LCD1_M1_0,
+ .flags = IORESOURCE_IRQ,
+ },
+ [18] = {
+ .start = S5PV310_PA_SYSMMU_PCIe,
+ .end = S5PV310_PA_SYSMMU_PCIe + SZ_64K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [19] = {
+ .start = IRQ_SYSMMU_PCIE_0,
+ .end = IRQ_SYSMMU_PCIE_0,
+ .flags = IORESOURCE_IRQ,
+ },
+ [20] = {
+ .start = S5PV310_PA_SYSMMU_G2D,
+ .end = S5PV310_PA_SYSMMU_G2D + SZ_64K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [21] = {
+ .start = IRQ_SYSMMU_2D_0,
+ .end = IRQ_SYSMMU_2D_0,
+ .flags = IORESOURCE_IRQ,
+ },
+ [22] = {
+ .start = S5PV310_PA_SYSMMU_ROTATOR,
+ .end = S5PV310_PA_SYSMMU_ROTATOR + SZ_64K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [23] = {
+ .start = IRQ_SYSMMU_ROTATOR_0,
+ .end = IRQ_SYSMMU_ROTATOR_0,
+ .flags = IORESOURCE_IRQ,
+ },
+ [24] = {
+ .start = S5PV310_PA_SYSMMU_MDMA2,
+ .end = S5PV310_PA_SYSMMU_MDMA2 + SZ_64K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [25] = {
+ .start = IRQ_SYSMMU_MDMA1_0,
+ .end = IRQ_SYSMMU_MDMA1_0,
+ .flags = IORESOURCE_IRQ,
+ },
+ [26] = {
+ .start = S5PV310_PA_SYSMMU_TV,
+ .end = S5PV310_PA_SYSMMU_TV + SZ_64K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [27] = {
+ .start = IRQ_SYSMMU_TV_M0_0,
+ .end = IRQ_SYSMMU_TV_M0_0,
+ .flags = IORESOURCE_IRQ,
+ },
+ [28] = {
+ .start = S5PV310_PA_SYSMMU_MFC_L,
+ .end = S5PV310_PA_SYSMMU_MFC_L + SZ_64K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [29] = {
+ .start = IRQ_SYSMMU_MFC_M0_0,
+ .end = IRQ_SYSMMU_MFC_M0_0,
+ .flags = IORESOURCE_IRQ,
+ },
+ [30] = {
+ .start = S5PV310_PA_SYSMMU_MFC_R,
+ .end = S5PV310_PA_SYSMMU_MFC_R + SZ_64K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [31] = {
+ .start = IRQ_SYSMMU_MFC_M1_0,
+ .end = IRQ_SYSMMU_MFC_M1_0,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+struct platform_device s5pv310_device_sysmmu = {
+ .name = "s5p-sysmmu",
+ .id = 32,
+ .num_resources = ARRAY_SIZE(s5pv310_sysmmu_resource),
+ .resource = s5pv310_sysmmu_resource,
+};
+
+EXPORT_SYMBOL(s5pv310_device_sysmmu);
diff --git a/arch/arm/mach-s5pv310/hotplug.c b/arch/arm/mach-s5pv310/hotplug.c
index afa5392..c24235c 100644
--- a/arch/arm/mach-s5pv310/hotplug.c
+++ b/arch/arm/mach-s5pv310/hotplug.c
@@ -30,10 +30,10 @@ static inline void cpu_enter_lowpower(void)
* Turn off coherency
*/
" mrc p15, 0, %0, c1, c0, 1\n"
- " bic %0, %0, %2\n"
+ " bic %0, %0, #0x20\n"
" mcr p15, 0, %0, c1, c0, 1\n"
" mrc p15, 0, %0, c1, c0, 0\n"
- " bic %0, %0, #0x04\n"
+ " bic %0, %0, %2\n"
" mcr p15, 0, %0, c1, c0, 0\n"
: "=&r" (v)
: "r" (0), "Ir" (CR_C)
diff --git a/arch/arm/mach-s5pv310/include/mach/irqs.h b/arch/arm/mach-s5pv310/include/mach/irqs.h
index 3c05c58..536b0b5 100644
--- a/arch/arm/mach-s5pv310/include/mach/irqs.h
+++ b/arch/arm/mach-s5pv310/include/mach/irqs.h
@@ -25,6 +25,8 @@
#define IRQ_SPI(x) S5P_IRQ(x+32)
+#define IRQ_MCT1 IRQ_SPI(35)
+
#define IRQ_EINT0 IRQ_SPI(40)
#define IRQ_EINT1 IRQ_SPI(41)
#define IRQ_EINT2 IRQ_SPI(42)
@@ -36,9 +38,8 @@
#define IRQ_JPEG IRQ_SPI(48)
#define IRQ_2D IRQ_SPI(49)
#define IRQ_PCIE IRQ_SPI(50)
-#define IRQ_SYSTEM_TIMER IRQ_SPI(51)
+#define IRQ_MCT0 IRQ_SPI(51)
#define IRQ_MFC IRQ_SPI(52)
-#define IRQ_WDT IRQ_SPI(53)
#define IRQ_AUDIO_SS IRQ_SPI(54)
#define IRQ_AC97 IRQ_SPI(55)
#define IRQ_SPDIF IRQ_SPI(56)
@@ -54,6 +55,24 @@
#define COMBINER_GROUP(x) ((x) * MAX_IRQ_IN_COMBINER + IRQ_SPI(64))
#define COMBINER_IRQ(x, y) (COMBINER_GROUP(x) + y)
+#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)
+#define IRQ_SYSMMU_FIMC1_0 COMBINER_IRQ(4, 3)
+#define IRQ_SYSMMU_FIMC2_0 COMBINER_IRQ(4, 4)
+#define IRQ_SYSMMU_FIMC3_0 COMBINER_IRQ(4, 5)
+#define IRQ_SYSMMU_JPEG_0 COMBINER_IRQ(4, 6)
+#define IRQ_SYSMMU_2D_0 COMBINER_IRQ(4, 7)
+
+#define IRQ_SYSMMU_ROTATOR_0 COMBINER_IRQ(5, 0)
+#define IRQ_SYSMMU_MDMA1_0 COMBINER_IRQ(5, 1)
+#define IRQ_SYSMMU_LCD0_M0_0 COMBINER_IRQ(5, 2)
+#define IRQ_SYSMMU_LCD1_M1_0 COMBINER_IRQ(5, 3)
+#define IRQ_SYSMMU_TV_M0_0 COMBINER_IRQ(5, 4)
+#define IRQ_SYSMMU_MFC_M0_0 COMBINER_IRQ(5, 5)
+#define IRQ_SYSMMU_MFC_M1_0 COMBINER_IRQ(5, 6)
+#define IRQ_SYSMMU_PCIE_0 COMBINER_IRQ(5, 7)
+
#define IRQ_PDMA0 COMBINER_IRQ(21, 0)
#define IRQ_PDMA1 COMBINER_IRQ(21, 1)
@@ -86,8 +105,13 @@
#define IRQ_HSMMC2 COMBINER_IRQ(29, 2)
#define IRQ_HSMMC3 COMBINER_IRQ(29, 3)
+#define IRQ_MIPI_CSIS0 COMBINER_IRQ(30, 0)
+#define IRQ_MIPI_CSIS1 COMBINER_IRQ(30, 1)
+
#define IRQ_ONENAND_AUDI COMBINER_IRQ(34, 0)
+#define IRQ_MCT_L1 COMBINER_IRQ(35, 3)
+
#define IRQ_EINT4 COMBINER_IRQ(37, 0)
#define IRQ_EINT5 COMBINER_IRQ(37, 1)
#define IRQ_EINT6 COMBINER_IRQ(37, 2)
@@ -104,7 +128,11 @@
#define IRQ_EINT16_31 COMBINER_IRQ(39, 0)
-#define MAX_COMBINER_NR 40
+#define IRQ_MCT_L0 COMBINER_IRQ(51, 0)
+
+#define IRQ_WDT COMBINER_IRQ(53, 0)
+
+#define MAX_COMBINER_NR 54
#define S5P_IRQ_EINT_BASE COMBINER_IRQ(MAX_COMBINER_NR, 0)
diff --git a/arch/arm/mach-s5pv310/include/mach/map.h b/arch/arm/mach-s5pv310/include/mach/map.h
index 5399446..74d4006 100644
--- a/arch/arm/mach-s5pv310/include/mach/map.h
+++ b/arch/arm/mach-s5pv310/include/mach/map.h
@@ -39,11 +39,15 @@
#define S5PV310_PA_SYSCON (0x10010000)
#define S5P_PA_SYSCON S5PV310_PA_SYSCON
+#define S5PV310_PA_PMU (0x10020000)
+
#define S5PV310_PA_CMU (0x10030000)
#define S5PV310_PA_WATCHDOG (0x10060000)
#define S5PV310_PA_RTC (0x10070000)
+#define S5PV310_PA_DMC0 (0x10400000)
+
#define S5PV310_PA_COMBINER (0x10448000)
#define S5PV310_PA_COREPERI (0x10500000)
@@ -61,9 +65,13 @@
#define S5PV310_PA_GPIO2 (0x11000000)
#define S5PV310_PA_GPIO3 (0x03860000)
+#define S5PV310_PA_MIPI_CSIS0 0x11880000
+#define S5PV310_PA_MIPI_CSIS1 0x11890000
+
#define S5PV310_PA_HSMMC(x) (0x12510000 + ((x) * 0x10000))
#define S5PV310_PA_SROMC (0x12570000)
+#define S5P_PA_SROMC S5PV310_PA_SROMC
/* S/PDIF */
#define S5PV310_PA_SPDIF 0xE1100000
@@ -100,6 +108,25 @@
#define S5PV310_PA_SDRAM (0x40000000)
#define S5P_PA_SDRAM S5PV310_PA_SDRAM
+#define S5PV310_PA_SYSMMU_MDMA 0x10A40000
+#define S5PV310_PA_SYSMMU_SSS 0x10A50000
+#define S5PV310_PA_SYSMMU_FIMC0 0x11A20000
+#define S5PV310_PA_SYSMMU_FIMC1 0x11A30000
+#define S5PV310_PA_SYSMMU_FIMC2 0x11A40000
+#define S5PV310_PA_SYSMMU_FIMC3 0x11A50000
+#define S5PV310_PA_SYSMMU_JPEG 0x11A60000
+#define S5PV310_PA_SYSMMU_FIMD0 0x11E20000
+#define S5PV310_PA_SYSMMU_FIMD1 0x12220000
+#define S5PV310_PA_SYSMMU_PCIe 0x12620000
+#define S5PV310_PA_SYSMMU_G2D 0x12A20000
+#define S5PV310_PA_SYSMMU_ROTATOR 0x12A30000
+#define S5PV310_PA_SYSMMU_MDMA2 0x12A40000
+#define S5PV310_PA_SYSMMU_TV 0x12E20000
+#define S5PV310_PA_SYSMMU_MFC_L 0x13620000
+#define S5PV310_PA_SYSMMU_MFC_R 0x13630000
+#define S5PV310_SYSMMU_TOTAL_IPNUM 16
+#define S5P_SYSMMU_TOTAL_IPNUM S5PV310_SYSMMU_TOTAL_IPNUM
+
/* compatibiltiy defines. */
#define S3C_PA_UART S5PV310_PA_UART
#define S3C_PA_HSMMC0 S5PV310_PA_HSMMC(0)
@@ -116,5 +143,7 @@
#define S3C_PA_IIC7 S5PV310_PA_IIC(7)
#define S3C_PA_RTC S5PV310_PA_RTC
#define S3C_PA_WDT S5PV310_PA_WATCHDOG
+#define S5P_PA_MIPI_CSIS0 S5PV310_PA_MIPI_CSIS0
+#define S5P_PA_MIPI_CSIS1 S5PV310_PA_MIPI_CSIS1
#endif /* __ASM_ARCH_MAP_H */
diff --git a/arch/arm/mach-s5pv310/include/mach/regs-clock.h b/arch/arm/mach-s5pv310/include/mach/regs-clock.h
index f1028ca..b5c4ada 100644
--- a/arch/arm/mach-s5pv310/include/mach/regs-clock.h
+++ b/arch/arm/mach-s5pv310/include/mach/regs-clock.h
@@ -19,6 +19,12 @@
#define S5P_INFORM0 S5P_CLKREG(0x800)
+#define S5P_CLKDIV_LEFTBUS S5P_CLKREG(0x04500)
+#define S5P_CLKDIV_STAT_LEFTBUS S5P_CLKREG(0x04600)
+
+#define S5P_CLKDIV_RIGHTBUS S5P_CLKREG(0x08500)
+#define S5P_CLKDIV_STAT_RIGHTBUS S5P_CLKREG(0x08600)
+
#define S5P_EPLL_CON0 S5P_CLKREG(0x0C110)
#define S5P_EPLL_CON1 S5P_CLKREG(0x0C114)
#define S5P_VPLL_CON0 S5P_CLKREG(0x0C120)
@@ -58,6 +64,8 @@
#define S5P_CLKSRC_MASK_PERIL0 S5P_CLKREG(0x0C350)
#define S5P_CLKSRC_MASK_PERIL1 S5P_CLKREG(0x0C354)
+#define S5P_CLKDIV_STAT_TOP S5P_CLKREG(0x0C610)
+
#define S5P_CLKGATE_IP_CAM S5P_CLKREG(0x0C920)
#define S5P_CLKGATE_IP_IMAGE S5P_CLKREG(0x0C930)
#define S5P_CLKGATE_IP_LCD0 S5P_CLKREG(0x0C934)
@@ -66,8 +74,9 @@
#define S5P_CLKGATE_IP_PERIL S5P_CLKREG(0x0C950)
#define S5P_CLKGATE_IP_PERIR S5P_CLKREG(0x0C960)
-#define S5P_CLKSRC_CORE S5P_CLKREG(0x10200)
-#define S5P_CLKDIV_CORE0 S5P_CLKREG(0x10500)
+#define S5P_CLKSRC_DMC S5P_CLKREG(0x10200)
+#define S5P_CLKDIV_DMC0 S5P_CLKREG(0x10500)
+#define S5P_CLKDIV_STAT_DMC0 S5P_CLKREG(0x10600)
#define S5P_APLL_LOCK S5P_CLKREG(0x14000)
#define S5P_MPLL_LOCK S5P_CLKREG(0x14004)
@@ -80,10 +89,77 @@
#define S5P_CLKMUX_STATCPU S5P_CLKREG(0x14400)
#define S5P_CLKDIV_CPU S5P_CLKREG(0x14500)
+#define S5P_CLKDIV_CPU1 S5P_CLKREG(0x14504)
#define S5P_CLKDIV_STATCPU S5P_CLKREG(0x14600)
+#define S5P_CLKDIV_STATCPU1 S5P_CLKREG(0x14604)
#define S5P_CLKGATE_SCLKCPU S5P_CLKREG(0x14800)
+/* APLL_LOCK */
+#define S5P_APLL_LOCKTIME (0x1C20) /* 300us */
+
+/* APLL_CON0 */
+#define S5P_APLLCON0_ENABLE_SHIFT (31)
+#define S5P_APLLCON0_LOCKED_SHIFT (29)
+#define S5P_APLL_VAL_1000 ((250 << 16) | (6 << 8) | 1)
+#define S5P_APLL_VAL_800 ((200 << 16) | (6 << 8) | 1)
+
+/* CLK_SRC_CPU */
+#define S5P_CLKSRC_CPU_MUXCORE_SHIFT (16)
+#define S5P_CLKMUX_STATCPU_MUXCORE_MASK (0x7 << S5P_CLKSRC_CPU_MUXCORE_SHIFT)
+
+/* CLKDIV_CPU0 */
+#define S5P_CLKDIV_CPU0_CORE_SHIFT (0)
+#define S5P_CLKDIV_CPU0_CORE_MASK (0x7 << S5P_CLKDIV_CPU0_CORE_SHIFT)
+#define S5P_CLKDIV_CPU0_COREM0_SHIFT (4)
+#define S5P_CLKDIV_CPU0_COREM0_MASK (0x7 << S5P_CLKDIV_CPU0_COREM0_SHIFT)
+#define S5P_CLKDIV_CPU0_COREM1_SHIFT (8)
+#define S5P_CLKDIV_CPU0_COREM1_MASK (0x7 << S5P_CLKDIV_CPU0_COREM1_SHIFT)
+#define S5P_CLKDIV_CPU0_PERIPH_SHIFT (12)
+#define S5P_CLKDIV_CPU0_PERIPH_MASK (0x7 << S5P_CLKDIV_CPU0_PERIPH_SHIFT)
+#define S5P_CLKDIV_CPU0_ATB_SHIFT (16)
+#define S5P_CLKDIV_CPU0_ATB_MASK (0x7 << S5P_CLKDIV_CPU0_ATB_SHIFT)
+#define S5P_CLKDIV_CPU0_PCLKDBG_SHIFT (20)
+#define S5P_CLKDIV_CPU0_PCLKDBG_MASK (0x7 << S5P_CLKDIV_CPU0_PCLKDBG_SHIFT)
+#define S5P_CLKDIV_CPU0_APLL_SHIFT (24)
+#define S5P_CLKDIV_CPU0_APLL_MASK (0x7 << S5P_CLKDIV_CPU0_APLL_SHIFT)
+
+/* CLKDIV_DMC0 */
+#define S5P_CLKDIV_DMC0_ACP_SHIFT (0)
+#define S5P_CLKDIV_DMC0_ACP_MASK (0x7 << S5P_CLKDIV_DMC0_ACP_SHIFT)
+#define S5P_CLKDIV_DMC0_ACPPCLK_SHIFT (4)
+#define S5P_CLKDIV_DMC0_ACPPCLK_MASK (0x7 << S5P_CLKDIV_DMC0_ACPPCLK_SHIFT)
+#define S5P_CLKDIV_DMC0_DPHY_SHIFT (8)
+#define S5P_CLKDIV_DMC0_DPHY_MASK (0x7 << S5P_CLKDIV_DMC0_DPHY_SHIFT)
+#define S5P_CLKDIV_DMC0_DMC_SHIFT (12)
+#define S5P_CLKDIV_DMC0_DMC_MASK (0x7 << S5P_CLKDIV_DMC0_DMC_SHIFT)
+#define S5P_CLKDIV_DMC0_DMCD_SHIFT (16)
+#define S5P_CLKDIV_DMC0_DMCD_MASK (0x7 << S5P_CLKDIV_DMC0_DMCD_SHIFT)
+#define S5P_CLKDIV_DMC0_DMCP_SHIFT (20)
+#define S5P_CLKDIV_DMC0_DMCP_MASK (0x7 << S5P_CLKDIV_DMC0_DMCP_SHIFT)
+#define S5P_CLKDIV_DMC0_COPY2_SHIFT (24)
+#define S5P_CLKDIV_DMC0_COPY2_MASK (0x7 << S5P_CLKDIV_DMC0_COPY2_SHIFT)
+#define S5P_CLKDIV_DMC0_CORETI_SHIFT (28)
+#define S5P_CLKDIV_DMC0_CORETI_MASK (0x7 << S5P_CLKDIV_DMC0_CORETI_SHIFT)
+
+/* CLKDIV_TOP */
+#define S5P_CLKDIV_TOP_ACLK200_SHIFT (0)
+#define S5P_CLKDIV_TOP_ACLK200_MASK (0x7 << S5P_CLKDIV_TOP_ACLK200_SHIFT)
+#define S5P_CLKDIV_TOP_ACLK100_SHIFT (4)
+#define S5P_CLKDIV_TOP_ACLK100_MASK (0xf << S5P_CLKDIV_TOP_ACLK100_SHIFT)
+#define S5P_CLKDIV_TOP_ACLK160_SHIFT (8)
+#define S5P_CLKDIV_TOP_ACLK160_MASK (0x7 << S5P_CLKDIV_TOP_ACLK160_SHIFT)
+#define S5P_CLKDIV_TOP_ACLK133_SHIFT (12)
+#define S5P_CLKDIV_TOP_ACLK133_MASK (0x7 << S5P_CLKDIV_TOP_ACLK133_SHIFT)
+#define S5P_CLKDIV_TOP_ONENAND_SHIFT (16)
+#define S5P_CLKDIV_TOP_ONENAND_MASK (0x7 << S5P_CLKDIV_TOP_ONENAND_SHIFT)
+
+/* CLKDIV_LEFTBUS / CLKDIV_RIGHTBUS*/
+#define S5P_CLKDIV_BUS_GDLR_SHIFT (0)
+#define S5P_CLKDIV_BUS_GDLR_MASK (0x7 << S5P_CLKDIV_BUS_GDLR_SHIFT)
+#define S5P_CLKDIV_BUS_GPLR_SHIFT (4)
+#define S5P_CLKDIV_BUS_GPLR_MASK (0x7 << S5P_CLKDIV_BUS_GPLR_SHIFT)
+
/* Compatibility defines */
#define S5P_EPLL_CON S5P_EPLL_CON0
diff --git a/arch/arm/mach-s5pv310/include/mach/regs-mem.h b/arch/arm/mach-s5pv310/include/mach/regs-mem.h
new file mode 100644
index 0000000..8342271
--- /dev/null
+++ b/arch/arm/mach-s5pv310/include/mach/regs-mem.h
@@ -0,0 +1,23 @@
+/* linux/arch/arm/mach-s5pv310/include/mach/regs-mem.h
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * S5PV310 - SROMC and DMC register definitions
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#ifndef __ASM_ARCH_REGS_MEM_H
+#define __ASM_ARCH_REGS_MEM_H __FILE__
+
+#include <mach/map.h>
+
+#define S5P_DMC0_MEMCON_OFFSET 0x04
+
+#define S5P_DMC0_MEMTYPE_SHIFT 8
+#define S5P_DMC0_MEMTYPE_MASK 0xF
+
+#endif /* __ASM_ARCH_REGS_MEM_H */
diff --git a/arch/arm/mach-s5pv310/include/mach/regs-pmu.h b/arch/arm/mach-s5pv310/include/mach/regs-pmu.h
new file mode 100644
index 0000000..fb333d0
--- /dev/null
+++ b/arch/arm/mach-s5pv310/include/mach/regs-pmu.h
@@ -0,0 +1,30 @@
+/* linux/arch/arm/mach-s5pv310/include/mach/regs-pmu.h
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * S5PV310 - Power management unit definition
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#ifndef __ASM_ARCH_REGS_PMU_H
+#define __ASM_ARCH_REGS_PMU_H __FILE__
+
+#include <mach/map.h>
+
+#define S5P_PMUREG(x) (S5P_VA_PMU + (x))
+
+#define S5P_PMU_CAM_CONF S5P_PMUREG(0x3C00)
+#define S5P_PMU_TV_CONF S5P_PMUREG(0x3C20)
+#define S5P_PMU_MFC_CONF S5P_PMUREG(0x3C40)
+#define S5P_PMU_G3D_CONF S5P_PMUREG(0x3C60)
+#define S5P_PMU_LCD0_CONF S5P_PMUREG(0x3C80)
+#define S5P_PMU_LCD1_CONF S5P_PMUREG(0x3CA0)
+#define S5P_PMU_GPS_CONF S5P_PMUREG(0x3CE0)
+
+#define S5P_INT_LOCAL_PWR_EN 0x7
+
+#endif /* __ASM_ARCH_REGS_PMU_H */
diff --git a/arch/arm/mach-s5pv310/include/mach/regs-srom.h b/arch/arm/mach-s5pv310/include/mach/regs-srom.h
deleted file mode 100644
index 1898b3e..0000000
--- a/arch/arm/mach-s5pv310/include/mach/regs-srom.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/* linux/arch/arm/mach-s5pv310/include/mach/regs-srom.h
- *
- * Copyright (c) 2010 Samsung Electronics Co., Ltd.
- * http://www.samsung.com
- *
- * S5PV310 - SROMC register definitions
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#ifndef __ASM_ARCH_REGS_SROM_H
-#define __ASM_ARCH_REGS_SROM_H __FILE__
-
-#include <mach/map.h>
-
-#define S5PV310_SROMREG(x) (S5P_VA_SROMC + (x))
-
-#define S5PV310_SROM_BW S5PV310_SROMREG(0x0)
-#define S5PV310_SROM_BC0 S5PV310_SROMREG(0x4)
-#define S5PV310_SROM_BC1 S5PV310_SROMREG(0x8)
-#define S5PV310_SROM_BC2 S5PV310_SROMREG(0xc)
-#define S5PV310_SROM_BC3 S5PV310_SROMREG(0x10)
-
-/* one register BW holds 4 x 4-bit packed settings for NCS0 - NCS3 */
-
-#define S5PV310_SROM_BW__DATAWIDTH__SHIFT 0
-#define S5PV310_SROM_BW__ADDRMODE__SHIFT 1
-#define S5PV310_SROM_BW__WAITENABLE__SHIFT 2
-#define S5PV310_SROM_BW__BYTEENABLE__SHIFT 3
-
-#define S5PV310_SROM_BW__CS_MASK 0xf
-
-#define S5PV310_SROM_BW__NCS0__SHIFT 0
-#define S5PV310_SROM_BW__NCS1__SHIFT 4
-#define S5PV310_SROM_BW__NCS2__SHIFT 8
-#define S5PV310_SROM_BW__NCS3__SHIFT 12
-
-/* applies to same to BCS0 - BCS3 */
-
-#define S5PV310_SROM_BCX__PMC__SHIFT 0
-#define S5PV310_SROM_BCX__TACP__SHIFT 4
-#define S5PV310_SROM_BCX__TCAH__SHIFT 8
-#define S5PV310_SROM_BCX__TCOH__SHIFT 12
-#define S5PV310_SROM_BCX__TACC__SHIFT 16
-#define S5PV310_SROM_BCX__TCOS__SHIFT 24
-#define S5PV310_SROM_BCX__TACS__SHIFT 28
-
-#endif /* __ASM_ARCH_REGS_SROM_H */
diff --git a/arch/arm/mach-s5pv310/include/mach/regs-sysmmu.h b/arch/arm/mach-s5pv310/include/mach/regs-sysmmu.h
new file mode 100644
index 0000000..0b28e81
--- /dev/null
+++ b/arch/arm/mach-s5pv310/include/mach/regs-sysmmu.h
@@ -0,0 +1,24 @@
+/* linux/arch/arm/mach-s5pv310/include/mach/regs-sysmmu.h
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * S5PV310 - System MMU register
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#ifndef __ASM_ARCH_REGS_SYSMMU_H
+#define __ASM_ARCH_REGS_SYSMMU_H __FILE__
+
+#define S5P_MMU_CTRL 0x000
+#define S5P_MMU_CFG 0x004
+#define S5P_MMU_STATUS 0x008
+#define S5P_MMU_FLUSH 0x00C
+#define S5P_PT_BASE_ADDR 0x014
+#define S5P_INT_STATUS 0x018
+#define S5P_PAGE_FAULT_ADDR 0x024
+
+#endif /* __ASM_ARCH_REGS_SYSMMU_H */
diff --git a/arch/arm/mach-s5pv310/include/mach/sysmmu.h b/arch/arm/mach-s5pv310/include/mach/sysmmu.h
new file mode 100644
index 0000000..662fe85f
--- /dev/null
+++ b/arch/arm/mach-s5pv310/include/mach/sysmmu.h
@@ -0,0 +1,119 @@
+/* linux/arch/arm/mach-s5pv310/include/mach/sysmmu.h
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * Samsung sysmmu driver for S5PV310
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#ifndef __ASM_ARM_ARCH_SYSMMU_H
+#define __ASM_ARM_ARCH_SYSMMU_H __FILE__
+
+enum s5pv310_sysmmu_ips {
+ SYSMMU_MDMA,
+ SYSMMU_SSS,
+ SYSMMU_FIMC0,
+ SYSMMU_FIMC1,
+ SYSMMU_FIMC2,
+ SYSMMU_FIMC3,
+ SYSMMU_JPEG,
+ SYSMMU_FIMD0,
+ SYSMMU_FIMD1,
+ SYSMMU_PCIe,
+ SYSMMU_G2D,
+ SYSMMU_ROTATOR,
+ SYSMMU_MDMA2,
+ SYSMMU_TV,
+ SYSMMU_MFC_L,
+ SYSMMU_MFC_R,
+};
+
+static char *sysmmu_ips_name[S5P_SYSMMU_TOTAL_IPNUM] = {
+ "SYSMMU_MDMA" ,
+ "SYSMMU_SSS" ,
+ "SYSMMU_FIMC0" ,
+ "SYSMMU_FIMC1" ,
+ "SYSMMU_FIMC2" ,
+ "SYSMMU_FIMC3" ,
+ "SYSMMU_JPEG" ,
+ "SYSMMU_FIMD0" ,
+ "SYSMMU_FIMD1" ,
+ "SYSMMU_PCIe" ,
+ "SYSMMU_G2D" ,
+ "SYSMMU_ROTATOR",
+ "SYSMMU_MDMA2" ,
+ "SYSMMU_TV" ,
+ "SYSMMU_MFC_L" ,
+ "SYSMMU_MFC_R" ,
+};
+
+typedef enum s5pv310_sysmmu_ips sysmmu_ips;
+
+struct sysmmu_tt_info {
+ unsigned long *pgd;
+ unsigned long pgd_paddr;
+ unsigned long *pte;
+};
+
+struct sysmmu_controller {
+ const char *name;
+
+ /* channels registers */
+ void __iomem *regs;
+
+ /* channel irq */
+ unsigned int irq;
+
+ sysmmu_ips ips;
+
+ /* Translation Table Info. */
+ struct sysmmu_tt_info *tt_info;
+
+ struct resource *mem;
+ struct device *dev;
+
+ /* SysMMU controller enable - true : enable */
+ bool enable;
+};
+
+/**
+ * s5p_sysmmu_enable() - enable system mmu of ip
+ * @ips: The ip connected system mmu.
+ *
+ * This function enable system mmu to transfer address
+ * from virtual address to physical address
+ */
+int s5p_sysmmu_enable(sysmmu_ips ips);
+
+/**
+ * s5p_sysmmu_disable() - disable sysmmu mmu of ip
+ * @ips: The ip connected system mmu.
+ *
+ * This function disable system mmu to transfer address
+ * from virtual address to physical address
+ */
+int s5p_sysmmu_disable(sysmmu_ips ips);
+
+/**
+ * s5p_sysmmu_set_tablebase_pgd() - set page table base address to refer page table
+ * @ips: The ip connected system mmu.
+ * @pgd: The page table base address.
+ *
+ * This function set page table base address
+ * When system mmu transfer address from virtaul address to physical address,
+ * system mmu refer address information from page table
+ */
+int s5p_sysmmu_set_tablebase_pgd(sysmmu_ips ips, unsigned long pgd);
+
+/**
+ * s5p_sysmmu_tlb_invalidate() - flush all TLB entry in system mmu
+ * @ips: The ip connected system mmu.
+ *
+ * This function flush all TLB entry in system mmu
+ */
+int s5p_sysmmu_tlb_invalidate(sysmmu_ips ips);
+#endif /* __ASM_ARM_ARCH_SYSMMU_H */
diff --git a/arch/arm/mach-s5pv310/irq-combiner.c b/arch/arm/mach-s5pv310/irq-combiner.c
index c3f88c3..1ea4a9e 100644
--- a/arch/arm/mach-s5pv310/irq-combiner.c
+++ b/arch/arm/mach-s5pv310/irq-combiner.c
@@ -24,29 +24,32 @@ static DEFINE_SPINLOCK(irq_controller_lock);
struct combiner_chip_data {
unsigned int irq_offset;
+ unsigned int irq_mask;
void __iomem *base;
};
static struct combiner_chip_data combiner_data[MAX_COMBINER_NR];
-static inline void __iomem *combiner_base(unsigned int irq)
+static inline void __iomem *combiner_base(struct irq_data *data)
{
- struct combiner_chip_data *combiner_data = get_irq_chip_data(irq);
+ struct combiner_chip_data *combiner_data =
+ irq_data_get_irq_chip_data(data);
+
return combiner_data->base;
}
-static void combiner_mask_irq(unsigned int irq)
+static void combiner_mask_irq(struct irq_data *data)
{
- u32 mask = 1 << (irq % 32);
+ u32 mask = 1 << (data->irq % 32);
- __raw_writel(mask, combiner_base(irq) + COMBINER_ENABLE_CLEAR);
+ __raw_writel(mask, combiner_base(data) + COMBINER_ENABLE_CLEAR);
}
-static void combiner_unmask_irq(unsigned int irq)
+static void combiner_unmask_irq(struct irq_data *data)
{
- u32 mask = 1 << (irq % 32);
+ u32 mask = 1 << (data->irq % 32);
- __raw_writel(mask, combiner_base(irq) + COMBINER_ENABLE_SET);
+ __raw_writel(mask, combiner_base(data) + COMBINER_ENABLE_SET);
}
static void combiner_handle_cascade_irq(unsigned int irq, struct irq_desc *desc)
@@ -57,11 +60,12 @@ static void combiner_handle_cascade_irq(unsigned int irq, struct irq_desc *desc)
unsigned long status;
/* primary controller ack'ing */
- chip->ack(irq);
+ chip->irq_ack(&desc->irq_data);
spin_lock(&irq_controller_lock);
status = __raw_readl(chip_data->base + COMBINER_INT_STATUS);
spin_unlock(&irq_controller_lock);
+ status &= chip_data->irq_mask;
if (status == 0)
goto out;
@@ -76,13 +80,13 @@ static void combiner_handle_cascade_irq(unsigned int irq, struct irq_desc *desc)
out:
/* primary controller unmasking */
- chip->unmask(irq);
+ chip->irq_unmask(&desc->irq_data);
}
static struct irq_chip combiner_chip = {
.name = "COMBINER",
- .mask = combiner_mask_irq,
- .unmask = combiner_unmask_irq,
+ .irq_mask = combiner_mask_irq,
+ .irq_unmask = combiner_unmask_irq,
};
void __init combiner_cascade_irq(unsigned int combiner_nr, unsigned int irq)
@@ -104,10 +108,12 @@ void __init combiner_init(unsigned int combiner_nr, void __iomem *base,
combiner_data[combiner_nr].base = base;
combiner_data[combiner_nr].irq_offset = irq_start;
+ combiner_data[combiner_nr].irq_mask = 0xff << ((combiner_nr % 4) << 3);
/* Disable all interrupts */
- __raw_writel(0xffffffff, base + COMBINER_ENABLE_CLEAR);
+ __raw_writel(combiner_data[combiner_nr].irq_mask,
+ base + COMBINER_ENABLE_CLEAR);
/* Setup the Linux IRQ subsystem */
diff --git a/arch/arm/mach-s5pv310/irq-eint.c b/arch/arm/mach-s5pv310/irq-eint.c
index 5877503..477bd9e 100644
--- a/arch/arm/mach-s5pv310/irq-eint.c
+++ b/arch/arm/mach-s5pv310/irq-eint.c
@@ -48,42 +48,43 @@ static unsigned int s5pv310_get_irq_nr(unsigned int number)
return ret;
}
-static inline void s5pv310_irq_eint_mask(unsigned int irq)
+static inline void s5pv310_irq_eint_mask(struct irq_data *data)
{
u32 mask;
spin_lock(&eint_lock);
- mask = __raw_readl(S5P_EINT_MASK(EINT_REG_NR(irq)));
- mask |= eint_irq_to_bit(irq);
- __raw_writel(mask, S5P_EINT_MASK(EINT_REG_NR(irq)));
+ mask = __raw_readl(S5P_EINT_MASK(EINT_REG_NR(data->irq)));
+ mask |= eint_irq_to_bit(data->irq);
+ __raw_writel(mask, S5P_EINT_MASK(EINT_REG_NR(data->irq)));
spin_unlock(&eint_lock);
}
-static void s5pv310_irq_eint_unmask(unsigned int irq)
+static void s5pv310_irq_eint_unmask(struct irq_data *data)
{
u32 mask;
spin_lock(&eint_lock);
- mask = __raw_readl(S5P_EINT_MASK(EINT_REG_NR(irq)));
- mask &= ~(eint_irq_to_bit(irq));
- __raw_writel(mask, S5P_EINT_MASK(EINT_REG_NR(irq)));
+ mask = __raw_readl(S5P_EINT_MASK(EINT_REG_NR(data->irq)));
+ mask &= ~(eint_irq_to_bit(data->irq));
+ __raw_writel(mask, S5P_EINT_MASK(EINT_REG_NR(data->irq)));
spin_unlock(&eint_lock);
}
-static inline void s5pv310_irq_eint_ack(unsigned int irq)
+static inline void s5pv310_irq_eint_ack(struct irq_data *data)
{
- __raw_writel(eint_irq_to_bit(irq), S5P_EINT_PEND(EINT_REG_NR(irq)));
+ __raw_writel(eint_irq_to_bit(data->irq),
+ S5P_EINT_PEND(EINT_REG_NR(data->irq)));
}
-static void s5pv310_irq_eint_maskack(unsigned int irq)
+static void s5pv310_irq_eint_maskack(struct irq_data *data)
{
- s5pv310_irq_eint_mask(irq);
- s5pv310_irq_eint_ack(irq);
+ s5pv310_irq_eint_mask(data);
+ s5pv310_irq_eint_ack(data);
}
-static int s5pv310_irq_eint_set_type(unsigned int irq, unsigned int type)
+static int s5pv310_irq_eint_set_type(struct irq_data *data, unsigned int type)
{
- int offs = EINT_OFFSET(irq);
+ int offs = EINT_OFFSET(data->irq);
int shift;
u32 ctrl, mask;
u32 newvalue = 0;
@@ -118,10 +119,10 @@ static int s5pv310_irq_eint_set_type(unsigned int irq, unsigned int type)
mask = 0x7 << shift;
spin_lock(&eint_lock);
- ctrl = __raw_readl(S5P_EINT_CON(EINT_REG_NR(irq)));
+ ctrl = __raw_readl(S5P_EINT_CON(EINT_REG_NR(data->irq)));
ctrl &= ~mask;
ctrl |= newvalue << shift;
- __raw_writel(ctrl, S5P_EINT_CON(EINT_REG_NR(irq)));
+ __raw_writel(ctrl, S5P_EINT_CON(EINT_REG_NR(data->irq)));
spin_unlock(&eint_lock);
switch (offs) {
@@ -146,13 +147,13 @@ static int s5pv310_irq_eint_set_type(unsigned int irq, unsigned int type)
static struct irq_chip s5pv310_irq_eint = {
.name = "s5pv310-eint",
- .mask = s5pv310_irq_eint_mask,
- .unmask = s5pv310_irq_eint_unmask,
- .mask_ack = s5pv310_irq_eint_maskack,
- .ack = s5pv310_irq_eint_ack,
- .set_type = s5pv310_irq_eint_set_type,
+ .irq_mask = s5pv310_irq_eint_mask,
+ .irq_unmask = s5pv310_irq_eint_unmask,
+ .irq_mask_ack = s5pv310_irq_eint_maskack,
+ .irq_ack = s5pv310_irq_eint_ack,
+ .irq_set_type = s5pv310_irq_eint_set_type,
#ifdef CONFIG_PM
- .set_wake = s3c_irqext_wake,
+ .irq_set_wake = s3c_irqext_wake,
#endif
};
@@ -192,14 +193,14 @@ static void s5pv310_irq_eint0_15(unsigned int irq, struct irq_desc *desc)
u32 *irq_data = get_irq_data(irq);
struct irq_chip *chip = get_irq_chip(irq);
- chip->mask(irq);
+ chip->irq_mask(&desc->irq_data);
- if (chip->ack)
- chip->ack(irq);
+ if (chip->irq_ack)
+ chip->irq_ack(&desc->irq_data);
generic_handle_irq(*irq_data);
- chip->unmask(irq);
+ chip->irq_unmask(&desc->irq_data);
}
int __init s5pv310_init_irq_eint(void)
diff --git a/arch/arm/mach-s5pv310/mach-smdkc210.c b/arch/arm/mach-s5pv310/mach-smdkc210.c
index 2b8d4fc..d9cab02 100644
--- a/arch/arm/mach-s5pv310/mach-smdkc210.c
+++ b/arch/arm/mach-s5pv310/mach-smdkc210.c
@@ -14,18 +14,21 @@
#include <linux/platform_device.h>
#include <linux/smsc911x.h>
#include <linux/io.h>
+#include <linux/i2c.h>
#include <asm/mach/arch.h>
#include <asm/mach-types.h>
#include <plat/regs-serial.h>
+#include <plat/regs-srom.h>
#include <plat/s5pv310.h>
#include <plat/cpu.h>
#include <plat/devs.h>
#include <plat/sdhci.h>
+#include <plat/iic.h>
+#include <plat/pd.h>
#include <mach/map.h>
-#include <mach/regs-srom.h>
/* Following are default values for UCON, ULCON and UFCON UART registers */
#define SMDKC210_UCON_DEFAULT (S3C2410_UCON_TXILEVEL | \
@@ -139,13 +142,29 @@ static struct platform_device smdkc210_smsc911x = {
},
};
+static struct i2c_board_info i2c_devs1[] __initdata = {
+ {I2C_BOARD_INFO("wm8994", 0x1a),},
+};
+
static struct platform_device *smdkc210_devices[] __initdata = {
&s3c_device_hsmmc0,
&s3c_device_hsmmc1,
&s3c_device_hsmmc2,
&s3c_device_hsmmc3,
+ &s3c_device_i2c1,
&s3c_device_rtc,
&s3c_device_wdt,
+ &s5pv310_device_ac97,
+ &s5pv310_device_i2s0,
+ &s5pv310_device_pd[PD_MFC],
+ &s5pv310_device_pd[PD_G3D],
+ &s5pv310_device_pd[PD_LCD0],
+ &s5pv310_device_pd[PD_LCD1],
+ &s5pv310_device_pd[PD_CAM],
+ &s5pv310_device_pd[PD_TV],
+ &s5pv310_device_pd[PD_GPS],
+ &s5pv310_device_sysmmu,
+ &samsung_asoc_dma,
&smdkc210_smsc911x,
};
@@ -154,23 +173,22 @@ static void __init smdkc210_smsc911x_init(void)
u32 cs1;
/* configure nCS1 width to 16 bits */
- cs1 = __raw_readl(S5PV310_SROM_BW) &
- ~(S5PV310_SROM_BW__CS_MASK <<
- S5PV310_SROM_BW__NCS1__SHIFT);
- cs1 |= ((1 << S5PV310_SROM_BW__DATAWIDTH__SHIFT) |
- (1 << S5PV310_SROM_BW__WAITENABLE__SHIFT) |
- (1 << S5PV310_SROM_BW__BYTEENABLE__SHIFT)) <<
- S5PV310_SROM_BW__NCS1__SHIFT;
- __raw_writel(cs1, S5PV310_SROM_BW);
+ cs1 = __raw_readl(S5P_SROM_BW) &
+ ~(S5P_SROM_BW__CS_MASK << S5P_SROM_BW__NCS1__SHIFT);
+ cs1 |= ((1 << S5P_SROM_BW__DATAWIDTH__SHIFT) |
+ (1 << S5P_SROM_BW__WAITENABLE__SHIFT) |
+ (1 << S5P_SROM_BW__BYTEENABLE__SHIFT)) <<
+ S5P_SROM_BW__NCS1__SHIFT;
+ __raw_writel(cs1, S5P_SROM_BW);
/* set timing for nCS1 suitable for ethernet chip */
- __raw_writel((0x1 << S5PV310_SROM_BCX__PMC__SHIFT) |
- (0x9 << S5PV310_SROM_BCX__TACP__SHIFT) |
- (0xc << S5PV310_SROM_BCX__TCAH__SHIFT) |
- (0x1 << S5PV310_SROM_BCX__TCOH__SHIFT) |
- (0x6 << S5PV310_SROM_BCX__TACC__SHIFT) |
- (0x1 << S5PV310_SROM_BCX__TCOS__SHIFT) |
- (0x1 << S5PV310_SROM_BCX__TACS__SHIFT), S5PV310_SROM_BC1);
+ __raw_writel((0x1 << S5P_SROM_BCX__PMC__SHIFT) |
+ (0x9 << S5P_SROM_BCX__TACP__SHIFT) |
+ (0xc << S5P_SROM_BCX__TCAH__SHIFT) |
+ (0x1 << S5P_SROM_BCX__TCOH__SHIFT) |
+ (0x6 << S5P_SROM_BCX__TACC__SHIFT) |
+ (0x1 << S5P_SROM_BCX__TCOS__SHIFT) |
+ (0x1 << S5P_SROM_BCX__TACS__SHIFT), S5P_SROM_BC1);
}
static void __init smdkc210_map_io(void)
@@ -182,6 +200,9 @@ static void __init smdkc210_map_io(void)
static void __init smdkc210_machine_init(void)
{
+ s3c_i2c1_set_platdata(NULL);
+ i2c_register_board_info(1, i2c_devs1, ARRAY_SIZE(i2c_devs1));
+
smdkc210_smsc911x_init();
s3c_sdhci0_set_platdata(&smdkc210_hsmmc0_pdata);
diff --git a/arch/arm/mach-s5pv310/mach-smdkv310.c b/arch/arm/mach-s5pv310/mach-smdkv310.c
index 35826d6..b1cddbf 100644
--- a/arch/arm/mach-s5pv310/mach-smdkv310.c
+++ b/arch/arm/mach-s5pv310/mach-smdkv310.c
@@ -14,18 +14,21 @@
#include <linux/platform_device.h>
#include <linux/smsc911x.h>
#include <linux/io.h>
+#include <linux/i2c.h>
#include <asm/mach/arch.h>
#include <asm/mach-types.h>
#include <plat/regs-serial.h>
+#include <plat/regs-srom.h>
#include <plat/s5pv310.h>
#include <plat/cpu.h>
#include <plat/devs.h>
#include <plat/sdhci.h>
+#include <plat/iic.h>
+#include <plat/pd.h>
#include <mach/map.h>
-#include <mach/regs-srom.h>
/* Following are default values for UCON, ULCON and UFCON UART registers */
#define SMDKV310_UCON_DEFAULT (S3C2410_UCON_TXILEVEL | \
@@ -139,13 +142,29 @@ static struct platform_device smdkv310_smsc911x = {
},
};
+static struct i2c_board_info i2c_devs1[] __initdata = {
+ {I2C_BOARD_INFO("wm8994", 0x1a),},
+};
+
static struct platform_device *smdkv310_devices[] __initdata = {
&s3c_device_hsmmc0,
&s3c_device_hsmmc1,
&s3c_device_hsmmc2,
&s3c_device_hsmmc3,
+ &s3c_device_i2c1,
&s3c_device_rtc,
&s3c_device_wdt,
+ &s5pv310_device_ac97,
+ &s5pv310_device_i2s0,
+ &s5pv310_device_pd[PD_MFC],
+ &s5pv310_device_pd[PD_G3D],
+ &s5pv310_device_pd[PD_LCD0],
+ &s5pv310_device_pd[PD_LCD1],
+ &s5pv310_device_pd[PD_CAM],
+ &s5pv310_device_pd[PD_TV],
+ &s5pv310_device_pd[PD_GPS],
+ &s5pv310_device_sysmmu,
+ &samsung_asoc_dma,
&smdkv310_smsc911x,
};
@@ -154,23 +173,22 @@ static void __init smdkv310_smsc911x_init(void)
u32 cs1;
/* configure nCS1 width to 16 bits */
- cs1 = __raw_readl(S5PV310_SROM_BW) &
- ~(S5PV310_SROM_BW__CS_MASK <<
- S5PV310_SROM_BW__NCS1__SHIFT);
- cs1 |= ((1 << S5PV310_SROM_BW__DATAWIDTH__SHIFT) |
- (1 << S5PV310_SROM_BW__WAITENABLE__SHIFT) |
- (1 << S5PV310_SROM_BW__BYTEENABLE__SHIFT)) <<
- S5PV310_SROM_BW__NCS1__SHIFT;
- __raw_writel(cs1, S5PV310_SROM_BW);
+ cs1 = __raw_readl(S5P_SROM_BW) &
+ ~(S5P_SROM_BW__CS_MASK << S5P_SROM_BW__NCS1__SHIFT);
+ cs1 |= ((1 << S5P_SROM_BW__DATAWIDTH__SHIFT) |
+ (1 << S5P_SROM_BW__WAITENABLE__SHIFT) |
+ (1 << S5P_SROM_BW__BYTEENABLE__SHIFT)) <<
+ S5P_SROM_BW__NCS1__SHIFT;
+ __raw_writel(cs1, S5P_SROM_BW);
/* set timing for nCS1 suitable for ethernet chip */
- __raw_writel((0x1 << S5PV310_SROM_BCX__PMC__SHIFT) |
- (0x9 << S5PV310_SROM_BCX__TACP__SHIFT) |
- (0xc << S5PV310_SROM_BCX__TCAH__SHIFT) |
- (0x1 << S5PV310_SROM_BCX__TCOH__SHIFT) |
- (0x6 << S5PV310_SROM_BCX__TACC__SHIFT) |
- (0x1 << S5PV310_SROM_BCX__TCOS__SHIFT) |
- (0x1 << S5PV310_SROM_BCX__TACS__SHIFT), S5PV310_SROM_BC1);
+ __raw_writel((0x1 << S5P_SROM_BCX__PMC__SHIFT) |
+ (0x9 << S5P_SROM_BCX__TACP__SHIFT) |
+ (0xc << S5P_SROM_BCX__TCAH__SHIFT) |
+ (0x1 << S5P_SROM_BCX__TCOH__SHIFT) |
+ (0x6 << S5P_SROM_BCX__TACC__SHIFT) |
+ (0x1 << S5P_SROM_BCX__TCOS__SHIFT) |
+ (0x1 << S5P_SROM_BCX__TACS__SHIFT), S5P_SROM_BC1);
}
static void __init smdkv310_map_io(void)
@@ -182,6 +200,9 @@ static void __init smdkv310_map_io(void)
static void __init smdkv310_machine_init(void)
{
+ s3c_i2c1_set_platdata(NULL);
+ i2c_register_board_info(1, i2c_devs1, ARRAY_SIZE(i2c_devs1));
+
smdkv310_smsc911x_init();
s3c_sdhci0_set_platdata(&smdkv310_hsmmc0_pdata);
diff --git a/arch/arm/mach-s5pv310/mach-universal_c210.c b/arch/arm/mach-s5pv310/mach-universal_c210.c
index 16d8fc0..36bc3cf 100644
--- a/arch/arm/mach-s5pv310/mach-universal_c210.c
+++ b/arch/arm/mach-s5pv310/mach-universal_c210.c
@@ -13,6 +13,9 @@
#include <linux/i2c.h>
#include <linux/gpio_keys.h>
#include <linux/gpio.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/fixed.h>
+#include <linux/mmc/host.h>
#include <asm/mach/arch.h>
#include <asm/mach-types.h>
@@ -21,6 +24,7 @@
#include <plat/s5pv310.h>
#include <plat/cpu.h>
#include <plat/devs.h>
+#include <plat/sdhci.h>
#include <mach/map.h>
@@ -116,6 +120,73 @@ static struct platform_device universal_gpio_keys = {
},
};
+/* eMMC */
+static struct s3c_sdhci_platdata universal_hsmmc0_data __initdata = {
+ .max_width = 8,
+ .host_caps = (MMC_CAP_8_BIT_DATA | MMC_CAP_4_BIT_DATA |
+ MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED |
+ MMC_CAP_DISABLE),
+ .cd_type = S3C_SDHCI_CD_PERMANENT,
+ .clk_type = S3C_SDHCI_CLK_DIV_EXTERNAL,
+};
+
+static struct regulator_consumer_supply mmc0_supplies[] = {
+ REGULATOR_SUPPLY("vmmc", "s3c-sdhci.0"),
+};
+
+static struct regulator_init_data mmc0_fixed_voltage_init_data = {
+ .constraints = {
+ .name = "VMEM_VDD_2.8V",
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(mmc0_supplies),
+ .consumer_supplies = mmc0_supplies,
+};
+
+static struct fixed_voltage_config mmc0_fixed_voltage_config = {
+ .supply_name = "MASSMEMORY_EN",
+ .microvolts = 2800000,
+ .gpio = S5PV310_GPE1(3),
+ .enable_high = true,
+ .init_data = &mmc0_fixed_voltage_init_data,
+};
+
+static struct platform_device mmc0_fixed_voltage = {
+ .name = "reg-fixed-voltage",
+ .id = 0,
+ .dev = {
+ .platform_data = &mmc0_fixed_voltage_config,
+ },
+};
+
+/* SD */
+static struct s3c_sdhci_platdata universal_hsmmc2_data __initdata = {
+ .max_width = 4,
+ .host_caps = MMC_CAP_4_BIT_DATA |
+ MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED |
+ MMC_CAP_DISABLE,
+ .ext_cd_gpio = S5PV310_GPX3(4), /* XEINT_28 */
+ .ext_cd_gpio_invert = 1,
+ .cd_type = S3C_SDHCI_CD_GPIO,
+ .clk_type = S3C_SDHCI_CLK_DIV_EXTERNAL,
+};
+
+/* WiFi */
+static struct s3c_sdhci_platdata universal_hsmmc3_data __initdata = {
+ .max_width = 4,
+ .host_caps = MMC_CAP_4_BIT_DATA |
+ MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED |
+ MMC_CAP_DISABLE,
+ .cd_type = S3C_SDHCI_CD_EXTERNAL,
+};
+
+static void __init universal_sdhci_init(void)
+{
+ s3c_sdhci0_set_platdata(&universal_hsmmc0_data);
+ s3c_sdhci2_set_platdata(&universal_hsmmc2_data);
+ s3c_sdhci3_set_platdata(&universal_hsmmc3_data);
+}
+
/* I2C0 */
static struct i2c_board_info i2c0_devs[] __initdata = {
/* Camera, To be updated */
@@ -127,6 +198,13 @@ static struct i2c_board_info i2c1_devs[] __initdata = {
};
static struct platform_device *universal_devices[] __initdata = {
+ /* Samsung Platform Devices */
+ &mmc0_fixed_voltage,
+ &s3c_device_hsmmc0,
+ &s3c_device_hsmmc2,
+ &s3c_device_hsmmc3,
+
+ /* Universal Devices */
&universal_gpio_keys,
&s5p_device_onenand,
};
@@ -140,6 +218,8 @@ static void __init universal_map_io(void)
static void __init universal_machine_init(void)
{
+ universal_sdhci_init();
+
i2c_register_board_info(0, i2c0_devs, ARRAY_SIZE(i2c0_devs));
i2c_register_board_info(1, i2c1_devs, ARRAY_SIZE(i2c1_devs));
diff --git a/arch/arm/mach-sa1100/generic.c b/arch/arm/mach-sa1100/generic.c
index 59d14f0..e21f347 100644
--- a/arch/arm/mach-sa1100/generic.c
+++ b/arch/arm/mach-sa1100/generic.c
@@ -21,7 +21,6 @@
#include <asm/div64.h>
#include <mach/hardware.h>
#include <asm/system.h>
-#include <asm/pgtable.h>
#include <asm/mach/map.h>
#include <asm/mach/flash.h>
#include <asm/irq.h>
diff --git a/arch/arm/mach-sa1100/irq.c b/arch/arm/mach-sa1100/irq.c
index 3093d46..3d85dfa 100644
--- a/arch/arm/mach-sa1100/irq.c
+++ b/arch/arm/mach-sa1100/irq.c
@@ -37,14 +37,14 @@ static int GPIO_IRQ_mask = (1 << 11) - 1;
#define GPIO_11_27_IRQ(i) ((i) - 21)
#define GPIO11_27_MASK(irq) (1 << GPIO_11_27_IRQ(irq))
-static int sa1100_gpio_type(unsigned int irq, unsigned int type)
+static int sa1100_gpio_type(struct irq_data *d, unsigned int type)
{
unsigned int mask;
- if (irq <= 10)
- mask = 1 << irq;
+ if (d->irq <= 10)
+ mask = 1 << d->irq;
else
- mask = GPIO11_27_MASK(irq);
+ mask = GPIO11_27_MASK(d->irq);
if (type == IRQ_TYPE_PROBE) {
if ((GPIO_IRQ_rising_edge | GPIO_IRQ_falling_edge) & mask)
@@ -70,37 +70,37 @@ static int sa1100_gpio_type(unsigned int irq, unsigned int type)
/*
* GPIO IRQs must be acknowledged. This is for IRQs from 0 to 10.
*/
-static void sa1100_low_gpio_ack(unsigned int irq)
+static void sa1100_low_gpio_ack(struct irq_data *d)
{
- GEDR = (1 << irq);
+ GEDR = (1 << d->irq);
}
-static void sa1100_low_gpio_mask(unsigned int irq)
+static void sa1100_low_gpio_mask(struct irq_data *d)
{
- ICMR &= ~(1 << irq);
+ ICMR &= ~(1 << d->irq);
}
-static void sa1100_low_gpio_unmask(unsigned int irq)
+static void sa1100_low_gpio_unmask(struct irq_data *d)
{
- ICMR |= 1 << irq;
+ ICMR |= 1 << d->irq;
}
-static int sa1100_low_gpio_wake(unsigned int irq, unsigned int on)
+static int sa1100_low_gpio_wake(struct irq_data *d, unsigned int on)
{
if (on)
- PWER |= 1 << irq;
+ PWER |= 1 << d->irq;
else
- PWER &= ~(1 << irq);
+ PWER &= ~(1 << d->irq);
return 0;
}
static struct irq_chip sa1100_low_gpio_chip = {
.name = "GPIO-l",
- .ack = sa1100_low_gpio_ack,
- .mask = sa1100_low_gpio_mask,
- .unmask = sa1100_low_gpio_unmask,
- .set_type = sa1100_gpio_type,
- .set_wake = sa1100_low_gpio_wake,
+ .irq_ack = sa1100_low_gpio_ack,
+ .irq_mask = sa1100_low_gpio_mask,
+ .irq_unmask = sa1100_low_gpio_unmask,
+ .irq_set_type = sa1100_gpio_type,
+ .irq_set_wake = sa1100_low_gpio_wake,
};
/*
@@ -139,16 +139,16 @@ sa1100_high_gpio_handler(unsigned int irq, struct irq_desc *desc)
* In addition, the IRQs are all collected up into one bit in the
* interrupt controller registers.
*/
-static void sa1100_high_gpio_ack(unsigned int irq)
+static void sa1100_high_gpio_ack(struct irq_data *d)
{
- unsigned int mask = GPIO11_27_MASK(irq);
+ unsigned int mask = GPIO11_27_MASK(d->irq);
GEDR = mask;
}
-static void sa1100_high_gpio_mask(unsigned int irq)
+static void sa1100_high_gpio_mask(struct irq_data *d)
{
- unsigned int mask = GPIO11_27_MASK(irq);
+ unsigned int mask = GPIO11_27_MASK(d->irq);
GPIO_IRQ_mask &= ~mask;
@@ -156,9 +156,9 @@ static void sa1100_high_gpio_mask(unsigned int irq)
GFER &= ~mask;
}
-static void sa1100_high_gpio_unmask(unsigned int irq)
+static void sa1100_high_gpio_unmask(struct irq_data *d)
{
- unsigned int mask = GPIO11_27_MASK(irq);
+ unsigned int mask = GPIO11_27_MASK(d->irq);
GPIO_IRQ_mask |= mask;
@@ -166,44 +166,44 @@ static void sa1100_high_gpio_unmask(unsigned int irq)
GFER = GPIO_IRQ_falling_edge & GPIO_IRQ_mask;
}
-static int sa1100_high_gpio_wake(unsigned int irq, unsigned int on)
+static int sa1100_high_gpio_wake(struct irq_data *d, unsigned int on)
{
if (on)
- PWER |= GPIO11_27_MASK(irq);
+ PWER |= GPIO11_27_MASK(d->irq);
else
- PWER &= ~GPIO11_27_MASK(irq);
+ PWER &= ~GPIO11_27_MASK(d->irq);
return 0;
}
static struct irq_chip sa1100_high_gpio_chip = {
.name = "GPIO-h",
- .ack = sa1100_high_gpio_ack,
- .mask = sa1100_high_gpio_mask,
- .unmask = sa1100_high_gpio_unmask,
- .set_type = sa1100_gpio_type,
- .set_wake = sa1100_high_gpio_wake,
+ .irq_ack = sa1100_high_gpio_ack,
+ .irq_mask = sa1100_high_gpio_mask,
+ .irq_unmask = sa1100_high_gpio_unmask,
+ .irq_set_type = sa1100_gpio_type,
+ .irq_set_wake = sa1100_high_gpio_wake,
};
/*
* We don't need to ACK IRQs on the SA1100 unless they're GPIOs
* this is for internal IRQs i.e. from 11 to 31.
*/
-static void sa1100_mask_irq(unsigned int irq)
+static void sa1100_mask_irq(struct irq_data *d)
{
- ICMR &= ~(1 << irq);
+ ICMR &= ~(1 << d->irq);
}
-static void sa1100_unmask_irq(unsigned int irq)
+static void sa1100_unmask_irq(struct irq_data *d)
{
- ICMR |= (1 << irq);
+ ICMR |= (1 << d->irq);
}
/*
* Apart form GPIOs, only the RTC alarm can be a wakeup event.
*/
-static int sa1100_set_wake(unsigned int irq, unsigned int on)
+static int sa1100_set_wake(struct irq_data *d, unsigned int on)
{
- if (irq == IRQ_RTCAlrm) {
+ if (d->irq == IRQ_RTCAlrm) {
if (on)
PWER |= PWER_RTC;
else
@@ -215,10 +215,10 @@ static int sa1100_set_wake(unsigned int irq, unsigned int on)
static struct irq_chip sa1100_normal_chip = {
.name = "SC",
- .ack = sa1100_mask_irq,
- .mask = sa1100_mask_irq,
- .unmask = sa1100_unmask_irq,
- .set_wake = sa1100_set_wake,
+ .irq_ack = sa1100_mask_irq,
+ .irq_mask = sa1100_mask_irq,
+ .irq_unmask = sa1100_unmask_irq,
+ .irq_set_wake = sa1100_set_wake,
};
static struct resource irq_resource = {
diff --git a/arch/arm/mach-sa1100/neponset.c b/arch/arm/mach-sa1100/neponset.c
index c601a75..4aad01f 100644
--- a/arch/arm/mach-sa1100/neponset.c
+++ b/arch/arm/mach-sa1100/neponset.c
@@ -35,7 +35,7 @@ neponset_irq_handler(unsigned int irq, struct irq_desc *desc)
/*
* Acknowledge the parent IRQ.
*/
- desc->chip->ack(irq);
+ desc->irq_data.chip->irq_ack(&desc->irq_data);
/*
* Read the interrupt reason register. Let's have all
@@ -53,7 +53,7 @@ neponset_irq_handler(unsigned int irq, struct irq_desc *desc)
* recheck the register for any pending IRQs.
*/
if (irr & (IRR_ETHERNET | IRR_USAR)) {
- desc->chip->mask(irq);
+ desc->irq_data.chip->irq_mask(&desc->irq_data);
/*
* Ack the interrupt now to prevent re-entering
@@ -61,7 +61,7 @@ neponset_irq_handler(unsigned int irq, struct irq_desc *desc)
* since we'll check the IRR register prior to
* leaving.
*/
- desc->chip->ack(irq);
+ desc->irq_data.chip->irq_ack(&desc->irq_data);
if (irr & IRR_ETHERNET) {
generic_handle_irq(IRQ_NEPONSET_SMC9196);
@@ -71,7 +71,7 @@ neponset_irq_handler(unsigned int irq, struct irq_desc *desc)
generic_handle_irq(IRQ_NEPONSET_USAR);
}
- desc->chip->unmask(irq);
+ desc->irq_data.chip->irq_unmask(&desc->irq_data);
}
if (irr & IRR_SA1111) {
diff --git a/arch/arm/mach-shark/irq.c b/arch/arm/mach-shark/irq.c
index c04eb6a..831fc66 100644
--- a/arch/arm/mach-shark/irq.c
+++ b/arch/arm/mach-shark/irq.c
@@ -30,35 +30,35 @@ static unsigned char cached_irq_mask[2] = { 0xfb, 0xff };
* These have to be protected by the irq controller spinlock
* before being called.
*/
-static void shark_disable_8259A_irq(unsigned int irq)
+static void shark_disable_8259A_irq(struct irq_data *d)
{
unsigned int mask;
- if (irq<8) {
- mask = 1 << irq;
+ if (d->irq<8) {
+ mask = 1 << d->irq;
cached_irq_mask[0] |= mask;
outb(cached_irq_mask[1],0xA1);
} else {
- mask = 1 << (irq-8);
+ mask = 1 << (d->irq-8);
cached_irq_mask[1] |= mask;
outb(cached_irq_mask[0],0x21);
}
}
-static void shark_enable_8259A_irq(unsigned int irq)
+static void shark_enable_8259A_irq(struct irq_data *d)
{
unsigned int mask;
- if (irq<8) {
- mask = ~(1 << irq);
+ if (d->irq<8) {
+ mask = ~(1 << d->irq);
cached_irq_mask[0] &= mask;
outb(cached_irq_mask[0],0x21);
} else {
- mask = ~(1 << (irq-8));
+ mask = ~(1 << (d->irq-8));
cached_irq_mask[1] &= mask;
outb(cached_irq_mask[1],0xA1);
}
}
-static void shark_ack_8259A_irq(unsigned int irq){}
+static void shark_ack_8259A_irq(struct irq_data *d){}
static irqreturn_t bogus_int(int irq, void *dev_id)
{
@@ -69,10 +69,10 @@ static irqreturn_t bogus_int(int irq, void *dev_id)
static struct irqaction cascade;
static struct irq_chip fb_chip = {
- .name = "XT-PIC",
- .ack = shark_ack_8259A_irq,
- .mask = shark_disable_8259A_irq,
- .unmask = shark_enable_8259A_irq,
+ .name = "XT-PIC",
+ .irq_ack = shark_ack_8259A_irq,
+ .irq_mask = shark_disable_8259A_irq,
+ .irq_unmask = shark_enable_8259A_irq,
};
void __init shark_init_irq(void)
diff --git a/arch/arm/mach-stmp378x/stmp378x.c b/arch/arm/mach-stmp378x/stmp378x.c
index ddd49a7..c2f9fe04 100644
--- a/arch/arm/mach-stmp378x/stmp378x.c
+++ b/arch/arm/mach-stmp378x/stmp378x.c
@@ -47,7 +47,7 @@
/*
* IRQ handling
*/
-static void stmp378x_ack_irq(unsigned int irq)
+static void stmp378x_ack_irq(struct irq_data *d)
{
/* Tell ICOLL to release IRQ line */
__raw_writel(0, REGS_ICOLL_BASE + HW_ICOLL_VECTOR);
@@ -60,24 +60,24 @@ static void stmp378x_ack_irq(unsigned int irq)
(void)__raw_readl(REGS_ICOLL_BASE + HW_ICOLL_STAT);
}
-static void stmp378x_mask_irq(unsigned int irq)
+static void stmp378x_mask_irq(struct irq_data *d)
{
/* IRQ disable */
stmp3xxx_clearl(BM_ICOLL_INTERRUPTn_ENABLE,
- REGS_ICOLL_BASE + HW_ICOLL_INTERRUPTn + irq * 0x10);
+ REGS_ICOLL_BASE + HW_ICOLL_INTERRUPTn + d->irq * 0x10);
}
-static void stmp378x_unmask_irq(unsigned int irq)
+static void stmp378x_unmask_irq(struct irq_data *d)
{
/* IRQ enable */
stmp3xxx_setl(BM_ICOLL_INTERRUPTn_ENABLE,
- REGS_ICOLL_BASE + HW_ICOLL_INTERRUPTn + irq * 0x10);
+ REGS_ICOLL_BASE + HW_ICOLL_INTERRUPTn + d->irq * 0x10);
}
static struct irq_chip stmp378x_chip = {
- .ack = stmp378x_ack_irq,
- .mask = stmp378x_mask_irq,
- .unmask = stmp378x_unmask_irq,
+ .irq_ack = stmp378x_ack_irq,
+ .irq_mask = stmp378x_mask_irq,
+ .irq_unmask = stmp378x_unmask_irq,
};
void __init stmp378x_init_irq(void)
diff --git a/arch/arm/mach-stmp37xx/stmp37xx.c b/arch/arm/mach-stmp37xx/stmp37xx.c
index 8c7d6fb..a9aed06 100644
--- a/arch/arm/mach-stmp37xx/stmp37xx.c
+++ b/arch/arm/mach-stmp37xx/stmp37xx.c
@@ -43,11 +43,11 @@
/*
* IRQ handling
*/
-static void stmp37xx_ack_irq(unsigned int irq)
+static void stmp37xx_ack_irq(struct irq_data *d)
{
/* Disable IRQ */
- stmp3xxx_clearl(0x04 << ((irq % 4) * 8),
- REGS_ICOLL_BASE + HW_ICOLL_PRIORITYn + irq / 4 * 0x10);
+ stmp3xxx_clearl(0x04 << ((d->irq % 4) * 8),
+ REGS_ICOLL_BASE + HW_ICOLL_PRIORITYn + d->irq / 4 * 0x10);
/* ACK current interrupt */
__raw_writel(1, REGS_ICOLL_BASE + HW_ICOLL_LEVELACK);
@@ -56,24 +56,24 @@ static void stmp37xx_ack_irq(unsigned int irq)
(void)__raw_readl(REGS_ICOLL_BASE + HW_ICOLL_STAT);
}
-static void stmp37xx_mask_irq(unsigned int irq)
+static void stmp37xx_mask_irq(struct irq_data *d)
{
/* IRQ disable */
- stmp3xxx_clearl(0x04 << ((irq % 4) * 8),
- REGS_ICOLL_BASE + HW_ICOLL_PRIORITYn + irq / 4 * 0x10);
+ stmp3xxx_clearl(0x04 << ((d->irq % 4) * 8),
+ REGS_ICOLL_BASE + HW_ICOLL_PRIORITYn + d->irq / 4 * 0x10);
}
-static void stmp37xx_unmask_irq(unsigned int irq)
+static void stmp37xx_unmask_irq(struct irq_data *d)
{
/* IRQ enable */
- stmp3xxx_setl(0x04 << ((irq % 4) * 8),
- REGS_ICOLL_BASE + HW_ICOLL_PRIORITYn + irq / 4 * 0x10);
+ stmp3xxx_setl(0x04 << ((d->irq % 4) * 8),
+ REGS_ICOLL_BASE + HW_ICOLL_PRIORITYn + d->irq / 4 * 0x10);
}
static struct irq_chip stmp37xx_chip = {
- .ack = stmp37xx_ack_irq,
- .mask = stmp37xx_mask_irq,
- .unmask = stmp37xx_unmask_irq,
+ .irq_ack = stmp37xx_ack_irq,
+ .irq_mask = stmp37xx_mask_irq,
+ .irq_unmask = stmp37xx_unmask_irq,
};
void __init stmp37xx_init_irq(void)
diff --git a/arch/arm/mach-tcc8k/irq.c b/arch/arm/mach-tcc8k/irq.c
index 34575c4..aa9231f 100644
--- a/arch/arm/mach-tcc8k/irq.c
+++ b/arch/arm/mach-tcc8k/irq.c
@@ -18,65 +18,65 @@
#include "common.h"
/* Disable IRQ */
-static void tcc8000_mask_ack_irq0(unsigned int irq)
+static void tcc8000_mask_ack_irq0(struct irq_data *d)
{
- PIC0_IEN &= ~(1 << irq);
- PIC0_CREQ |= (1 << irq);
+ PIC0_IEN &= ~(1 << d->irq);
+ PIC0_CREQ |= (1 << d->irq);
}
-static void tcc8000_mask_ack_irq1(unsigned int irq)
+static void tcc8000_mask_ack_irq1(struct irq_data *d)
{
- PIC1_IEN &= ~(1 << (irq - 32));
- PIC1_CREQ |= (1 << (irq - 32));
+ PIC1_IEN &= ~(1 << (d->irq - 32));
+ PIC1_CREQ |= (1 << (d->irq - 32));
}
-static void tcc8000_mask_irq0(unsigned int irq)
+static void tcc8000_mask_irq0(struct irq_data *d)
{
- PIC0_IEN &= ~(1 << irq);
+ PIC0_IEN &= ~(1 << d->irq);
}
-static void tcc8000_mask_irq1(unsigned int irq)
+static void tcc8000_mask_irq1(struct irq_data *d)
{
- PIC1_IEN &= ~(1 << (irq - 32));
+ PIC1_IEN &= ~(1 << (d->irq - 32));
}
-static void tcc8000_ack_irq0(unsigned int irq)
+static void tcc8000_ack_irq0(struct irq_data *d)
{
- PIC0_CREQ |= (1 << irq);
+ PIC0_CREQ |= (1 << d->irq);
}
-static void tcc8000_ack_irq1(unsigned int irq)
+static void tcc8000_ack_irq1(struct irq_data *d)
{
- PIC1_CREQ |= (1 << (irq - 32));
+ PIC1_CREQ |= (1 << (d->irq - 32));
}
/* Enable IRQ */
-static void tcc8000_unmask_irq0(unsigned int irq)
+static void tcc8000_unmask_irq0(struct irq_data *d)
{
- PIC0_IEN |= (1 << irq);
- PIC0_INTOEN |= (1 << irq);
+ PIC0_IEN |= (1 << d->irq);
+ PIC0_INTOEN |= (1 << d->irq);
}
-static void tcc8000_unmask_irq1(unsigned int irq)
+static void tcc8000_unmask_irq1(struct irq_data *d)
{
- PIC1_IEN |= (1 << (irq - 32));
- PIC1_INTOEN |= (1 << (irq - 32));
+ PIC1_IEN |= (1 << (d->irq - 32));
+ PIC1_INTOEN |= (1 << (d->irq - 32));
}
static struct irq_chip tcc8000_irq_chip0 = {
.name = "tcc_irq0",
- .mask = tcc8000_mask_irq0,
- .ack = tcc8000_ack_irq0,
- .mask_ack = tcc8000_mask_ack_irq0,
- .unmask = tcc8000_unmask_irq0,
+ .irq_mask = tcc8000_mask_irq0,
+ .irq_ack = tcc8000_ack_irq0,
+ .irq_mask_ack = tcc8000_mask_ack_irq0,
+ .irq_unmask = tcc8000_unmask_irq0,
};
static struct irq_chip tcc8000_irq_chip1 = {
.name = "tcc_irq1",
- .mask = tcc8000_mask_irq1,
- .ack = tcc8000_ack_irq1,
- .mask_ack = tcc8000_mask_ack_irq1,
- .unmask = tcc8000_unmask_irq1,
+ .irq_mask = tcc8000_mask_irq1,
+ .irq_ack = tcc8000_ack_irq1,
+ .irq_mask_ack = tcc8000_mask_ack_irq1,
+ .irq_unmask = tcc8000_unmask_irq1,
};
void __init tcc8k_init_irq(void)
diff --git a/arch/arm/mach-tegra/gpio.c b/arch/arm/mach-tegra/gpio.c
index 0775265..bd06620 100644
--- a/arch/arm/mach-tegra/gpio.c
+++ b/arch/arm/mach-tegra/gpio.c
@@ -142,31 +142,31 @@ static struct gpio_chip tegra_gpio_chip = {
.ngpio = TEGRA_NR_GPIOS,
};
-static void tegra_gpio_irq_ack(unsigned int irq)
+static void tegra_gpio_irq_ack(struct irq_data *d)
{
- int gpio = irq - INT_GPIO_BASE;
+ int gpio = d->irq - INT_GPIO_BASE;
__raw_writel(1 << GPIO_BIT(gpio), GPIO_INT_CLR(gpio));
}
-static void tegra_gpio_irq_mask(unsigned int irq)
+static void tegra_gpio_irq_mask(struct irq_data *d)
{
- int gpio = irq - INT_GPIO_BASE;
+ int gpio = d->irq - INT_GPIO_BASE;
tegra_gpio_mask_write(GPIO_MSK_INT_ENB(gpio), gpio, 0);
}
-static void tegra_gpio_irq_unmask(unsigned int irq)
+static void tegra_gpio_irq_unmask(struct irq_data *d)
{
- int gpio = irq - INT_GPIO_BASE;
+ int gpio = d->irq - INT_GPIO_BASE;
tegra_gpio_mask_write(GPIO_MSK_INT_ENB(gpio), gpio, 1);
}
-static int tegra_gpio_irq_set_type(unsigned int irq, unsigned int type)
+static int tegra_gpio_irq_set_type(struct irq_data *d, unsigned int type)
{
- int gpio = irq - INT_GPIO_BASE;
- struct tegra_gpio_bank *bank = get_irq_chip_data(irq);
+ int gpio = d->irq - INT_GPIO_BASE;
+ struct tegra_gpio_bank *bank = irq_data_get_irq_chip_data(d);
int port = GPIO_PORT(gpio);
int lvl_type;
int val;
@@ -221,7 +221,7 @@ static void tegra_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
int pin;
int unmasked = 0;
- desc->chip->ack(irq);
+ desc->irq_data.chip->irq_ack(&desc->irq_data);
bank = get_irq_data(irq);
@@ -240,7 +240,7 @@ static void tegra_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
*/
if (lvl & (0x100 << pin)) {
unmasked = 1;
- desc->chip->unmask(irq);
+ desc->irq_data.chip->irq_unmask(&desc->irq_data);
}
generic_handle_irq(gpio_to_irq(gpio + pin));
@@ -248,7 +248,7 @@ static void tegra_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
}
if (!unmasked)
- desc->chip->unmask(irq);
+ desc->irq_data.chip->irq_unmask(&desc->irq_data);
}
@@ -316,21 +316,21 @@ void tegra_gpio_suspend(void)
local_irq_restore(flags);
}
-static int tegra_gpio_wake_enable(unsigned int irq, unsigned int enable)
+static int tegra_gpio_wake_enable(struct irq_data *d, unsigned int enable)
{
- struct tegra_gpio_bank *bank = get_irq_chip_data(irq);
+ struct tegra_gpio_bank *bank = irq_data_get_irq_chip_data(d);
return set_irq_wake(bank->irq, enable);
}
#endif
static struct irq_chip tegra_gpio_irq_chip = {
.name = "GPIO",
- .ack = tegra_gpio_irq_ack,
- .mask = tegra_gpio_irq_mask,
- .unmask = tegra_gpio_irq_unmask,
- .set_type = tegra_gpio_irq_set_type,
+ .irq_ack = tegra_gpio_irq_ack,
+ .irq_mask = tegra_gpio_irq_mask,
+ .irq_unmask = tegra_gpio_irq_unmask,
+ .irq_set_type = tegra_gpio_irq_set_type,
#ifdef CONFIG_PM
- .set_wake = tegra_gpio_wake_enable,
+ .irq_set_wake = tegra_gpio_wake_enable,
#endif
};
diff --git a/arch/arm/mach-tegra/hotplug.c b/arch/arm/mach-tegra/hotplug.c
index a5cb1ce..f329404 100644
--- a/arch/arm/mach-tegra/hotplug.c
+++ b/arch/arm/mach-tegra/hotplug.c
@@ -26,10 +26,10 @@ static inline void cpu_enter_lowpower(void)
* Turn off coherency
*/
" mrc p15, 0, %0, c1, c0, 1\n"
- " bic %0, %0, %2\n"
+ " bic %0, %0, #0x20\n"
" mcr p15, 0, %0, c1, c0, 1\n"
" mrc p15, 0, %0, c1, c0, 0\n"
- " bic %0, %0, #0x04\n"
+ " bic %0, %0, %2\n"
" mcr p15, 0, %0, c1, c0, 0\n"
: "=&r" (v)
: "r" (0), "Ir" (CR_C)
diff --git a/arch/arm/mach-tegra/irq.c b/arch/arm/mach-tegra/irq.c
index 5407de0..de7dfad 100644
--- a/arch/arm/mach-tegra/irq.c
+++ b/arch/arm/mach-tegra/irq.c
@@ -46,30 +46,30 @@
#define ICTLR_COP_IER_CLR 0x38
#define ICTLR_COP_IEP_CLASS 0x3c
-static void (*gic_mask_irq)(unsigned int irq);
-static void (*gic_unmask_irq)(unsigned int irq);
+static void (*gic_mask_irq)(struct irq_data *d);
+static void (*gic_unmask_irq)(struct irq_data *d);
#define irq_to_ictlr(irq) (((irq)-32) >> 5)
static void __iomem *tegra_ictlr_base = IO_ADDRESS(TEGRA_PRIMARY_ICTLR_BASE);
#define ictlr_to_virt(ictlr) (tegra_ictlr_base + (ictlr)*0x100)
-static void tegra_mask(unsigned int irq)
+static void tegra_mask(struct irq_data *d)
{
- void __iomem *addr = ictlr_to_virt(irq_to_ictlr(irq));
- gic_mask_irq(irq);
- writel(1<<(irq&31), addr+ICTLR_CPU_IER_CLR);
+ void __iomem *addr = ictlr_to_virt(irq_to_ictlr(d->irq));
+ gic_mask_irq(d);
+ writel(1<<(d->irq&31), addr+ICTLR_CPU_IER_CLR);
}
-static void tegra_unmask(unsigned int irq)
+static void tegra_unmask(struct irq_data *d)
{
- void __iomem *addr = ictlr_to_virt(irq_to_ictlr(irq));
- gic_unmask_irq(irq);
- writel(1<<(irq&31), addr+ICTLR_CPU_IER_SET);
+ void __iomem *addr = ictlr_to_virt(irq_to_ictlr(d->irq));
+ gic_unmask_irq(d);
+ writel(1<<(d->irq&31), addr+ICTLR_CPU_IER_SET);
}
#ifdef CONFIG_PM
-static int tegra_set_wake(unsigned int irq, unsigned int on)
+static int tegra_set_wake(struct irq_data *d, unsigned int on)
{
return 0;
}
@@ -77,10 +77,10 @@ static int tegra_set_wake(unsigned int irq, unsigned int on)
static struct irq_chip tegra_irq = {
.name = "PPI",
- .mask = tegra_mask,
- .unmask = tegra_unmask,
+ .irq_mask = tegra_mask,
+ .irq_unmask = tegra_unmask,
#ifdef CONFIG_PM
- .set_wake = tegra_set_wake,
+ .irq_set_wake = tegra_set_wake,
#endif
};
@@ -98,11 +98,11 @@ void __init tegra_init_irq(void)
IO_ADDRESS(TEGRA_ARM_PERIF_BASE + 0x100));
gic = get_irq_chip(29);
- gic_unmask_irq = gic->unmask;
- gic_mask_irq = gic->mask;
- tegra_irq.ack = gic->ack;
+ gic_unmask_irq = gic->irq_unmask;
+ gic_mask_irq = gic->irq_mask;
+ tegra_irq.irq_ack = gic->irq_ack;
#ifdef CONFIG_SMP
- tegra_irq.set_affinity = gic->set_affinity;
+ tegra_irq.irq_set_affinity = gic->irq_set_affinity;
#endif
for (i = INT_PRI_BASE; i < INT_GPIO_BASE; i++) {
diff --git a/arch/arm/mach-versatile/core.c b/arch/arm/mach-versatile/core.c
index 13a83e4..136c32e 100644
--- a/arch/arm/mach-versatile/core.c
+++ b/arch/arm/mach-versatile/core.c
@@ -63,23 +63,25 @@
#define VA_VIC_BASE __io_address(VERSATILE_VIC_BASE)
#define VA_SIC_BASE __io_address(VERSATILE_SIC_BASE)
-static void sic_mask_irq(unsigned int irq)
+static void sic_mask_irq(struct irq_data *d)
{
- irq -= IRQ_SIC_START;
+ unsigned int irq = d->irq - IRQ_SIC_START;
+
writel(1 << irq, VA_SIC_BASE + SIC_IRQ_ENABLE_CLEAR);
}
-static void sic_unmask_irq(unsigned int irq)
+static void sic_unmask_irq(struct irq_data *d)
{
- irq -= IRQ_SIC_START;
+ unsigned int irq = d->irq - IRQ_SIC_START;
+
writel(1 << irq, VA_SIC_BASE + SIC_IRQ_ENABLE_SET);
}
static struct irq_chip sic_chip = {
- .name = "SIC",
- .ack = sic_mask_irq,
- .mask = sic_mask_irq,
- .unmask = sic_unmask_irq,
+ .name = "SIC",
+ .irq_ack = sic_mask_irq,
+ .irq_mask = sic_mask_irq,
+ .irq_unmask = sic_unmask_irq,
};
static void
diff --git a/arch/arm/mach-w90x900/irq.c b/arch/arm/mach-w90x900/irq.c
index 0ce9d8e..9c35010 100644
--- a/arch/arm/mach-w90x900/irq.c
+++ b/arch/arm/mach-w90x900/irq.c
@@ -92,15 +92,15 @@ static void nuc900_group_enable(struct group_irq *gpirq, int enable)
__raw_writel(regval, REG_AIC_GEN);
}
-static void nuc900_irq_mask(unsigned int irq)
+static void nuc900_irq_mask(struct irq_data *d)
{
struct group_irq *group_irq;
group_irq = NULL;
- __raw_writel(1 << irq, REG_AIC_MDCR);
+ __raw_writel(1 << d->irq, REG_AIC_MDCR);
- switch (irq) {
+ switch (d->irq) {
case IRQ_GROUP0:
group_irq = &group_nirq0;
break;
@@ -143,20 +143,20 @@ static void nuc900_irq_mask(unsigned int irq)
* to REG_AIC_EOSCR for ACK
*/
-static void nuc900_irq_ack(unsigned int irq)
+static void nuc900_irq_ack(struct irq_data *d)
{
__raw_writel(0x01, REG_AIC_EOSCR);
}
-static void nuc900_irq_unmask(unsigned int irq)
+static void nuc900_irq_unmask(struct irq_data *d)
{
struct group_irq *group_irq;
group_irq = NULL;
- __raw_writel(1 << irq, REG_AIC_MECR);
+ __raw_writel(1 << d->irq, REG_AIC_MECR);
- switch (irq) {
+ switch (d->irq) {
case IRQ_GROUP0:
group_irq = &group_nirq0;
break;
@@ -195,9 +195,9 @@ static void nuc900_irq_unmask(unsigned int irq)
}
static struct irq_chip nuc900_irq_chip = {
- .ack = nuc900_irq_ack,
- .mask = nuc900_irq_mask,
- .unmask = nuc900_irq_unmask,
+ .irq_ack = nuc900_irq_ack,
+ .irq_mask = nuc900_irq_mask,
+ .irq_unmask = nuc900_irq_unmask,
};
void __init nuc900_init_irq(void)
diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig
index fcc1e62..9d30c6f 100644
--- a/arch/arm/mm/Kconfig
+++ b/arch/arm/mm/Kconfig
@@ -644,7 +644,7 @@ config ARM_THUMBEE
config SWP_EMULATE
bool "Emulate SWP/SWPB instructions"
- depends on CPU_V7
+ depends on CPU_V7 && !CPU_V6
select HAVE_PROC_CPU if PROC_FS
default y if SMP
help
diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c
index 6b48e0a..4771dba 100644
--- a/arch/arm/mm/dma-mapping.c
+++ b/arch/arm/mm/dma-mapping.c
@@ -577,7 +577,7 @@ EXPORT_SYMBOL(dma_map_sg);
* 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 (returned from dma_map_sg)
+ * @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
diff --git a/arch/arm/mm/proc-v7.S b/arch/arm/mm/proc-v7.S
index b49fab2..0c1172b 100644
--- a/arch/arm/mm/proc-v7.S
+++ b/arch/arm/mm/proc-v7.S
@@ -159,7 +159,9 @@ ENTRY(cpu_v7_set_pte_ext)
tstne r1, #L_PTE_PRESENT
moveq r3, #0
- str r3, [r0, #2048]!
+ ARM( str r3, [r0, #2048]! )
+ THUMB( add r0, r0, #2048 )
+ THUMB( str r3, [r0] )
mcr p15, 0, r0, c7, c10, 1 @ flush_pte
#endif
mov pc, lr
diff --git a/arch/arm/plat-mxc/3ds_debugboard.c b/arch/arm/plat-mxc/3ds_debugboard.c
index 639c54a..c856fa3 100644
--- a/arch/arm/plat-mxc/3ds_debugboard.c
+++ b/arch/arm/plat-mxc/3ds_debugboard.c
@@ -60,7 +60,6 @@
#define EXPIO_INT_BUTTON_B (MXC_BOARD_IRQ_START + 4)
static void __iomem *brd_io;
-static void expio_ack_irq(u32 irq);
static struct resource smsc911x_resources[] = {
{
@@ -93,7 +92,8 @@ static void mxc_expio_irq_handler(u32 irq, struct irq_desc *desc)
u32 int_valid;
u32 expio_irq;
- desc->chip->mask(irq); /* irq = gpio irq number */
+ /* irq = gpio irq number */
+ desc->irq_data.chip->irq_mask(&desc->irq_data);
imr_val = __raw_readw(brd_io + INTR_MASK_REG);
int_valid = __raw_readw(brd_io + INTR_STATUS_REG) & ~imr_val;
@@ -110,37 +110,37 @@ static void mxc_expio_irq_handler(u32 irq, struct irq_desc *desc)
d->handle_irq(expio_irq, d);
}
- desc->chip->ack(irq);
- desc->chip->unmask(irq);
+ desc->irq_data.chip->irq_ack(&desc->irq_data);
+ desc->irq_data.chip->irq_unmask(&desc->irq_data);
}
/*
* Disable an expio pin's interrupt by setting the bit in the imr.
* Irq is an expio virtual irq number
*/
-static void expio_mask_irq(u32 irq)
+static void expio_mask_irq(struct irq_data *d)
{
u16 reg;
- u32 expio = MXC_IRQ_TO_EXPIO(irq);
+ u32 expio = MXC_IRQ_TO_EXPIO(d->irq);
reg = __raw_readw(brd_io + INTR_MASK_REG);
reg |= (1 << expio);
__raw_writew(reg, brd_io + INTR_MASK_REG);
}
-static void expio_ack_irq(u32 irq)
+static void expio_ack_irq(struct irq_data *d)
{
- u32 expio = MXC_IRQ_TO_EXPIO(irq);
+ u32 expio = MXC_IRQ_TO_EXPIO(d->irq);
__raw_writew(1 << expio, brd_io + INTR_RESET_REG);
__raw_writew(0, brd_io + INTR_RESET_REG);
- expio_mask_irq(irq);
+ expio_mask_irq(d);
}
-static void expio_unmask_irq(u32 irq)
+static void expio_unmask_irq(struct irq_data *d)
{
u16 reg;
- u32 expio = MXC_IRQ_TO_EXPIO(irq);
+ u32 expio = MXC_IRQ_TO_EXPIO(d->irq);
reg = __raw_readw(brd_io + INTR_MASK_REG);
reg &= ~(1 << expio);
@@ -148,9 +148,9 @@ static void expio_unmask_irq(u32 irq)
}
static struct irq_chip expio_irq_chip = {
- .ack = expio_ack_irq,
- .mask = expio_mask_irq,
- .unmask = expio_unmask_irq,
+ .irq_ack = expio_ack_irq,
+ .irq_mask = expio_mask_irq,
+ .irq_unmask = expio_unmask_irq,
};
int __init mxc_expio_init(u32 base, u32 p_irq)
diff --git a/arch/arm/plat-mxc/avic.c b/arch/arm/plat-mxc/avic.c
index 9a4e8a2..deb284b 100644
--- a/arch/arm/plat-mxc/avic.c
+++ b/arch/arm/plat-mxc/avic.c
@@ -89,22 +89,22 @@ static int avic_set_irq_fiq(unsigned int irq, unsigned int type)
#endif /* CONFIG_FIQ */
/* Disable interrupt number "irq" in the AVIC */
-static void mxc_mask_irq(unsigned int irq)
+static void mxc_mask_irq(struct irq_data *d)
{
- __raw_writel(irq, avic_base + AVIC_INTDISNUM);
+ __raw_writel(d->irq, avic_base + AVIC_INTDISNUM);
}
/* Enable interrupt number "irq" in the AVIC */
-static void mxc_unmask_irq(unsigned int irq)
+static void mxc_unmask_irq(struct irq_data *d)
{
- __raw_writel(irq, avic_base + AVIC_INTENNUM);
+ __raw_writel(d->irq, avic_base + AVIC_INTENNUM);
}
static struct mxc_irq_chip mxc_avic_chip = {
.base = {
- .ack = mxc_mask_irq,
- .mask = mxc_mask_irq,
- .unmask = mxc_unmask_irq,
+ .irq_ack = mxc_mask_irq,
+ .irq_mask = mxc_mask_irq,
+ .irq_unmask = mxc_unmask_irq,
},
#ifdef CONFIG_MXC_IRQ_PRIOR
.set_priority = avic_irq_set_priority,
diff --git a/arch/arm/plat-mxc/devices/Kconfig b/arch/arm/plat-mxc/devices/Kconfig
index 2537166..b9ab1d5 100644
--- a/arch/arm/plat-mxc/devices/Kconfig
+++ b/arch/arm/plat-mxc/devices/Kconfig
@@ -1,6 +1,6 @@
config IMX_HAVE_PLATFORM_FEC
bool
- default y if ARCH_MX25 || SOC_IMX27 || SOC_IMX35 || SOC_IMX51
+ default y if ARCH_MX25 || SOC_IMX27 || SOC_IMX35 || SOC_IMX51 || SOC_IMX53
config IMX_HAVE_PLATFORM_FLEXCAN
select HAVE_CAN_FLEXCAN if CAN
diff --git a/arch/arm/plat-mxc/devices/platform-fec.c b/arch/arm/plat-mxc/devices/platform-fec.c
index 269ec78..b50c351 100644
--- a/arch/arm/plat-mxc/devices/platform-fec.c
+++ b/arch/arm/plat-mxc/devices/platform-fec.c
@@ -36,6 +36,11 @@ const struct imx_fec_data imx51_fec_data __initconst =
imx_fec_data_entry_single(MX51);
#endif
+#ifdef CONFIG_SOC_IMX53
+const struct imx_fec_data imx53_fec_data __initconst =
+ imx_fec_data_entry_single(MX53);
+#endif
+
struct platform_device *__init imx_add_fec(
const struct imx_fec_data *data,
const struct fec_platform_data *pdata)
diff --git a/arch/arm/plat-mxc/devices/platform-imx-i2c.c b/arch/arm/plat-mxc/devices/platform-imx-i2c.c
index 72ba880..7ba94e1 100644
--- a/arch/arm/plat-mxc/devices/platform-imx-i2c.c
+++ b/arch/arm/plat-mxc/devices/platform-imx-i2c.c
@@ -78,6 +78,15 @@ const struct imx_imx_i2c_data imx51_imx_i2c_data[] __initconst = {
};
#endif /* ifdef CONFIG_SOC_IMX51 */
+#ifdef CONFIG_SOC_IMX53
+const struct imx_imx_i2c_data imx53_imx_i2c_data[] __initconst = {
+#define imx53_imx_i2c_data_entry(_id, _hwid) \
+ imx_imx_i2c_data_entry(MX53, _id, _hwid, SZ_4K)
+ imx53_imx_i2c_data_entry(0, 1),
+ imx53_imx_i2c_data_entry(1, 2),
+};
+#endif /* ifdef CONFIG_SOC_IMX51 */
+
struct platform_device *__init imx_add_imx_i2c(
const struct imx_imx_i2c_data *data,
const struct imxi2c_platform_data *pdata)
diff --git a/arch/arm/plat-mxc/devices/platform-imx-keypad.c b/arch/arm/plat-mxc/devices/platform-imx-keypad.c
index 40238f0..2636611 100644
--- a/arch/arm/plat-mxc/devices/platform-imx-keypad.c
+++ b/arch/arm/plat-mxc/devices/platform-imx-keypad.c
@@ -41,6 +41,11 @@ const struct imx_imx_keypad_data imx35_imx_keypad_data __initconst =
imx_imx_keypad_data_entry_single(MX35, SZ_16);
#endif /* ifdef CONFIG_SOC_IMX35 */
+#ifdef CONFIG_SOC_IMX51
+const struct imx_imx_keypad_data imx51_imx_keypad_data __initconst =
+ imx_imx_keypad_data_entry_single(MX51, SZ_16);
+#endif /* ifdef CONFIG_SOC_IMX51 */
+
struct platform_device *__init imx_add_imx_keypad(
const struct imx_imx_keypad_data *data,
const struct matrix_keymap_data *pdata)
diff --git a/arch/arm/plat-mxc/devices/platform-mxc_pwm.c b/arch/arm/plat-mxc/devices/platform-mxc_pwm.c
index 3d8ebdb..b0c4ae2 100644
--- a/arch/arm/plat-mxc/devices/platform-mxc_pwm.c
+++ b/arch/arm/plat-mxc/devices/platform-mxc_pwm.c
@@ -40,6 +40,15 @@ const struct imx_mxc_pwm_data imx27_mxc_pwm_data __initconst =
imx_mxc_pwm_data_entry_single(MX27, 0, , SZ_4K);
#endif /* ifdef CONFIG_SOC_IMX27 */
+#ifdef CONFIG_SOC_IMX51
+const struct imx_mxc_pwm_data imx51_mxc_pwm_data[] __initconst = {
+#define imx51_mxc_pwm_data_entry(_id, _hwid) \
+ imx_mxc_pwm_data_entry(MX51, _id, _hwid, SZ_16K)
+ imx51_mxc_pwm_data_entry(0, 1),
+ imx51_mxc_pwm_data_entry(1, 2),
+};
+#endif /* ifdef CONFIG_SOC_IMX51 */
+
struct platform_device *__init imx_add_mxc_pwm(
const struct imx_mxc_pwm_data *data)
{
diff --git a/arch/arm/plat-mxc/devices/platform-sdhci-esdhc-imx.c b/arch/arm/plat-mxc/devices/platform-sdhci-esdhc-imx.c
index b352564..6b2940b 100644
--- a/arch/arm/plat-mxc/devices/platform-sdhci-esdhc-imx.c
+++ b/arch/arm/plat-mxc/devices/platform-sdhci-esdhc-imx.c
@@ -53,6 +53,18 @@ imx51_sdhci_esdhc_imx_data[] __initconst = {
};
#endif /* ifdef CONFIG_SOC_IMX51 */
+#ifdef CONFIG_SOC_IMX53
+const struct imx_sdhci_esdhc_imx_data
+imx53_sdhci_esdhc_imx_data[] __initconst = {
+#define imx53_sdhci_esdhc_imx_data_entry(_id, _hwid) \
+ imx_sdhci_esdhc_imx_data_entry(MX53, _id, _hwid)
+ imx53_sdhci_esdhc_imx_data_entry(0, 1),
+ imx53_sdhci_esdhc_imx_data_entry(1, 2),
+ imx53_sdhci_esdhc_imx_data_entry(2, 3),
+ imx53_sdhci_esdhc_imx_data_entry(3, 4),
+};
+#endif /* ifdef CONFIG_SOC_IMX53 */
+
struct platform_device *__init imx_add_sdhci_esdhc_imx(
const struct imx_sdhci_esdhc_imx_data *data,
const struct esdhc_platform_data *pdata)
diff --git a/arch/arm/plat-mxc/devices/platform-spi_imx.c b/arch/arm/plat-mxc/devices/platform-spi_imx.c
index 8ea49ad..013c85f 100644
--- a/arch/arm/plat-mxc/devices/platform-spi_imx.c
+++ b/arch/arm/plat-mxc/devices/platform-spi_imx.c
@@ -81,6 +81,18 @@ const struct imx_spi_imx_data imx51_ecspi_data[] __initconst = {
};
#endif /* ifdef CONFIG_SOC_IMX51 */
+#ifdef CONFIG_SOC_IMX53
+const struct imx_spi_imx_data imx53_cspi_data __initconst =
+ imx_spi_imx_data_entry_single(MX53, CSPI, "imx53-cspi", 0, , SZ_4K);
+
+const struct imx_spi_imx_data imx53_ecspi_data[] __initconst = {
+#define imx53_ecspi_data_entry(_id, _hwid) \
+ imx_spi_imx_data_entry(MX53, ECSPI, "imx53-ecspi", _id, _hwid, SZ_4K)
+ imx53_ecspi_data_entry(0, 1),
+ imx53_ecspi_data_entry(1, 2),
+};
+#endif /* ifdef CONFIG_SOC_IMX53 */
+
struct platform_device *__init imx_add_spi_imx(
const struct imx_spi_imx_data *data,
const struct spi_imx_master *pdata)
diff --git a/arch/arm/plat-mxc/gpio.c b/arch/arm/plat-mxc/gpio.c
index bc2c7bc..d17b3c9 100644
--- a/arch/arm/plat-mxc/gpio.c
+++ b/arch/arm/plat-mxc/gpio.c
@@ -63,29 +63,29 @@ static void _set_gpio_irqenable(struct mxc_gpio_port *port, u32 index,
__raw_writel(l, port->base + GPIO_IMR);
}
-static void gpio_ack_irq(u32 irq)
+static void gpio_ack_irq(struct irq_data *d)
{
- u32 gpio = irq_to_gpio(irq);
+ u32 gpio = irq_to_gpio(d->irq);
_clear_gpio_irqstatus(&mxc_gpio_ports[gpio / 32], gpio & 0x1f);
}
-static void gpio_mask_irq(u32 irq)
+static void gpio_mask_irq(struct irq_data *d)
{
- u32 gpio = irq_to_gpio(irq);
+ u32 gpio = irq_to_gpio(d->irq);
_set_gpio_irqenable(&mxc_gpio_ports[gpio / 32], gpio & 0x1f, 0);
}
-static void gpio_unmask_irq(u32 irq)
+static void gpio_unmask_irq(struct irq_data *d)
{
- u32 gpio = irq_to_gpio(irq);
+ u32 gpio = irq_to_gpio(d->irq);
_set_gpio_irqenable(&mxc_gpio_ports[gpio / 32], gpio & 0x1f, 1);
}
static int mxc_gpio_get(struct gpio_chip *chip, unsigned offset);
-static int gpio_set_irq_type(u32 irq, u32 type)
+static int gpio_set_irq_type(struct irq_data *d, u32 type)
{
- u32 gpio = irq_to_gpio(irq);
+ u32 gpio = irq_to_gpio(d->irq);
struct mxc_gpio_port *port = &mxc_gpio_ports[gpio / 32];
u32 bit, val;
int edge;
@@ -211,9 +211,9 @@ static void mx2_gpio_irq_handler(u32 irq, struct irq_desc *desc)
* @param enable enable as wake-up if equal to non-zero
* @return This function returns 0 on success.
*/
-static int gpio_set_wake_irq(u32 irq, u32 enable)
+static int gpio_set_wake_irq(struct irq_data *d, u32 enable)
{
- u32 gpio = irq_to_gpio(irq);
+ u32 gpio = irq_to_gpio(d->irq);
u32 gpio_idx = gpio & 0x1F;
struct mxc_gpio_port *port = &mxc_gpio_ports[gpio / 32];
@@ -233,11 +233,11 @@ static int gpio_set_wake_irq(u32 irq, u32 enable)
}
static struct irq_chip gpio_irq_chip = {
- .ack = gpio_ack_irq,
- .mask = gpio_mask_irq,
- .unmask = gpio_unmask_irq,
- .set_type = gpio_set_irq_type,
- .set_wake = gpio_set_wake_irq,
+ .irq_ack = gpio_ack_irq,
+ .irq_mask = gpio_mask_irq,
+ .irq_unmask = gpio_unmask_irq,
+ .irq_set_type = gpio_set_irq_type,
+ .irq_set_wake = gpio_set_wake_irq,
};
static void _set_gpio_direction(struct gpio_chip *chip, unsigned offset,
diff --git a/arch/arm/plat-mxc/include/mach/iomux-mx53.h b/arch/arm/plat-mxc/include/mach/iomux-mx53.h
index 5deee01..68e11d7 100644
--- a/arch/arm/plat-mxc/include/mach/iomux-mx53.h
+++ b/arch/arm/plat-mxc/include/mach/iomux-mx53.h
@@ -34,7 +34,6 @@ typedef enum iomux_config {
IOMUX_CONFIG_ALT6,
IOMUX_CONFIG_ALT7,
IOMUX_CONFIG_GPIO, /* added to help user use GPIO mode */
- IOMUX_CONFIG_SION = 0x1 << 4, /* LOOPBACK:MUX SION bit */
} iomux_pin_cfg_t;
/* These 2 defines are for pins that may not have a mux register, but could
@@ -135,6 +134,9 @@ typedef enum iomux_config {
#define MX53_PAD_EIM_D16__GPIO_3_16 IOMUX_PAD(0x460, 0x118,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
#define MX53_PAD_EIM_D17__GPIO_3_17 IOMUX_PAD(0x464, 0x11C,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
#define MX53_PAD_EIM_D18__GPIO_3_18 IOMUX_PAD(0x468, 0x120,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
+#define MX53_PAD_EIM_D16__CSPI1_SCLK IOMUX_PAD(0x460, 0x118,IOMUX_CONFIG_ALT4, 0x79c, 3, NO_PAD_CTRL)
+#define MX53_PAD_EIM_D17__CSPI1_MISO IOMUX_PAD(0x464, 0x11C,IOMUX_CONFIG_ALT4, 0x7a0, 3, NO_PAD_CTRL)
+#define MX53_PAD_EIM_D18__CSPI1_MOSI IOMUX_PAD(0x468, 0x120,IOMUX_CONFIG_ALT4, 0x7a4, 3, NO_PAD_CTRL)
#define MX53_PAD_EIM_D19__GPIO_3_19 IOMUX_PAD(0x46C, 0x124,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
#define MX53_PAD_EIM_D20__GPIO_3_20 IOMUX_PAD(0x470, 0x128,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
#define MX53_PAD_EIM_D21__GPIO_3_21 IOMUX_PAD(0x474, 0x12C,IOMUX_CONFIG_ALT1, 0x0, 0, NO_PAD_CTRL)
diff --git a/arch/arm/plat-mxc/include/mach/iomux-v3.h b/arch/arm/plat-mxc/include/mach/iomux-v3.h
index 2277b01..82620af 100644
--- a/arch/arm/plat-mxc/include/mach/iomux-v3.h
+++ b/arch/arm/plat-mxc/include/mach/iomux-v3.h
@@ -105,6 +105,7 @@ typedef u64 iomux_v3_cfg_t;
#define PAD_CTL_SRE_FAST (1 << 0)
#define PAD_CTL_SRE_SLOW (0 << 0)
+#define IOMUX_CONFIG_SION (0x1 << 4)
#define MX51_NUM_GPIO_PORT 4
diff --git a/arch/arm/plat-mxc/include/mach/mx51.h b/arch/arm/plat-mxc/include/mach/mx51.h
index 873807f..1eb339e 100644
--- a/arch/arm/plat-mxc/include/mach/mx51.h
+++ b/arch/arm/plat-mxc/include/mach/mx51.h
@@ -301,8 +301,8 @@
#define MX51_MXC_INT_GPIO4_HIGH 57
#define MX51_MXC_INT_WDOG1 58
#define MX51_MXC_INT_WDOG2 59
-#define MX51_MXC_INT_KPP 60
-#define MX51_MXC_INT_PWM1 61
+#define MX51_INT_KPP 60
+#define MX51_INT_PWM1 61
#define MX51_INT_I2C1 62
#define MX51_INT_I2C2 63
#define MX51_MXC_INT_HS_I2C 64
@@ -335,7 +335,7 @@
#define MX51_MXC_INT_SPDIF 91
#define MX51_MXC_INT_TVE 92
#define MX51_MXC_INT_FIRI 93
-#define MX51_MXC_INT_PWM2 94
+#define MX51_INT_PWM2 94
#define MX51_MXC_INT_SLIM_EXP 95
#define MX51_INT_SSI3 96
#define MX51_MXC_INT_EMI_BOOT 97
diff --git a/arch/arm/plat-mxc/include/mach/mx53.h b/arch/arm/plat-mxc/include/mach/mx53.h
index 9577cdb..d7a8e52 100644
--- a/arch/arm/plat-mxc/include/mach/mx53.h
+++ b/arch/arm/plat-mxc/include/mach/mx53.h
@@ -53,13 +53,13 @@
#define MX53_SPBA0_BASE_ADDR 0x50000000
#define MX53_SPBA0_SIZE SZ_1M
-#define MX53_MMC_SDHC1_BASE_ADDR (MX53_SPBA0_BASE_ADDR + 0x00004000)
-#define MX53_MMC_SDHC2_BASE_ADDR (MX53_SPBA0_BASE_ADDR + 0x00008000)
+#define MX53_ESDHC1_BASE_ADDR (MX53_SPBA0_BASE_ADDR + 0x00004000)
+#define MX53_ESDHC2_BASE_ADDR (MX53_SPBA0_BASE_ADDR + 0x00008000)
#define MX53_UART3_BASE_ADDR (MX53_SPBA0_BASE_ADDR + 0x0000C000)
-#define MX53_CSPI1_BASE_ADDR (MX53_SPBA0_BASE_ADDR + 0x00010000)
+#define MX53_ECSPI1_BASE_ADDR (MX53_SPBA0_BASE_ADDR + 0x00010000)
#define MX53_SSI2_BASE_ADDR (MX53_SPBA0_BASE_ADDR + 0x00014000)
-#define MX53_MMC_SDHC3_BASE_ADDR (MX53_SPBA0_BASE_ADDR + 0x00020000)
-#define MX53_MMC_SDHC4_BASE_ADDR (MX53_SPBA0_BASE_ADDR + 0x00024000)
+#define MX53_ESDHC3_BASE_ADDR (MX53_SPBA0_BASE_ADDR + 0x00020000)
+#define MX53_ESDHC4_BASE_ADDR (MX53_SPBA0_BASE_ADDR + 0x00024000)
#define MX53_SPDIF_BASE_ADDR (MX53_SPBA0_BASE_ADDR + 0x00028000)
#define MX53_ASRC_BASE_ADDR (MX53_SPBA0_BASE_ADDR + 0x0002C000)
#define MX53_ATA_DMA_BASE_ADDR (MX53_SPBA0_BASE_ADDR + 0x00030000)
@@ -117,12 +117,12 @@
#define MX53_ARM_BASE_ADDR (MX53_AIPS2_BASE_ADDR + 0x000A0000)
#define MX53_OWIRE_BASE_ADDR (MX53_AIPS2_BASE_ADDR + 0x000A4000)
#define MX53_FIRI_BASE_ADDR (MX53_AIPS2_BASE_ADDR + 0x000A8000)
-#define MX53_CSPI2_BASE_ADDR (MX53_AIPS2_BASE_ADDR + 0x000AC000)
+#define MX53_ECSPI2_BASE_ADDR (MX53_AIPS2_BASE_ADDR + 0x000AC000)
#define MX53_SDMA_BASE_ADDR (MX53_AIPS2_BASE_ADDR + 0x000B0000)
#define MX53_SCC_BASE_ADDR (MX53_AIPS2_BASE_ADDR + 0x000B4000)
#define MX53_ROMCP_BASE_ADDR (MX53_AIPS2_BASE_ADDR + 0x000B8000)
#define MX53_RTIC_BASE_ADDR (MX53_AIPS2_BASE_ADDR + 0x000BC000)
-#define MX53_CSPI3_BASE_ADDR (MX53_AIPS2_BASE_ADDR + 0x000C0000)
+#define MX53_CSPI_BASE_ADDR (MX53_AIPS2_BASE_ADDR + 0x000C0000)
#define MX53_I2C2_BASE_ADDR (MX53_AIPS2_BASE_ADDR + 0x000C4000)
#define MX53_I2C1_BASE_ADDR (MX53_AIPS2_BASE_ADDR + 0x000C8000)
#define MX53_SSI1_BASE_ADDR (MX53_AIPS2_BASE_ADDR + 0x000CC000)
@@ -136,7 +136,7 @@
#define MX53_MIPI_HSC_BASE_ADDR (MX53_AIPS2_BASE_ADDR + 0x000DC000)
#define MX53_MLB_BASE_ADDR (MX53_AIPS2_BASE_ADDR + 0x000E4000)
#define MX53_SSI3_BASE_ADDR (MX53_AIPS2_BASE_ADDR + 0x000E8000)
-#define MX53_MXC_FEC_BASE_ADDR (MX53_AIPS2_BASE_ADDR + 0x000EC000)
+#define MX53_FEC_BASE_ADDR (MX53_AIPS2_BASE_ADDR + 0x000EC000)
#define MX53_TVE_BASE_ADDR (MX53_AIPS2_BASE_ADDR + 0x000F0000)
#define MX53_VPU_BASE_ADDR (MX53_AIPS2_BASE_ADDR + 0x000F4000)
#define MX53_SAHARA_BASE_ADDR (MX53_AIPS2_BASE_ADDR + 0x000F8000)
@@ -229,10 +229,10 @@
* Interrupt numbers
*/
#define MX53_INT_RESV0 0
-#define MX53_INT_MMC_SDHC1 1
-#define MX53_INT_MMC_SDHC2 2
-#define MX53_INT_MMC_SDHC3 3
-#define MX53_INT_MMC_SDHC4 4
+#define MX53_INT_ESDHC1 1
+#define MX53_INT_ESDHC2 2
+#define MX53_INT_ESDHC3 3
+#define MX53_INT_ESDHC4 4
#define MX53_INT_RESV5 5
#define MX53_INT_SDMA 6
#define MX53_INT_IOMUX 7
@@ -264,8 +264,8 @@
#define MX53_INT_UART3 33
#define MX53_INT_RESV34 34
#define MX53_INT_RESV35 35
-#define MX53_INT_CSPI1 36
-#define MX53_INT_CSPI2 37
+#define MX53_INT_ECSPI1 36
+#define MX53_INT_ECSPI2 37
#define MX53_INT_CSPI 38
#define MX53_INT_GPT 39
#define MX53_INT_EPIT1 40
diff --git a/arch/arm/plat-mxc/pwm.c b/arch/arm/plat-mxc/pwm.c
index c36f263..7a61ef8 100644
--- a/arch/arm/plat-mxc/pwm.c
+++ b/arch/arm/plat-mxc/pwm.c
@@ -57,7 +57,7 @@ int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
if (pwm == NULL || period_ns == 0 || duty_ns > period_ns)
return -EINVAL;
- if (cpu_is_mx27() || cpu_is_mx3() || cpu_is_mx25()) {
+ if (cpu_is_mx27() || cpu_is_mx3() || cpu_is_mx25() || cpu_is_mx51()) {
unsigned long long c;
unsigned long period_cycles, duty_cycles, prescale;
u32 cr;
diff --git a/arch/arm/plat-mxc/tzic.c b/arch/arm/plat-mxc/tzic.c
index e69ed8a..bc3a6be 100644
--- a/arch/arm/plat-mxc/tzic.c
+++ b/arch/arm/plat-mxc/tzic.c
@@ -69,50 +69,50 @@ static int tzic_set_irq_fiq(unsigned int irq, unsigned int type)
#endif
/**
- * tzic_mask_irq() - Disable interrupt number "irq" in the TZIC
+ * tzic_mask_irq() - Disable interrupt source "d" in the TZIC
*
- * @param irq interrupt source number
+ * @param d interrupt source
*/
-static void tzic_mask_irq(unsigned int irq)
+static void tzic_mask_irq(struct irq_data *d)
{
int index, off;
- index = irq >> 5;
- off = irq & 0x1F;
+ index = d->irq >> 5;
+ off = d->irq & 0x1F;
__raw_writel(1 << off, tzic_base + TZIC_ENCLEAR0(index));
}
/**
- * tzic_unmask_irq() - Enable interrupt number "irq" in the TZIC
+ * tzic_unmask_irq() - Enable interrupt source "d" in the TZIC
*
- * @param irq interrupt source number
+ * @param d interrupt source
*/
-static void tzic_unmask_irq(unsigned int irq)
+static void tzic_unmask_irq(struct irq_data *d)
{
int index, off;
- index = irq >> 5;
- off = irq & 0x1F;
+ index = d->irq >> 5;
+ off = d->irq & 0x1F;
__raw_writel(1 << off, tzic_base + TZIC_ENSET0(index));
}
static unsigned int wakeup_intr[4];
/**
- * tzic_set_wake_irq() - Set interrupt number "irq" in the TZIC as a wake-up source.
+ * tzic_set_wake_irq() - Set interrupt source "d" in the TZIC as a wake-up source.
*
- * @param irq interrupt source number
+ * @param d interrupt source
* @param enable enable as wake-up if equal to non-zero
* disble as wake-up if equal to zero
*
* @return This function returns 0 on success.
*/
-static int tzic_set_wake_irq(unsigned int irq, unsigned int enable)
+static int tzic_set_wake_irq(struct irq_data *d, unsigned int enable)
{
unsigned int index, off;
- index = irq >> 5;
- off = irq & 0x1F;
+ index = d->irq >> 5;
+ off = d->irq & 0x1F;
if (index > 3)
return -EINVAL;
@@ -128,10 +128,10 @@ static int tzic_set_wake_irq(unsigned int irq, unsigned int enable)
static struct mxc_irq_chip mxc_tzic_chip = {
.base = {
.name = "MXC_TZIC",
- .ack = tzic_mask_irq,
- .mask = tzic_mask_irq,
- .unmask = tzic_unmask_irq,
- .set_wake = tzic_set_wake_irq,
+ .irq_ack = tzic_mask_irq,
+ .irq_mask = tzic_mask_irq,
+ .irq_unmask = tzic_unmask_irq,
+ .irq_set_wake = tzic_set_wake_irq,
},
#ifdef CONFIG_FIQ
.set_irq_fiq = tzic_set_irq_fiq,
diff --git a/arch/arm/plat-nomadik/gpio.c b/arch/arm/plat-nomadik/gpio.c
index eda4e3a..1e88ecb 100644
--- a/arch/arm/plat-nomadik/gpio.c
+++ b/arch/arm/plat-nomadik/gpio.c
@@ -356,13 +356,13 @@ static inline int nmk_gpio_get_bitmask(int gpio)
return 1 << (gpio % 32);
}
-static void nmk_gpio_irq_ack(unsigned int irq)
+static void nmk_gpio_irq_ack(struct irq_data *d)
{
int gpio;
struct nmk_gpio_chip *nmk_chip;
- gpio = NOMADIK_IRQ_TO_GPIO(irq);
- nmk_chip = get_irq_chip_data(irq);
+ gpio = NOMADIK_IRQ_TO_GPIO(d->irq);
+ nmk_chip = irq_data_get_irq_chip_data(d);
if (!nmk_chip)
return;
writel(nmk_gpio_get_bitmask(gpio), nmk_chip->addr + NMK_GPIO_IC);
@@ -401,7 +401,7 @@ static void __nmk_gpio_irq_modify(struct nmk_gpio_chip *nmk_chip,
}
}
-static int nmk_gpio_irq_modify(unsigned int irq, enum nmk_gpio_irq_type which,
+static int nmk_gpio_irq_modify(struct irq_data *d, enum nmk_gpio_irq_type which,
bool enable)
{
int gpio;
@@ -409,8 +409,8 @@ static int nmk_gpio_irq_modify(unsigned int irq, enum nmk_gpio_irq_type which,
unsigned long flags;
u32 bitmask;
- gpio = NOMADIK_IRQ_TO_GPIO(irq);
- nmk_chip = get_irq_chip_data(irq);
+ gpio = NOMADIK_IRQ_TO_GPIO(d->irq);
+ nmk_chip = irq_data_get_irq_chip_data(d);
bitmask = nmk_gpio_get_bitmask(gpio);
if (!nmk_chip)
return -EINVAL;
@@ -422,24 +422,24 @@ static int nmk_gpio_irq_modify(unsigned int irq, enum nmk_gpio_irq_type which,
return 0;
}
-static void nmk_gpio_irq_mask(unsigned int irq)
+static void nmk_gpio_irq_mask(struct irq_data *d)
{
- nmk_gpio_irq_modify(irq, NORMAL, false);
+ nmk_gpio_irq_modify(d, NORMAL, false);
}
-static void nmk_gpio_irq_unmask(unsigned int irq)
+static void nmk_gpio_irq_unmask(struct irq_data *d)
{
- nmk_gpio_irq_modify(irq, NORMAL, true);
+ nmk_gpio_irq_modify(d, NORMAL, true);
}
-static int nmk_gpio_irq_set_wake(unsigned int irq, unsigned int on)
+static int nmk_gpio_irq_set_wake(struct irq_data *d, unsigned int on)
{
struct nmk_gpio_chip *nmk_chip;
unsigned long flags;
int gpio;
- gpio = NOMADIK_IRQ_TO_GPIO(irq);
- nmk_chip = get_irq_chip_data(irq);
+ gpio = NOMADIK_IRQ_TO_GPIO(d->irq);
+ nmk_chip = irq_data_get_irq_chip_data(d);
if (!nmk_chip)
return -EINVAL;
@@ -457,9 +457,9 @@ static int nmk_gpio_irq_set_wake(unsigned int irq, unsigned int on)
return 0;
}
-static int nmk_gpio_irq_set_type(unsigned int irq, unsigned int type)
+static int nmk_gpio_irq_set_type(struct irq_data *d, unsigned int type)
{
- struct irq_desc *desc = irq_to_desc(irq);
+ struct irq_desc *desc = irq_to_desc(d->irq);
bool enabled = !(desc->status & IRQ_DISABLED);
bool wake = desc->wake_depth;
int gpio;
@@ -467,8 +467,8 @@ static int nmk_gpio_irq_set_type(unsigned int irq, unsigned int type)
unsigned long flags;
u32 bitmask;
- gpio = NOMADIK_IRQ_TO_GPIO(irq);
- nmk_chip = get_irq_chip_data(irq);
+ gpio = NOMADIK_IRQ_TO_GPIO(d->irq);
+ nmk_chip = irq_data_get_irq_chip_data(d);
bitmask = nmk_gpio_get_bitmask(gpio);
if (!nmk_chip)
return -EINVAL;
@@ -507,11 +507,11 @@ static int nmk_gpio_irq_set_type(unsigned int irq, unsigned int type)
static struct irq_chip nmk_gpio_irq_chip = {
.name = "Nomadik-GPIO",
- .ack = nmk_gpio_irq_ack,
- .mask = nmk_gpio_irq_mask,
- .unmask = nmk_gpio_irq_unmask,
- .set_type = nmk_gpio_irq_set_type,
- .set_wake = nmk_gpio_irq_set_wake,
+ .irq_ack = nmk_gpio_irq_ack,
+ .irq_mask = nmk_gpio_irq_mask,
+ .irq_unmask = nmk_gpio_irq_unmask,
+ .irq_set_type = nmk_gpio_irq_set_type,
+ .irq_set_wake = nmk_gpio_irq_set_wake,
};
static void nmk_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
@@ -522,12 +522,12 @@ static void nmk_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
u32 pending;
unsigned int first_irq;
- if (host_chip->mask_ack)
- host_chip->mask_ack(irq);
+ if (host_chip->irq_mask_ack)
+ host_chip->irq_mask_ack(&desc->irq_data);
else {
- host_chip->mask(irq);
- if (host_chip->ack)
- host_chip->ack(irq);
+ host_chip->irq_mask(&desc->irq_data);
+ if (host_chip->irq_ack)
+ host_chip->irq_ack(&desc->irq_data);
}
nmk_chip = get_irq_data(irq);
@@ -537,7 +537,7 @@ static void nmk_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
generic_handle_irq(gpio_irq);
}
- host_chip->unmask(irq);
+ host_chip->irq_unmask(&desc->irq_data);
}
static int nmk_gpio_init_irq(struct nmk_gpio_chip *nmk_chip)
diff --git a/arch/arm/plat-nomadik/include/plat/ste_dma40.h b/arch/arm/plat-nomadik/include/plat/ste_dma40.h
index 74b62f1..4d6dd4c 100644
--- a/arch/arm/plat-nomadik/include/plat/ste_dma40.h
+++ b/arch/arm/plat-nomadik/include/plat/ste_dma40.h
@@ -13,6 +13,14 @@
#include <linux/workqueue.h>
#include <linux/interrupt.h>
+/*
+ * Maxium size for a single dma descriptor
+ * Size is limited to 16 bits.
+ * Size is in the units of addr-widths (1,2,4,8 bytes)
+ * Larger transfers will be split up to multiple linked desc
+ */
+#define STEDMA40_MAX_SEG_SIZE 0xFFFF
+
/* dev types for memcpy */
#define STEDMA40_DEV_DST_MEMORY (-1)
#define STEDMA40_DEV_SRC_MEMORY (-1)
diff --git a/arch/arm/plat-omap/Kconfig b/arch/arm/plat-omap/Kconfig
index 18fe3cb..b6333ae 100644
--- a/arch/arm/plat-omap/Kconfig
+++ b/arch/arm/plat-omap/Kconfig
@@ -144,12 +144,9 @@ config OMAP_IOMMU_DEBUG
config OMAP_IOMMU_IVA2
bool
-choice
- prompt "System timer"
- default OMAP_32K_TIMER if !ARCH_OMAP15XX
-
config OMAP_MPU_TIMER
bool "Use mpu timer"
+ depends on ARCH_OMAP1
help
Select this option if you want to use the OMAP mpu timer. This
timer provides more intra-tick resolution than the 32KHz timer,
@@ -158,6 +155,7 @@ config OMAP_MPU_TIMER
config OMAP_32K_TIMER
bool "Use 32KHz timer"
depends on ARCH_OMAP16XX || ARCH_OMAP2PLUS
+ default y if (ARCH_OMAP16XX || ARCH_OMAP2PLUS)
help
Select this option if you want to enable the OMAP 32KHz timer.
This timer saves power compared to the OMAP_MPU_TIMER, and has
@@ -165,8 +163,6 @@ config OMAP_32K_TIMER
intra-tick resolution than OMAP_MPU_TIMER. The 32KHz timer is
currently only available for OMAP16XX, 24XX, 34XX and OMAP4.
-endchoice
-
config OMAP3_L2_AUX_SECURE_SAVE_RESTORE
bool "OMAP3 HS/EMU save and restore for L2 AUX control register"
depends on ARCH_OMAP3 && PM
diff --git a/arch/arm/plat-omap/counter_32k.c b/arch/arm/plat-omap/counter_32k.c
index ea46440..862dda9 100644
--- a/arch/arm/plat-omap/counter_32k.c
+++ b/arch/arm/plat-omap/counter_32k.c
@@ -36,8 +36,6 @@
#define OMAP16XX_TIMER_32K_SYNCHRONIZED 0xfffbc410
-#if !(defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP15XX))
-
#include <linux/clocksource.h>
/*
@@ -122,12 +120,24 @@ static DEFINE_CLOCK_DATA(cd);
#define SC_MULT 4000000000u
#define SC_SHIFT 17
-unsigned long long notrace sched_clock(void)
+static inline unsigned long long notrace _omap_32k_sched_clock(void)
{
u32 cyc = clocksource_32k.read(&clocksource_32k);
return cyc_to_fixed_sched_clock(&cd, cyc, (u32)~0, SC_MULT, SC_SHIFT);
}
+#ifndef CONFIG_OMAP_MPU_TIMER
+unsigned long long notrace sched_clock(void)
+{
+ return _omap_32k_sched_clock();
+}
+#else
+unsigned long long notrace omap_32k_sched_clock(void)
+{
+ return _omap_32k_sched_clock();
+}
+#endif
+
static void notrace omap_update_sched_clock(void)
{
u32 cyc = clocksource_32k.read(&clocksource_32k);
@@ -160,7 +170,7 @@ void read_persistent_clock(struct timespec *ts)
*ts = *tsp;
}
-static int __init omap_init_clocksource_32k(void)
+int __init omap_init_clocksource_32k(void)
{
static char err[] __initdata = KERN_ERR
"%s: can't register clocksource!\n";
@@ -195,7 +205,3 @@ static int __init omap_init_clocksource_32k(void)
}
return 0;
}
-arch_initcall(omap_init_clocksource_32k);
-
-#endif /* !(defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP15XX)) */
-
diff --git a/arch/arm/plat-omap/dma.c b/arch/arm/plat-omap/dma.c
index c4b2b47..8536308 100644
--- a/arch/arm/plat-omap/dma.c
+++ b/arch/arm/plat-omap/dma.c
@@ -53,7 +53,7 @@ enum { DMA_CHAIN_STARTED, DMA_CHAIN_NOTSTARTED };
#endif
#define OMAP_DMA_ACTIVE 0x01
-#define OMAP2_DMA_CSR_CLEAR_MASK 0xffe
+#define OMAP2_DMA_CSR_CLEAR_MASK 0xffffffff
#define OMAP_FUNC_MUX_ARM_BASE (0xfffe1000 + 0xec)
@@ -1873,7 +1873,7 @@ static int omap2_dma_handle_ch(int ch)
printk(KERN_INFO "DMA misaligned error with device %d\n",
dma_chan[ch].dev_id);
- p->dma_write(OMAP2_DMA_CSR_CLEAR_MASK, CSR, ch);
+ p->dma_write(status, CSR, ch);
p->dma_write(1 << ch, IRQSTATUS_L0, ch);
/* read back the register to flush the write */
p->dma_read(IRQSTATUS_L0, ch);
@@ -1893,10 +1893,9 @@ static int omap2_dma_handle_ch(int ch)
OMAP_DMA_CHAIN_INCQHEAD(chain_id);
status = p->dma_read(CSR, ch);
+ p->dma_write(status, CSR, ch);
}
- p->dma_write(status, CSR, ch);
-
if (likely(dma_chan[ch].callback != NULL))
dma_chan[ch].callback(ch, status, dma_chan[ch].data);
diff --git a/arch/arm/plat-omap/gpio.c b/arch/arm/plat-omap/gpio.c
index 1f98e0b..971d186 100644
--- a/arch/arm/plat-omap/gpio.c
+++ b/arch/arm/plat-omap/gpio.c
@@ -718,7 +718,7 @@ static int _set_gpio_triggering(struct gpio_bank *bank, int gpio, int trigger)
case METHOD_GPIO_24XX:
case METHOD_GPIO_44XX:
set_24xx_gpio_triggering(bank, gpio, trigger);
- break;
+ return 0;
#endif
default:
goto bad;
@@ -729,17 +729,17 @@ bad:
return -EINVAL;
}
-static int gpio_irq_type(unsigned irq, unsigned type)
+static int gpio_irq_type(struct irq_data *d, unsigned type)
{
struct gpio_bank *bank;
unsigned gpio;
int retval;
unsigned long flags;
- if (!cpu_class_is_omap2() && irq > IH_MPUIO_BASE)
- gpio = OMAP_MPUIO(irq - IH_MPUIO_BASE);
+ if (!cpu_class_is_omap2() && d->irq > IH_MPUIO_BASE)
+ gpio = OMAP_MPUIO(d->irq - IH_MPUIO_BASE);
else
- gpio = irq - IH_GPIO_BASE;
+ gpio = d->irq - IH_GPIO_BASE;
if (check_gpio(gpio) < 0)
return -EINVAL;
@@ -752,19 +752,21 @@ static int gpio_irq_type(unsigned irq, unsigned type)
&& (type & (IRQ_TYPE_LEVEL_LOW|IRQ_TYPE_LEVEL_HIGH)))
return -EINVAL;
- bank = get_irq_chip_data(irq);
+ bank = irq_data_get_irq_chip_data(d);
spin_lock_irqsave(&bank->lock, flags);
retval = _set_gpio_triggering(bank, get_gpio_index(gpio), type);
if (retval == 0) {
- irq_desc[irq].status &= ~IRQ_TYPE_SENSE_MASK;
- irq_desc[irq].status |= type;
+ struct irq_desc *desc = irq_to_desc(d->irq);
+
+ desc->status &= ~IRQ_TYPE_SENSE_MASK;
+ desc->status |= type;
}
spin_unlock_irqrestore(&bank->lock, flags);
if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH))
- __set_irq_handler_unlocked(irq, handle_level_irq);
+ __set_irq_handler_unlocked(d->irq, handle_level_irq);
else if (type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING))
- __set_irq_handler_unlocked(irq, handle_edge_irq);
+ __set_irq_handler_unlocked(d->irq, handle_edge_irq);
return retval;
}
@@ -1021,15 +1023,15 @@ static void _reset_gpio(struct gpio_bank *bank, int gpio)
}
/* Use disable_irq_wake() and enable_irq_wake() functions from drivers */
-static int gpio_wake_enable(unsigned int irq, unsigned int enable)
+static int gpio_wake_enable(struct irq_data *d, unsigned int enable)
{
- unsigned int gpio = irq - IH_GPIO_BASE;
+ unsigned int gpio = d->irq - IH_GPIO_BASE;
struct gpio_bank *bank;
int retval;
if (check_gpio(gpio) < 0)
return -ENODEV;
- bank = get_irq_chip_data(irq);
+ bank = irq_data_get_irq_chip_data(d);
retval = _set_gpio_wakeup(bank, get_gpio_index(gpio), enable);
return retval;
@@ -1142,7 +1144,7 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
u32 retrigger = 0;
int unmasked = 0;
- desc->chip->ack(irq);
+ desc->irq_data.chip->irq_ack(&desc->irq_data);
bank = get_irq_data(irq);
#ifdef CONFIG_ARCH_OMAP1
@@ -1199,7 +1201,7 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
configured, we could unmask GPIO bank interrupt immediately */
if (!level_mask && !unmasked) {
unmasked = 1;
- desc->chip->unmask(irq);
+ desc->irq_data.chip->irq_unmask(&desc->irq_data);
}
isr |= retrigger;
@@ -1235,41 +1237,40 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
interrupt */
exit:
if (!unmasked)
- desc->chip->unmask(irq);
-
+ desc->irq_data.chip->irq_unmask(&desc->irq_data);
}
-static void gpio_irq_shutdown(unsigned int irq)
+static void gpio_irq_shutdown(struct irq_data *d)
{
- unsigned int gpio = irq - IH_GPIO_BASE;
- struct gpio_bank *bank = get_irq_chip_data(irq);
+ unsigned int gpio = d->irq - IH_GPIO_BASE;
+ struct gpio_bank *bank = irq_data_get_irq_chip_data(d);
_reset_gpio(bank, gpio);
}
-static void gpio_ack_irq(unsigned int irq)
+static void gpio_ack_irq(struct irq_data *d)
{
- unsigned int gpio = irq - IH_GPIO_BASE;
- struct gpio_bank *bank = get_irq_chip_data(irq);
+ unsigned int gpio = d->irq - IH_GPIO_BASE;
+ struct gpio_bank *bank = irq_data_get_irq_chip_data(d);
_clear_gpio_irqstatus(bank, gpio);
}
-static void gpio_mask_irq(unsigned int irq)
+static void gpio_mask_irq(struct irq_data *d)
{
- unsigned int gpio = irq - IH_GPIO_BASE;
- struct gpio_bank *bank = get_irq_chip_data(irq);
+ unsigned int gpio = d->irq - IH_GPIO_BASE;
+ struct gpio_bank *bank = irq_data_get_irq_chip_data(d);
_set_gpio_irqenable(bank, gpio, 0);
_set_gpio_triggering(bank, get_gpio_index(gpio), IRQ_TYPE_NONE);
}
-static void gpio_unmask_irq(unsigned int irq)
+static void gpio_unmask_irq(struct irq_data *d)
{
- unsigned int gpio = irq - IH_GPIO_BASE;
- struct gpio_bank *bank = get_irq_chip_data(irq);
+ unsigned int gpio = d->irq - IH_GPIO_BASE;
+ struct gpio_bank *bank = irq_data_get_irq_chip_data(d);
unsigned int irq_mask = 1 << get_gpio_index(gpio);
- struct irq_desc *desc = irq_to_desc(irq);
+ struct irq_desc *desc = irq_to_desc(d->irq);
u32 trigger = desc->status & IRQ_TYPE_SENSE_MASK;
if (trigger)
@@ -1287,12 +1288,12 @@ static void gpio_unmask_irq(unsigned int irq)
static struct irq_chip gpio_irq_chip = {
.name = "GPIO",
- .shutdown = gpio_irq_shutdown,
- .ack = gpio_ack_irq,
- .mask = gpio_mask_irq,
- .unmask = gpio_unmask_irq,
- .set_type = gpio_irq_type,
- .set_wake = gpio_wake_enable,
+ .irq_shutdown = gpio_irq_shutdown,
+ .irq_ack = gpio_ack_irq,
+ .irq_mask = gpio_mask_irq,
+ .irq_unmask = gpio_unmask_irq,
+ .irq_set_type = gpio_irq_type,
+ .irq_set_wake = gpio_wake_enable,
};
/*---------------------------------------------------------------------*/
@@ -1301,36 +1302,36 @@ static struct irq_chip gpio_irq_chip = {
/* MPUIO uses the always-on 32k clock */
-static void mpuio_ack_irq(unsigned int irq)
+static void mpuio_ack_irq(struct irq_data *d)
{
/* The ISR is reset automatically, so do nothing here. */
}
-static void mpuio_mask_irq(unsigned int irq)
+static void mpuio_mask_irq(struct irq_data *d)
{
- unsigned int gpio = OMAP_MPUIO(irq - IH_MPUIO_BASE);
- struct gpio_bank *bank = get_irq_chip_data(irq);
+ unsigned int gpio = OMAP_MPUIO(d->irq - IH_MPUIO_BASE);
+ struct gpio_bank *bank = irq_data_get_irq_chip_data(d);
_set_gpio_irqenable(bank, gpio, 0);
}
-static void mpuio_unmask_irq(unsigned int irq)
+static void mpuio_unmask_irq(struct irq_data *d)
{
- unsigned int gpio = OMAP_MPUIO(irq - IH_MPUIO_BASE);
- struct gpio_bank *bank = get_irq_chip_data(irq);
+ unsigned int gpio = OMAP_MPUIO(d->irq - IH_MPUIO_BASE);
+ struct gpio_bank *bank = irq_data_get_irq_chip_data(d);
_set_gpio_irqenable(bank, gpio, 1);
}
static struct irq_chip mpuio_irq_chip = {
.name = "MPUIO",
- .ack = mpuio_ack_irq,
- .mask = mpuio_mask_irq,
- .unmask = mpuio_unmask_irq,
- .set_type = gpio_irq_type,
+ .irq_ack = mpuio_ack_irq,
+ .irq_mask = mpuio_mask_irq,
+ .irq_unmask = mpuio_unmask_irq,
+ .irq_set_type = gpio_irq_type,
#ifdef CONFIG_ARCH_OMAP16XX
/* REVISIT: assuming only 16xx supports MPUIO wake events */
- .set_wake = gpio_wake_enable,
+ .irq_set_wake = gpio_wake_enable,
#endif
};
@@ -1671,7 +1672,9 @@ static void __init omap_gpio_chip_init(struct gpio_bank *bank)
for (j = bank->virtual_irq_start;
j < bank->virtual_irq_start + bank_width; j++) {
- lockdep_set_class(&irq_desc[j].lock, &gpio_lock_class);
+ struct irq_desc *d = irq_to_desc(j);
+
+ lockdep_set_class(&d->lock, &gpio_lock_class);
set_irq_chip_data(j, bank);
if (bank_is_mpuio(bank))
set_irq_chip(j, &mpuio_irq_chip);
diff --git a/arch/arm/plat-omap/include/plat/common.h b/arch/arm/plat-omap/include/plat/common.h
index 6b8088e..29b2afb 100644
--- a/arch/arm/plat-omap/include/plat/common.h
+++ b/arch/arm/plat-omap/include/plat/common.h
@@ -35,6 +35,9 @@ struct sys_timer;
extern void omap_map_common_io(void);
extern struct sys_timer omap_timer;
+extern bool omap_32k_timer_init(void);
+extern int __init omap_init_clocksource_32k(void);
+extern unsigned long long notrace omap_32k_sched_clock(void);
extern void omap_reserve(void);
diff --git a/arch/arm/plat-omap/include/plat/onenand.h b/arch/arm/plat-omap/include/plat/onenand.h
index 72f433d..affe87e 100644
--- a/arch/arm/plat-omap/include/plat/onenand.h
+++ b/arch/arm/plat-omap/include/plat/onenand.h
@@ -23,6 +23,7 @@ struct omap_onenand_platform_data {
int (*onenand_setup)(void __iomem *, int freq);
int dma_channel;
u8 flags;
+ u8 regulator_can_sleep;
};
#define ONENAND_MAX_PARTITIONS 8
diff --git a/arch/arm/plat-omap/include/plat/voltage.h b/arch/arm/plat-omap/include/plat/voltage.h
index 0ff1233..5bd204e 100644
--- a/arch/arm/plat-omap/include/plat/voltage.h
+++ b/arch/arm/plat-omap/include/plat/voltage.h
@@ -14,6 +14,8 @@
#ifndef __ARCH_ARM_MACH_OMAP2_VOLTAGE_H
#define __ARCH_ARM_MACH_OMAP2_VOLTAGE_H
+#include <linux/err.h>
+
#define VOLTSCALE_VPFORCEUPDATE 1
#define VOLTSCALE_VCBYPASS 2
@@ -65,9 +67,6 @@ struct voltagedomain {
char *name;
};
-/* API to get the voltagedomain pointer */
-struct voltagedomain *omap_voltage_domain_lookup(char *name);
-
/**
* struct omap_volt_data - Omap voltage specific data.
* @voltage_nominal: The possible voltage value in uV
@@ -131,16 +130,26 @@ int omap_voltage_register_pmic(struct voltagedomain *voltdm,
struct omap_volt_pmic_info *pmic_info);
void omap_change_voltscale_method(struct voltagedomain *voltdm,
int voltscale_method);
+/* API to get the voltagedomain pointer */
+struct voltagedomain *omap_voltage_domain_lookup(char *name);
+
int omap_voltage_late_init(void);
#else
static inline int omap_voltage_register_pmic(struct voltagedomain *voltdm,
- struct omap_volt_pmic_info *pmic_info) {}
+ struct omap_volt_pmic_info *pmic_info)
+{
+ return -EINVAL;
+}
static inline void omap_change_voltscale_method(struct voltagedomain *voltdm,
int voltscale_method) {}
static inline int omap_voltage_late_init(void)
{
return -EINVAL;
}
+static inline struct voltagedomain *omap_voltage_domain_lookup(char *name)
+{
+ return ERR_PTR(-EINVAL);
+}
#endif
#endif
diff --git a/arch/arm/plat-orion/gpio.c b/arch/arm/plat-orion/gpio.c
index e814803..5f35223 100644
--- a/arch/arm/plat-orion/gpio.c
+++ b/arch/arm/plat-orion/gpio.c
@@ -232,20 +232,19 @@ EXPORT_SYMBOL(orion_gpio_set_blink);
* polarity LEVEL mask
*
****************************************************************************/
-
-static void gpio_irq_ack(u32 irq)
+static void gpio_irq_ack(struct irq_data *d)
{
- int type = irq_desc[irq].status & IRQ_TYPE_SENSE_MASK;
+ int type = irq_desc[d->irq].status & IRQ_TYPE_SENSE_MASK;
if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) {
- int pin = irq_to_gpio(irq);
+ int pin = irq_to_gpio(d->irq);
writel(~(1 << (pin & 31)), GPIO_EDGE_CAUSE(pin));
}
}
-static void gpio_irq_mask(u32 irq)
+static void gpio_irq_mask(struct irq_data *d)
{
- int pin = irq_to_gpio(irq);
- int type = irq_desc[irq].status & IRQ_TYPE_SENSE_MASK;
+ int pin = irq_to_gpio(d->irq);
+ int type = irq_desc[d->irq].status & IRQ_TYPE_SENSE_MASK;
u32 reg = (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) ?
GPIO_EDGE_MASK(pin) : GPIO_LEVEL_MASK(pin);
u32 u = readl(reg);
@@ -253,10 +252,10 @@ static void gpio_irq_mask(u32 irq)
writel(u, reg);
}
-static void gpio_irq_unmask(u32 irq)
+static void gpio_irq_unmask(struct irq_data *d)
{
- int pin = irq_to_gpio(irq);
- int type = irq_desc[irq].status & IRQ_TYPE_SENSE_MASK;
+ int pin = irq_to_gpio(d->irq);
+ int type = irq_desc[d->irq].status & IRQ_TYPE_SENSE_MASK;
u32 reg = (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) ?
GPIO_EDGE_MASK(pin) : GPIO_LEVEL_MASK(pin);
u32 u = readl(reg);
@@ -264,20 +263,20 @@ static void gpio_irq_unmask(u32 irq)
writel(u, reg);
}
-static int gpio_irq_set_type(u32 irq, u32 type)
+static int gpio_irq_set_type(struct irq_data *d, u32 type)
{
- int pin = irq_to_gpio(irq);
+ int pin = irq_to_gpio(d->irq);
struct irq_desc *desc;
u32 u;
u = readl(GPIO_IO_CONF(pin)) & (1 << (pin & 31));
if (!u) {
printk(KERN_ERR "orion gpio_irq_set_type failed "
- "(irq %d, pin %d).\n", irq, pin);
+ "(irq %d, pin %d).\n", d->irq, pin);
return -EINVAL;
}
- desc = irq_desc + irq;
+ desc = irq_desc + d->irq;
/*
* Set edge/level type.
@@ -287,7 +286,7 @@ static int gpio_irq_set_type(u32 irq, u32 type)
} else if (type & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) {
desc->handle_irq = handle_level_irq;
} else {
- printk(KERN_ERR "failed to set irq=%d (type=%d)\n", irq, type);
+ printk(KERN_ERR "failed to set irq=%d (type=%d)\n", d->irq, type);
return -EINVAL;
}
@@ -325,10 +324,10 @@ static int gpio_irq_set_type(u32 irq, u32 type)
struct irq_chip orion_gpio_irq_chip = {
.name = "orion_gpio_irq",
- .ack = gpio_irq_ack,
- .mask = gpio_irq_mask,
- .unmask = gpio_irq_unmask,
- .set_type = gpio_irq_set_type,
+ .irq_ack = gpio_irq_ack,
+ .irq_mask = gpio_irq_mask,
+ .irq_unmask = gpio_irq_unmask,
+ .irq_set_type = gpio_irq_set_type,
};
void orion_gpio_irq_handler(int pinoff)
diff --git a/arch/arm/plat-orion/irq.c b/arch/arm/plat-orion/irq.c
index 3f9d34f..7d0c7eb 100644
--- a/arch/arm/plat-orion/irq.c
+++ b/arch/arm/plat-orion/irq.c
@@ -14,31 +14,31 @@
#include <linux/io.h>
#include <plat/irq.h>
-static void orion_irq_mask(u32 irq)
+static void orion_irq_mask(struct irq_data *d)
{
- void __iomem *maskaddr = get_irq_chip_data(irq);
+ void __iomem *maskaddr = irq_data_get_irq_chip_data(d);
u32 mask;
mask = readl(maskaddr);
- mask &= ~(1 << (irq & 31));
+ mask &= ~(1 << (d->irq & 31));
writel(mask, maskaddr);
}
-static void orion_irq_unmask(u32 irq)
+static void orion_irq_unmask(struct irq_data *d)
{
- void __iomem *maskaddr = get_irq_chip_data(irq);
+ void __iomem *maskaddr = irq_data_get_irq_chip_data(d);
u32 mask;
mask = readl(maskaddr);
- mask |= 1 << (irq & 31);
+ mask |= 1 << (d->irq & 31);
writel(mask, maskaddr);
}
static struct irq_chip orion_irq_chip = {
.name = "orion_irq",
- .mask = orion_irq_mask,
- .mask_ack = orion_irq_mask,
- .unmask = orion_irq_unmask,
+ .irq_mask = orion_irq_mask,
+ .irq_mask_ack = orion_irq_mask,
+ .irq_unmask = orion_irq_unmask,
};
void __init orion_irq_init(unsigned int irq_start, void __iomem *maskaddr)
diff --git a/arch/arm/plat-pxa/gpio.c b/arch/arm/plat-pxa/gpio.c
index 98548c6..e7de6ae 100644
--- a/arch/arm/plat-pxa/gpio.c
+++ b/arch/arm/plat-pxa/gpio.c
@@ -155,10 +155,10 @@ static inline void update_edge_detect(struct pxa_gpio_chip *c)
__raw_writel(gfer, c->regbase + GFER_OFFSET);
}
-static int pxa_gpio_irq_type(unsigned int irq, unsigned int type)
+static int pxa_gpio_irq_type(struct irq_data *d, unsigned int type)
{
struct pxa_gpio_chip *c;
- int gpio = irq_to_gpio(irq);
+ int gpio = irq_to_gpio(d->irq);
unsigned long gpdr, mask = GPIO_bit(gpio);
c = gpio_to_chip(gpio);
@@ -195,7 +195,7 @@ static int pxa_gpio_irq_type(unsigned int irq, unsigned int type)
update_edge_detect(c);
- pr_debug("%s: IRQ%d (GPIO%d) - edge%s%s\n", __func__, irq, gpio,
+ pr_debug("%s: IRQ%d (GPIO%d) - edge%s%s\n", __func__, d->irq, gpio,
((type & IRQ_TYPE_EDGE_RISING) ? " rising" : ""),
((type & IRQ_TYPE_EDGE_FALLING) ? " falling" : ""));
return 0;
@@ -227,17 +227,17 @@ static void pxa_gpio_demux_handler(unsigned int irq, struct irq_desc *desc)
} while (loop);
}
-static void pxa_ack_muxed_gpio(unsigned int irq)
+static void pxa_ack_muxed_gpio(struct irq_data *d)
{
- int gpio = irq_to_gpio(irq);
+ int gpio = irq_to_gpio(d->irq);
struct pxa_gpio_chip *c = gpio_to_chip(gpio);
__raw_writel(GPIO_bit(gpio), c->regbase + GEDR_OFFSET);
}
-static void pxa_mask_muxed_gpio(unsigned int irq)
+static void pxa_mask_muxed_gpio(struct irq_data *d)
{
- int gpio = irq_to_gpio(irq);
+ int gpio = irq_to_gpio(d->irq);
struct pxa_gpio_chip *c = gpio_to_chip(gpio);
uint32_t grer, gfer;
@@ -249,9 +249,9 @@ static void pxa_mask_muxed_gpio(unsigned int irq)
__raw_writel(gfer, c->regbase + GFER_OFFSET);
}
-static void pxa_unmask_muxed_gpio(unsigned int irq)
+static void pxa_unmask_muxed_gpio(struct irq_data *d)
{
- int gpio = irq_to_gpio(irq);
+ int gpio = irq_to_gpio(d->irq);
struct pxa_gpio_chip *c = gpio_to_chip(gpio);
c->irq_mask |= GPIO_bit(gpio);
@@ -260,10 +260,10 @@ static void pxa_unmask_muxed_gpio(unsigned int irq)
static struct irq_chip pxa_muxed_gpio_chip = {
.name = "GPIO",
- .ack = pxa_ack_muxed_gpio,
- .mask = pxa_mask_muxed_gpio,
- .unmask = pxa_unmask_muxed_gpio,
- .set_type = pxa_gpio_irq_type,
+ .irq_ack = pxa_ack_muxed_gpio,
+ .irq_mask = pxa_mask_muxed_gpio,
+ .irq_unmask = pxa_unmask_muxed_gpio,
+ .irq_set_type = pxa_gpio_irq_type,
};
void __init pxa_init_gpio(int mux_irq, int start, int end, set_wake_t fn)
@@ -291,7 +291,7 @@ void __init pxa_init_gpio(int mux_irq, int start, int end, set_wake_t fn)
/* Install handler for GPIO>=2 edge detect interrupts */
set_irq_chained_handler(mux_irq, pxa_gpio_demux_handler);
- pxa_muxed_gpio_chip.set_wake = fn;
+ pxa_muxed_gpio_chip.irq_set_wake = fn;
}
#ifdef CONFIG_PM
diff --git a/arch/arm/plat-pxa/include/plat/gpio.h b/arch/arm/plat-pxa/include/plat/gpio.h
index 44248cb..1ddd2b9 100644
--- a/arch/arm/plat-pxa/include/plat/gpio.h
+++ b/arch/arm/plat-pxa/include/plat/gpio.h
@@ -1,6 +1,8 @@
#ifndef __PLAT_GPIO_H
#define __PLAT_GPIO_H
+struct irq_data;
+
/*
* We handle the GPIOs by banks, each bank covers up to 32 GPIOs with
* one set of registers. The register offsets are organized below:
@@ -56,7 +58,7 @@ static inline void gpio_set_value(unsigned gpio, int value)
*/
extern int pxa_last_gpio;
-typedef int (*set_wake_t)(unsigned int irq, unsigned int on);
+typedef int (*set_wake_t)(struct irq_data *d, unsigned int on);
extern void pxa_init_gpio(int mux_irq, int start, int end, set_wake_t fn);
#endif /* __PLAT_GPIO_H */
diff --git a/arch/arm/plat-s3c24xx/devs.c b/arch/arm/plat-s3c24xx/devs.c
index 8a42bc4..268f3ed 100644
--- a/arch/arm/plat-s3c24xx/devs.c
+++ b/arch/arm/plat-s3c24xx/devs.c
@@ -194,7 +194,6 @@ void __init s3c24xx_ts_set_platdata(struct s3c2410_ts_mach_info *hard_s3c2410ts_
memcpy(&s3c2410ts_info, hard_s3c2410ts_info, sizeof(struct s3c2410_ts_mach_info));
s3c_device_ts.dev.platform_data = &s3c2410ts_info;
}
-EXPORT_SYMBOL(s3c24xx_ts_set_platdata);
/* USB Device (Gadget)*/
diff --git a/arch/arm/plat-s3c24xx/include/plat/irq.h b/arch/arm/plat-s3c24xx/include/plat/irq.h
index 69e1be8..ec087d6 100644
--- a/arch/arm/plat-s3c24xx/include/plat/irq.h
+++ b/arch/arm/plat-s3c24xx/include/plat/irq.h
@@ -107,9 +107,9 @@ s3c_irqsub_ack(unsigned int irqno, unsigned int parentmask, unsigned int group)
/* exported for use in arch/arm/mach-s3c2410 */
#ifdef CONFIG_PM
-extern int s3c_irq_wake(unsigned int irqno, unsigned int state);
+extern int s3c_irq_wake(struct irq_data *data, unsigned int state);
#else
#define s3c_irq_wake NULL
#endif
-extern int s3c_irqext_type(unsigned int irq, unsigned int type);
+extern int s3c_irqext_type(struct irq_data *d, unsigned int type);
diff --git a/arch/arm/plat-s3c24xx/irq-pm.c b/arch/arm/plat-s3c24xx/irq-pm.c
index ea8dea3..c3624d8 100644
--- a/arch/arm/plat-s3c24xx/irq-pm.c
+++ b/arch/arm/plat-s3c24xx/irq-pm.c
@@ -15,11 +15,14 @@
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/sysdev.h>
+#include <linux/irq.h>
#include <plat/cpu.h>
#include <plat/pm.h>
#include <plat/irq.h>
+#include <asm/irq.h>
+
/* state for IRQs over sleep */
/* default is to allow for EINT0..EINT15, and IRQ_RTC as wakeup sources
@@ -30,15 +33,15 @@
unsigned long s3c_irqwake_intallow = 1L << (IRQ_RTC - IRQ_EINT0) | 0xfL;
unsigned long s3c_irqwake_eintallow = 0x0000fff0L;
-int s3c_irq_wake(unsigned int irqno, unsigned int state)
+int s3c_irq_wake(struct irq_data *data, unsigned int state)
{
- unsigned long irqbit = 1 << (irqno - IRQ_EINT0);
+ unsigned long irqbit = 1 << (data->irq - IRQ_EINT0);
if (!(s3c_irqwake_intallow & irqbit))
return -ENOENT;
printk(KERN_INFO "wake %s for irq %d\n",
- state ? "enabled" : "disabled", irqno);
+ state ? "enabled" : "disabled", data->irq);
if (!state)
s3c_irqwake_intmask |= irqbit;
diff --git a/arch/arm/plat-s3c24xx/irq.c b/arch/arm/plat-s3c24xx/irq.c
index ad0d44e..4434cb5 100644
--- a/arch/arm/plat-s3c24xx/irq.c
+++ b/arch/arm/plat-s3c24xx/irq.c
@@ -34,30 +34,29 @@
#include <plat/irq.h>
static void
-s3c_irq_mask(unsigned int irqno)
+s3c_irq_mask(struct irq_data *data)
{
+ unsigned int irqno = data->irq - IRQ_EINT0;
unsigned long mask;
- irqno -= IRQ_EINT0;
-
mask = __raw_readl(S3C2410_INTMSK);
mask |= 1UL << irqno;
__raw_writel(mask, S3C2410_INTMSK);
}
static inline void
-s3c_irq_ack(unsigned int irqno)
+s3c_irq_ack(struct irq_data *data)
{
- unsigned long bitval = 1UL << (irqno - IRQ_EINT0);
+ unsigned long bitval = 1UL << (data->irq - IRQ_EINT0);
__raw_writel(bitval, S3C2410_SRCPND);
__raw_writel(bitval, S3C2410_INTPND);
}
static inline void
-s3c_irq_maskack(unsigned int irqno)
+s3c_irq_maskack(struct irq_data *data)
{
- unsigned long bitval = 1UL << (irqno - IRQ_EINT0);
+ unsigned long bitval = 1UL << (data->irq - IRQ_EINT0);
unsigned long mask;
mask = __raw_readl(S3C2410_INTMSK);
@@ -69,8 +68,9 @@ s3c_irq_maskack(unsigned int irqno)
static void
-s3c_irq_unmask(unsigned int irqno)
+s3c_irq_unmask(struct irq_data *data)
{
+ unsigned int irqno = data->irq;
unsigned long mask;
if (irqno != IRQ_TIMER4 && irqno != IRQ_EINT8t23)
@@ -85,40 +85,39 @@ s3c_irq_unmask(unsigned int irqno)
struct irq_chip s3c_irq_level_chip = {
.name = "s3c-level",
- .ack = s3c_irq_maskack,
- .mask = s3c_irq_mask,
- .unmask = s3c_irq_unmask,
- .set_wake = s3c_irq_wake
+ .irq_ack = s3c_irq_maskack,
+ .irq_mask = s3c_irq_mask,
+ .irq_unmask = s3c_irq_unmask,
+ .irq_set_wake = s3c_irq_wake
};
struct irq_chip s3c_irq_chip = {
.name = "s3c",
- .ack = s3c_irq_ack,
- .mask = s3c_irq_mask,
- .unmask = s3c_irq_unmask,
- .set_wake = s3c_irq_wake
+ .irq_ack = s3c_irq_ack,
+ .irq_mask = s3c_irq_mask,
+ .irq_unmask = s3c_irq_unmask,
+ .irq_set_wake = s3c_irq_wake
};
static void
-s3c_irqext_mask(unsigned int irqno)
+s3c_irqext_mask(struct irq_data *data)
{
+ unsigned int irqno = data->irq - EXTINT_OFF;
unsigned long mask;
- irqno -= EXTINT_OFF;
-
mask = __raw_readl(S3C24XX_EINTMASK);
mask |= ( 1UL << irqno);
__raw_writel(mask, S3C24XX_EINTMASK);
}
static void
-s3c_irqext_ack(unsigned int irqno)
+s3c_irqext_ack(struct irq_data *data)
{
unsigned long req;
unsigned long bit;
unsigned long mask;
- bit = 1UL << (irqno - EXTINT_OFF);
+ bit = 1UL << (data->irq - EXTINT_OFF);
mask = __raw_readl(S3C24XX_EINTMASK);
@@ -129,64 +128,57 @@ s3c_irqext_ack(unsigned int irqno)
/* not sure if we should be acking the parent irq... */
- if (irqno <= IRQ_EINT7 ) {
+ if (data->irq <= IRQ_EINT7) {
if ((req & 0xf0) == 0)
- s3c_irq_ack(IRQ_EINT4t7);
+ s3c_irq_ack(irq_get_irq_data(IRQ_EINT4t7));
} else {
if ((req >> 8) == 0)
- s3c_irq_ack(IRQ_EINT8t23);
+ s3c_irq_ack(irq_get_irq_data(IRQ_EINT8t23));
}
}
static void
-s3c_irqext_unmask(unsigned int irqno)
+s3c_irqext_unmask(struct irq_data *data)
{
+ unsigned int irqno = data->irq - EXTINT_OFF;
unsigned long mask;
- irqno -= EXTINT_OFF;
-
mask = __raw_readl(S3C24XX_EINTMASK);
- mask &= ~( 1UL << irqno);
+ mask &= ~(1UL << irqno);
__raw_writel(mask, S3C24XX_EINTMASK);
}
int
-s3c_irqext_type(unsigned int irq, unsigned int type)
+s3c_irqext_type(struct irq_data *data, unsigned int type)
{
void __iomem *extint_reg;
void __iomem *gpcon_reg;
unsigned long gpcon_offset, extint_offset;
unsigned long newvalue = 0, value;
- if ((irq >= IRQ_EINT0) && (irq <= IRQ_EINT3))
- {
+ if ((data->irq >= IRQ_EINT0) && (data->irq <= IRQ_EINT3)) {
gpcon_reg = S3C2410_GPFCON;
extint_reg = S3C24XX_EXTINT0;
- gpcon_offset = (irq - IRQ_EINT0) * 2;
- extint_offset = (irq - IRQ_EINT0) * 4;
- }
- else if ((irq >= IRQ_EINT4) && (irq <= IRQ_EINT7))
- {
+ gpcon_offset = (data->irq - IRQ_EINT0) * 2;
+ extint_offset = (data->irq - IRQ_EINT0) * 4;
+ } else if ((data->irq >= IRQ_EINT4) && (data->irq <= IRQ_EINT7)) {
gpcon_reg = S3C2410_GPFCON;
extint_reg = S3C24XX_EXTINT0;
- gpcon_offset = (irq - (EXTINT_OFF)) * 2;
- extint_offset = (irq - (EXTINT_OFF)) * 4;
- }
- else if ((irq >= IRQ_EINT8) && (irq <= IRQ_EINT15))
- {
+ gpcon_offset = (data->irq - (EXTINT_OFF)) * 2;
+ extint_offset = (data->irq - (EXTINT_OFF)) * 4;
+ } else if ((data->irq >= IRQ_EINT8) && (data->irq <= IRQ_EINT15)) {
gpcon_reg = S3C2410_GPGCON;
extint_reg = S3C24XX_EXTINT1;
- gpcon_offset = (irq - IRQ_EINT8) * 2;
- extint_offset = (irq - IRQ_EINT8) * 4;
- }
- else if ((irq >= IRQ_EINT16) && (irq <= IRQ_EINT23))
- {
+ gpcon_offset = (data->irq - IRQ_EINT8) * 2;
+ extint_offset = (data->irq - IRQ_EINT8) * 4;
+ } else if ((data->irq >= IRQ_EINT16) && (data->irq <= IRQ_EINT23)) {
gpcon_reg = S3C2410_GPGCON;
extint_reg = S3C24XX_EXTINT2;
- gpcon_offset = (irq - IRQ_EINT8) * 2;
- extint_offset = (irq - IRQ_EINT16) * 4;
- } else
+ gpcon_offset = (data->irq - IRQ_EINT8) * 2;
+ extint_offset = (data->irq - IRQ_EINT16) * 4;
+ } else {
return -1;
+ }
/* Set the GPIO to external interrupt mode */
value = __raw_readl(gpcon_reg);
@@ -234,20 +226,20 @@ s3c_irqext_type(unsigned int irq, unsigned int type)
static struct irq_chip s3c_irqext_chip = {
.name = "s3c-ext",
- .mask = s3c_irqext_mask,
- .unmask = s3c_irqext_unmask,
- .ack = s3c_irqext_ack,
- .set_type = s3c_irqext_type,
- .set_wake = s3c_irqext_wake
+ .irq_mask = s3c_irqext_mask,
+ .irq_unmask = s3c_irqext_unmask,
+ .irq_ack = s3c_irqext_ack,
+ .irq_set_type = s3c_irqext_type,
+ .irq_set_wake = s3c_irqext_wake
};
static struct irq_chip s3c_irq_eint0t4 = {
.name = "s3c-ext0",
- .ack = s3c_irq_ack,
- .mask = s3c_irq_mask,
- .unmask = s3c_irq_unmask,
- .set_wake = s3c_irq_wake,
- .set_type = s3c_irqext_type,
+ .irq_ack = s3c_irq_ack,
+ .irq_mask = s3c_irq_mask,
+ .irq_unmask = s3c_irq_unmask,
+ .irq_set_wake = s3c_irq_wake,
+ .irq_set_type = s3c_irqext_type,
};
/* mask values for the parent registers for each of the interrupt types */
@@ -261,109 +253,109 @@ static struct irq_chip s3c_irq_eint0t4 = {
/* UART0 */
static void
-s3c_irq_uart0_mask(unsigned int irqno)
+s3c_irq_uart0_mask(struct irq_data *data)
{
- s3c_irqsub_mask(irqno, INTMSK_UART0, 7);
+ s3c_irqsub_mask(data->irq, INTMSK_UART0, 7);
}
static void
-s3c_irq_uart0_unmask(unsigned int irqno)
+s3c_irq_uart0_unmask(struct irq_data *data)
{
- s3c_irqsub_unmask(irqno, INTMSK_UART0);
+ s3c_irqsub_unmask(data->irq, INTMSK_UART0);
}
static void
-s3c_irq_uart0_ack(unsigned int irqno)
+s3c_irq_uart0_ack(struct irq_data *data)
{
- s3c_irqsub_maskack(irqno, INTMSK_UART0, 7);
+ s3c_irqsub_maskack(data->irq, INTMSK_UART0, 7);
}
static struct irq_chip s3c_irq_uart0 = {
.name = "s3c-uart0",
- .mask = s3c_irq_uart0_mask,
- .unmask = s3c_irq_uart0_unmask,
- .ack = s3c_irq_uart0_ack,
+ .irq_mask = s3c_irq_uart0_mask,
+ .irq_unmask = s3c_irq_uart0_unmask,
+ .irq_ack = s3c_irq_uart0_ack,
};
/* UART1 */
static void
-s3c_irq_uart1_mask(unsigned int irqno)
+s3c_irq_uart1_mask(struct irq_data *data)
{
- s3c_irqsub_mask(irqno, INTMSK_UART1, 7 << 3);
+ s3c_irqsub_mask(data->irq, INTMSK_UART1, 7 << 3);
}
static void
-s3c_irq_uart1_unmask(unsigned int irqno)
+s3c_irq_uart1_unmask(struct irq_data *data)
{
- s3c_irqsub_unmask(irqno, INTMSK_UART1);
+ s3c_irqsub_unmask(data->irq, INTMSK_UART1);
}
static void
-s3c_irq_uart1_ack(unsigned int irqno)
+s3c_irq_uart1_ack(struct irq_data *data)
{
- s3c_irqsub_maskack(irqno, INTMSK_UART1, 7 << 3);
+ s3c_irqsub_maskack(data->irq, INTMSK_UART1, 7 << 3);
}
static struct irq_chip s3c_irq_uart1 = {
.name = "s3c-uart1",
- .mask = s3c_irq_uart1_mask,
- .unmask = s3c_irq_uart1_unmask,
- .ack = s3c_irq_uart1_ack,
+ .irq_mask = s3c_irq_uart1_mask,
+ .irq_unmask = s3c_irq_uart1_unmask,
+ .irq_ack = s3c_irq_uart1_ack,
};
/* UART2 */
static void
-s3c_irq_uart2_mask(unsigned int irqno)
+s3c_irq_uart2_mask(struct irq_data *data)
{
- s3c_irqsub_mask(irqno, INTMSK_UART2, 7 << 6);
+ s3c_irqsub_mask(data->irq, INTMSK_UART2, 7 << 6);
}
static void
-s3c_irq_uart2_unmask(unsigned int irqno)
+s3c_irq_uart2_unmask(struct irq_data *data)
{
- s3c_irqsub_unmask(irqno, INTMSK_UART2);
+ s3c_irqsub_unmask(data->irq, INTMSK_UART2);
}
static void
-s3c_irq_uart2_ack(unsigned int irqno)
+s3c_irq_uart2_ack(struct irq_data *data)
{
- s3c_irqsub_maskack(irqno, INTMSK_UART2, 7 << 6);
+ s3c_irqsub_maskack(data->irq, INTMSK_UART2, 7 << 6);
}
static struct irq_chip s3c_irq_uart2 = {
.name = "s3c-uart2",
- .mask = s3c_irq_uart2_mask,
- .unmask = s3c_irq_uart2_unmask,
- .ack = s3c_irq_uart2_ack,
+ .irq_mask = s3c_irq_uart2_mask,
+ .irq_unmask = s3c_irq_uart2_unmask,
+ .irq_ack = s3c_irq_uart2_ack,
};
/* ADC and Touchscreen */
static void
-s3c_irq_adc_mask(unsigned int irqno)
+s3c_irq_adc_mask(struct irq_data *d)
{
- s3c_irqsub_mask(irqno, INTMSK_ADCPARENT, 3 << 9);
+ s3c_irqsub_mask(d->irq, INTMSK_ADCPARENT, 3 << 9);
}
static void
-s3c_irq_adc_unmask(unsigned int irqno)
+s3c_irq_adc_unmask(struct irq_data *d)
{
- s3c_irqsub_unmask(irqno, INTMSK_ADCPARENT);
+ s3c_irqsub_unmask(d->irq, INTMSK_ADCPARENT);
}
static void
-s3c_irq_adc_ack(unsigned int irqno)
+s3c_irq_adc_ack(struct irq_data *d)
{
- s3c_irqsub_ack(irqno, INTMSK_ADCPARENT, 3 << 9);
+ s3c_irqsub_ack(d->irq, INTMSK_ADCPARENT, 3 << 9);
}
static struct irq_chip s3c_irq_adc = {
.name = "s3c-adc",
- .mask = s3c_irq_adc_mask,
- .unmask = s3c_irq_adc_unmask,
- .ack = s3c_irq_adc_ack,
+ .irq_mask = s3c_irq_adc_mask,
+ .irq_unmask = s3c_irq_adc_unmask,
+ .irq_ack = s3c_irq_adc_ack,
};
/* irq demux for adc */
diff --git a/arch/arm/plat-s3c24xx/s3c2443-clock.c b/arch/arm/plat-s3c24xx/s3c2443-clock.c
index 461f070..82f2d4a 100644
--- a/arch/arm/plat-s3c24xx/s3c2443-clock.c
+++ b/arch/arm/plat-s3c24xx/s3c2443-clock.c
@@ -271,7 +271,7 @@ static struct clk init_clocks[] = {
.ctrlbit = S3C2443_HCLKCON_DMA5,
}, {
.name = "hsmmc",
- .id = 0,
+ .id = 1,
.parent = &clk_h,
.enable = s3c2443_clkcon_enable_h,
.ctrlbit = S3C2443_HCLKCON_HSMMC,
diff --git a/arch/arm/plat-s5p/Kconfig b/arch/arm/plat-s5p/Kconfig
index 65dbfa8..deb3995 100644
--- a/arch/arm/plat-s5p/Kconfig
+++ b/arch/arm/plat-s5p/Kconfig
@@ -56,3 +56,29 @@ config S5P_DEV_ONENAND
bool
help
Compile in platform device definition for OneNAND controller
+
+config S5P_DEV_CSIS0
+ bool
+ help
+ Compile in platform device definitions for MIPI-CSIS channel 0
+
+config S5P_DEV_CSIS1
+ bool
+ help
+ Compile in platform device definitions for MIPI-CSIS channel 1
+
+menuconfig S5P_SYSMMU
+ bool "SYSMMU support"
+ depends on ARCH_S5PV310
+ help
+ This is a System MMU driver for Samsung ARM based Soc.
+
+if S5P_SYSMMU
+
+config S5P_SYSMMU_DEBUG
+ bool "Enables debug messages"
+ depends on S5P_SYSMMU
+ help
+ This enables SYSMMU driver debug massages.
+
+endif
diff --git a/arch/arm/plat-s5p/Makefile b/arch/arm/plat-s5p/Makefile
index de65238..92efe1a 100644
--- a/arch/arm/plat-s5p/Makefile
+++ b/arch/arm/plat-s5p/Makefile
@@ -28,3 +28,6 @@ obj-$(CONFIG_S5P_DEV_FIMC0) += dev-fimc0.o
obj-$(CONFIG_S5P_DEV_FIMC1) += dev-fimc1.o
obj-$(CONFIG_S5P_DEV_FIMC2) += dev-fimc2.o
obj-$(CONFIG_S5P_DEV_ONENAND) += dev-onenand.o
+obj-$(CONFIG_S5P_DEV_CSIS0) += dev-csis0.o
+obj-$(CONFIG_S5P_DEV_CSIS1) += dev-csis1.o
+obj-$(CONFIG_S5P_SYSMMU) += sysmmu.o
diff --git a/arch/arm/plat-s5p/cpu.c b/arch/arm/plat-s5p/cpu.c
index 74f7f5a..047d31c 100644
--- a/arch/arm/plat-s5p/cpu.c
+++ b/arch/arm/plat-s5p/cpu.c
@@ -108,6 +108,11 @@ static struct map_desc s5p_iodesc[] __initdata = {
.pfn = __phys_to_pfn(S3C_PA_WDT),
.length = SZ_4K,
.type = MT_DEVICE,
+ }, {
+ .virtual = (unsigned long)S5P_VA_SROMC,
+ .pfn = __phys_to_pfn(S5P_PA_SROMC),
+ .length = SZ_4K,
+ .type = MT_DEVICE,
},
};
diff --git a/arch/arm/plat-s5p/dev-csis0.c b/arch/arm/plat-s5p/dev-csis0.c
new file mode 100644
index 0000000..dfab1c8
--- /dev/null
+++ b/arch/arm/plat-s5p/dev-csis0.c
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2010 Samsung Electronics
+ *
+ * S5P series device definition for MIPI-CSIS channel 0
+ *
+ * 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/interrupt.h>
+#include <linux/platform_device.h>
+#include <mach/map.h>
+
+static struct resource s5p_mipi_csis0_resource[] = {
+ [0] = {
+ .start = S5P_PA_MIPI_CSIS0,
+ .end = S5P_PA_MIPI_CSIS0 + SZ_4K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = IRQ_MIPI_CSIS0,
+ .end = IRQ_MIPI_CSIS0,
+ .flags = IORESOURCE_IRQ,
+ }
+};
+
+struct platform_device s5p_device_mipi_csis0 = {
+ .name = "s5p-mipi-csis",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(s5p_mipi_csis0_resource),
+ .resource = s5p_mipi_csis0_resource,
+};
diff --git a/arch/arm/plat-s5p/dev-csis1.c b/arch/arm/plat-s5p/dev-csis1.c
new file mode 100644
index 0000000..e3053f2
--- /dev/null
+++ b/arch/arm/plat-s5p/dev-csis1.c
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2010 Samsung Electronics
+ *
+ * S5P series device definition for MIPI-CSIS channel 1
+ *
+ * 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/interrupt.h>
+#include <linux/platform_device.h>
+#include <mach/map.h>
+
+static struct resource s5p_mipi_csis1_resource[] = {
+ [0] = {
+ .start = S5P_PA_MIPI_CSIS1,
+ .end = S5P_PA_MIPI_CSIS1 + SZ_4K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = IRQ_MIPI_CSIS1,
+ .end = IRQ_MIPI_CSIS1,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+struct platform_device s5p_device_mipi_csis1 = {
+ .name = "s5p-mipi-csis",
+ .id = 1,
+ .num_resources = ARRAY_SIZE(s5p_mipi_csis1_resource),
+ .resource = s5p_mipi_csis1_resource,
+};
diff --git a/arch/arm/plat-s5p/include/plat/csis.h b/arch/arm/plat-s5p/include/plat/csis.h
new file mode 100644
index 0000000..51e308c
--- /dev/null
+++ b/arch/arm/plat-s5p/include/plat/csis.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2010 Samsung Electronics
+ *
+ * S5P series MIPI CSI slave device support
+ *
+ * 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 PLAT_S5P_CSIS_H_
+#define PLAT_S5P_CSIS_H_ __FILE__
+
+/**
+ * struct s5p_platform_mipi_csis - platform data for MIPI-CSIS
+ * @clk_rate: bus clock frequency
+ * @lanes: number of data lanes used
+ * @alignment: data alignment in bits
+ * @hs_settle: HS-RX settle time
+ */
+struct s5p_platform_mipi_csis {
+ unsigned long clk_rate;
+ u8 lanes;
+ u8 alignment;
+ u8 hs_settle;
+};
+
+#endif /* PLAT_S5P_CSIS_H_ */
diff --git a/arch/arm/plat-s5p/include/plat/map-s5p.h b/arch/arm/plat-s5p/include/plat/map-s5p.h
index fef353d..d973d39 100644
--- a/arch/arm/plat-s5p/include/plat/map-s5p.h
+++ b/arch/arm/plat-s5p/include/plat/map-s5p.h
@@ -15,6 +15,7 @@
#define S5P_VA_CHIPID S3C_ADDR(0x02000000)
#define S5P_VA_CMU S3C_ADDR(0x02100000)
+#define S5P_VA_PMU S3C_ADDR(0x02180000)
#define S5P_VA_GPIO S3C_ADDR(0x02200000)
#define S5P_VA_GPIO1 S5P_VA_GPIO
#define S5P_VA_GPIO2 S3C_ADDR(0x02240000)
diff --git a/arch/arm/plat-s5p/include/plat/regs-srom.h b/arch/arm/plat-s5p/include/plat/regs-srom.h
new file mode 100644
index 0000000..f121ab5
--- /dev/null
+++ b/arch/arm/plat-s5p/include/plat/regs-srom.h
@@ -0,0 +1,54 @@
+/* linux/arch/arm/plat-s5p/include/plat/regs-srom.h
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * S5P SROMC register definitions
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#ifndef __ASM_PLAT_S5P_REGS_SROM_H
+#define __ASM_PLAT_S5P_REGS_SROM_H __FILE__
+
+#include <mach/map.h>
+
+#define S5P_SROMREG(x) (S5P_VA_SROMC + (x))
+
+#define S5P_SROM_BW S5P_SROMREG(0x0)
+#define S5P_SROM_BC0 S5P_SROMREG(0x4)
+#define S5P_SROM_BC1 S5P_SROMREG(0x8)
+#define S5P_SROM_BC2 S5P_SROMREG(0xc)
+#define S5P_SROM_BC3 S5P_SROMREG(0x10)
+#define S5P_SROM_BC4 S5P_SROMREG(0x14)
+#define S5P_SROM_BC5 S5P_SROMREG(0x18)
+
+/* one register BW holds 4 x 4-bit packed settings for NCS0 - NCS3 */
+
+#define S5P_SROM_BW__DATAWIDTH__SHIFT 0
+#define S5P_SROM_BW__ADDRMODE__SHIFT 1
+#define S5P_SROM_BW__WAITENABLE__SHIFT 2
+#define S5P_SROM_BW__BYTEENABLE__SHIFT 3
+
+#define S5P_SROM_BW__CS_MASK 0xf
+
+#define S5P_SROM_BW__NCS0__SHIFT 0
+#define S5P_SROM_BW__NCS1__SHIFT 4
+#define S5P_SROM_BW__NCS2__SHIFT 8
+#define S5P_SROM_BW__NCS3__SHIFT 12
+#define S5P_SROM_BW__NCS4__SHIFT 16
+#define S5P_SROM_BW__NCS5__SHIFT 20
+
+/* applies to same to BCS0 - BCS3 */
+
+#define S5P_SROM_BCX__PMC__SHIFT 0
+#define S5P_SROM_BCX__TACP__SHIFT 4
+#define S5P_SROM_BCX__TCAH__SHIFT 8
+#define S5P_SROM_BCX__TCOH__SHIFT 12
+#define S5P_SROM_BCX__TACC__SHIFT 16
+#define S5P_SROM_BCX__TCOS__SHIFT 24
+#define S5P_SROM_BCX__TACS__SHIFT 28
+
+#endif /* __ASM_PLAT_S5P_REGS_SROM_H */
diff --git a/arch/arm/plat-s5p/include/plat/sysmmu.h b/arch/arm/plat-s5p/include/plat/sysmmu.h
new file mode 100644
index 0000000..db298fc
--- /dev/null
+++ b/arch/arm/plat-s5p/include/plat/sysmmu.h
@@ -0,0 +1,23 @@
+/* linux/arch/arm/plat-s5p/include/plat/sysmmu.h
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * Samsung sysmmu driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#ifndef __ASM_PLAT_S5P_SYSMMU_H
+#define __ASM_PLAT_S5P_SYSMMU_H __FILE__
+
+/* debug macro */
+#ifdef CONFIG_S5P_SYSMMU_DEBUG
+#define sysmmu_debug(fmt, arg...) printk(KERN_INFO "[%s] " fmt, __func__, ## arg)
+#else
+#define sysmmu_debug(fmt, arg...) do { } while (0)
+#endif
+
+#endif /* __ASM_PLAT_S5P_SYSMMU_H */
diff --git a/arch/arm/plat-s5p/irq-eint.c b/arch/arm/plat-s5p/irq-eint.c
index 752f1a6..225aa25 100644
--- a/arch/arm/plat-s5p/irq-eint.c
+++ b/arch/arm/plat-s5p/irq-eint.c
@@ -28,39 +28,40 @@
#include <plat/gpio-cfg.h>
#include <mach/regs-gpio.h>
-static inline void s5p_irq_eint_mask(unsigned int irq)
+static inline void s5p_irq_eint_mask(struct irq_data *data)
{
u32 mask;
- mask = __raw_readl(S5P_EINT_MASK(EINT_REG_NR(irq)));
- mask |= eint_irq_to_bit(irq);
- __raw_writel(mask, S5P_EINT_MASK(EINT_REG_NR(irq)));
+ mask = __raw_readl(S5P_EINT_MASK(EINT_REG_NR(data->irq)));
+ mask |= eint_irq_to_bit(data->irq);
+ __raw_writel(mask, S5P_EINT_MASK(EINT_REG_NR(data->irq)));
}
-static void s5p_irq_eint_unmask(unsigned int irq)
+static void s5p_irq_eint_unmask(struct irq_data *data)
{
u32 mask;
- mask = __raw_readl(S5P_EINT_MASK(EINT_REG_NR(irq)));
- mask &= ~(eint_irq_to_bit(irq));
- __raw_writel(mask, S5P_EINT_MASK(EINT_REG_NR(irq)));
+ mask = __raw_readl(S5P_EINT_MASK(EINT_REG_NR(data->irq)));
+ mask &= ~(eint_irq_to_bit(data->irq));
+ __raw_writel(mask, S5P_EINT_MASK(EINT_REG_NR(data->irq)));
}
-static inline void s5p_irq_eint_ack(unsigned int irq)
+static inline void s5p_irq_eint_ack(struct irq_data *data)
{
- __raw_writel(eint_irq_to_bit(irq), S5P_EINT_PEND(EINT_REG_NR(irq)));
+ __raw_writel(eint_irq_to_bit(data->irq),
+ S5P_EINT_PEND(EINT_REG_NR(data->irq)));
}
-static void s5p_irq_eint_maskack(unsigned int irq)
+static void s5p_irq_eint_maskack(struct irq_data *data)
{
/* compiler should in-line these */
- s5p_irq_eint_mask(irq);
- s5p_irq_eint_ack(irq);
+ s5p_irq_eint_mask(data);
+ s5p_irq_eint_ack(data);
}
-static int s5p_irq_eint_set_type(unsigned int irq, unsigned int type)
+static int s5p_irq_eint_set_type(struct irq_data *data, unsigned int type)
{
- int offs = EINT_OFFSET(irq);
+ int offs = EINT_OFFSET(data->irq);
int shift;
u32 ctrl, mask;
u32 newvalue = 0;
@@ -94,10 +95,10 @@ static int s5p_irq_eint_set_type(unsigned int irq, unsigned int type)
shift = (offs & 0x7) * 4;
mask = 0x7 << shift;
- ctrl = __raw_readl(S5P_EINT_CON(EINT_REG_NR(irq)));
+ ctrl = __raw_readl(S5P_EINT_CON(EINT_REG_NR(data->irq)));
ctrl &= ~mask;
ctrl |= newvalue << shift;
- __raw_writel(ctrl, S5P_EINT_CON(EINT_REG_NR(irq)));
+ __raw_writel(ctrl, S5P_EINT_CON(EINT_REG_NR(data->irq)));
if ((0 <= offs) && (offs < 8))
s3c_gpio_cfgpin(EINT_GPIO_0(offs & 0x7), EINT_MODE);
@@ -119,13 +120,13 @@ static int s5p_irq_eint_set_type(unsigned int irq, unsigned int type)
static struct irq_chip s5p_irq_eint = {
.name = "s5p-eint",
- .mask = s5p_irq_eint_mask,
- .unmask = s5p_irq_eint_unmask,
- .mask_ack = s5p_irq_eint_maskack,
- .ack = s5p_irq_eint_ack,
- .set_type = s5p_irq_eint_set_type,
+ .irq_mask = s5p_irq_eint_mask,
+ .irq_unmask = s5p_irq_eint_unmask,
+ .irq_mask_ack = s5p_irq_eint_maskack,
+ .irq_ack = s5p_irq_eint_ack,
+ .irq_set_type = s5p_irq_eint_set_type,
#ifdef CONFIG_PM
- .set_wake = s3c_irqext_wake,
+ .irq_set_wake = s3c_irqext_wake,
#endif
};
@@ -159,42 +160,43 @@ static void s5p_irq_demux_eint16_31(unsigned int irq, struct irq_desc *desc)
s5p_irq_demux_eint(IRQ_EINT(24));
}
-static inline void s5p_irq_vic_eint_mask(unsigned int irq)
+static inline void s5p_irq_vic_eint_mask(struct irq_data *data)
{
- void __iomem *base = get_irq_chip_data(irq);
+ void __iomem *base = irq_data_get_irq_chip_data(data);
- s5p_irq_eint_mask(irq);
- writel(1 << EINT_OFFSET(irq), base + VIC_INT_ENABLE_CLEAR);
+ s5p_irq_eint_mask(data);
+ writel(1 << EINT_OFFSET(data->irq), base + VIC_INT_ENABLE_CLEAR);
}
-static void s5p_irq_vic_eint_unmask(unsigned int irq)
+static void s5p_irq_vic_eint_unmask(struct irq_data *data)
{
- void __iomem *base = get_irq_chip_data(irq);
+ void __iomem *base = irq_data_get_irq_chip_data(data);
- s5p_irq_eint_unmask(irq);
- writel(1 << EINT_OFFSET(irq), base + VIC_INT_ENABLE);
+ s5p_irq_eint_unmask(data);
+ writel(1 << EINT_OFFSET(data->irq), base + VIC_INT_ENABLE);
}
-static inline void s5p_irq_vic_eint_ack(unsigned int irq)
+static inline void s5p_irq_vic_eint_ack(struct irq_data *data)
{
- __raw_writel(eint_irq_to_bit(irq), S5P_EINT_PEND(EINT_REG_NR(irq)));
+ __raw_writel(eint_irq_to_bit(data->irq),
+ S5P_EINT_PEND(EINT_REG_NR(data->irq)));
}
-static void s5p_irq_vic_eint_maskack(unsigned int irq)
+static void s5p_irq_vic_eint_maskack(struct irq_data *data)
{
- s5p_irq_vic_eint_mask(irq);
- s5p_irq_vic_eint_ack(irq);
+ s5p_irq_vic_eint_mask(data);
+ s5p_irq_vic_eint_ack(data);
}
static struct irq_chip s5p_irq_vic_eint = {
.name = "s5p_vic_eint",
- .mask = s5p_irq_vic_eint_mask,
- .unmask = s5p_irq_vic_eint_unmask,
- .mask_ack = s5p_irq_vic_eint_maskack,
- .ack = s5p_irq_vic_eint_ack,
- .set_type = s5p_irq_eint_set_type,
+ .irq_mask = s5p_irq_vic_eint_mask,
+ .irq_unmask = s5p_irq_vic_eint_unmask,
+ .irq_mask_ack = s5p_irq_vic_eint_maskack,
+ .irq_ack = s5p_irq_vic_eint_ack,
+ .irq_set_type = s5p_irq_eint_set_type,
#ifdef CONFIG_PM
- .set_wake = s3c_irqext_wake,
+ .irq_set_wake = s3c_irqext_wake,
#endif
};
diff --git a/arch/arm/plat-s5p/irq-gpioint.c b/arch/arm/plat-s5p/irq-gpioint.c
index 0e5dc8c..3b6bf89 100644
--- a/arch/arm/plat-s5p/irq-gpioint.c
+++ b/arch/arm/plat-s5p/irq-gpioint.c
@@ -30,9 +30,9 @@
static struct s3c_gpio_chip *irq_chips[S5P_GPIOINT_GROUP_MAXNR];
-static int s5p_gpioint_get_group(unsigned int irq)
+static int s5p_gpioint_get_group(struct irq_data *data)
{
- struct gpio_chip *chip = get_irq_data(irq);
+ struct gpio_chip *chip = irq_data_get_irq_data(data);
struct s3c_gpio_chip *s3c_chip = container_of(chip,
struct s3c_gpio_chip, chip);
int group;
@@ -44,22 +44,22 @@ static int s5p_gpioint_get_group(unsigned int irq)
return group;
}
-static int s5p_gpioint_get_offset(unsigned int irq)
+static int s5p_gpioint_get_offset(struct irq_data *data)
{
- struct gpio_chip *chip = get_irq_data(irq);
+ struct gpio_chip *chip = irq_data_get_irq_data(data);
struct s3c_gpio_chip *s3c_chip = container_of(chip,
struct s3c_gpio_chip, chip);
- return irq - s3c_chip->irq_base;
+ return data->irq - s3c_chip->irq_base;
}
-static void s5p_gpioint_ack(unsigned int irq)
+static void s5p_gpioint_ack(struct irq_data *data)
{
int group, offset, pend_offset;
unsigned int value;
- group = s5p_gpioint_get_group(irq);
- offset = s5p_gpioint_get_offset(irq);
+ group = s5p_gpioint_get_group(data);
+ offset = s5p_gpioint_get_offset(data);
pend_offset = group << 2;
value = __raw_readl(S5P_GPIOREG(GPIOINT_PEND_OFFSET) + pend_offset);
@@ -67,13 +67,13 @@ static void s5p_gpioint_ack(unsigned int irq)
__raw_writel(value, S5P_GPIOREG(GPIOINT_PEND_OFFSET) + pend_offset);
}
-static void s5p_gpioint_mask(unsigned int irq)
+static void s5p_gpioint_mask(struct irq_data *data)
{
int group, offset, mask_offset;
unsigned int value;
- group = s5p_gpioint_get_group(irq);
- offset = s5p_gpioint_get_offset(irq);
+ group = s5p_gpioint_get_group(data);
+ offset = s5p_gpioint_get_offset(data);
mask_offset = group << 2;
value = __raw_readl(S5P_GPIOREG(GPIOINT_MASK_OFFSET) + mask_offset);
@@ -81,13 +81,13 @@ static void s5p_gpioint_mask(unsigned int irq)
__raw_writel(value, S5P_GPIOREG(GPIOINT_MASK_OFFSET) + mask_offset);
}
-static void s5p_gpioint_unmask(unsigned int irq)
+static void s5p_gpioint_unmask(struct irq_data *data)
{
int group, offset, mask_offset;
unsigned int value;
- group = s5p_gpioint_get_group(irq);
- offset = s5p_gpioint_get_offset(irq);
+ group = s5p_gpioint_get_group(data);
+ offset = s5p_gpioint_get_offset(data);
mask_offset = group << 2;
value = __raw_readl(S5P_GPIOREG(GPIOINT_MASK_OFFSET) + mask_offset);
@@ -95,19 +95,19 @@ static void s5p_gpioint_unmask(unsigned int irq)
__raw_writel(value, S5P_GPIOREG(GPIOINT_MASK_OFFSET) + mask_offset);
}
-static void s5p_gpioint_mask_ack(unsigned int irq)
+static void s5p_gpioint_mask_ack(struct irq_data *data)
{
- s5p_gpioint_mask(irq);
- s5p_gpioint_ack(irq);
+ s5p_gpioint_mask(data);
+ s5p_gpioint_ack(data);
}
-static int s5p_gpioint_set_type(unsigned int irq, unsigned int type)
+static int s5p_gpioint_set_type(struct irq_data *data, unsigned int type)
{
int group, offset, con_offset;
unsigned int value;
- group = s5p_gpioint_get_group(irq);
- offset = s5p_gpioint_get_offset(irq);
+ group = s5p_gpioint_get_group(data);
+ offset = s5p_gpioint_get_offset(data);
con_offset = group << 2;
switch (type) {
@@ -142,11 +142,11 @@ static int s5p_gpioint_set_type(unsigned int irq, unsigned int type)
struct irq_chip s5p_gpioint = {
.name = "s5p_gpioint",
- .ack = s5p_gpioint_ack,
- .mask = s5p_gpioint_mask,
- .mask_ack = s5p_gpioint_mask_ack,
- .unmask = s5p_gpioint_unmask,
- .set_type = s5p_gpioint_set_type,
+ .irq_ack = s5p_gpioint_ack,
+ .irq_mask = s5p_gpioint_mask,
+ .irq_mask_ack = s5p_gpioint_mask_ack,
+ .irq_unmask = s5p_gpioint_unmask,
+ .irq_set_type = s5p_gpioint_set_type,
};
static void s5p_gpioint_handler(unsigned int irq, struct irq_desc *desc)
diff --git a/arch/arm/plat-s5p/irq-pm.c b/arch/arm/plat-s5p/irq-pm.c
index dc33b9e..5259ad4 100644
--- a/arch/arm/plat-s5p/irq-pm.c
+++ b/arch/arm/plat-s5p/irq-pm.c
@@ -37,14 +37,14 @@
unsigned long s3c_irqwake_intallow = 0x00000006L;
unsigned long s3c_irqwake_eintallow = 0xffffffffL;
-int s3c_irq_wake(unsigned int irqno, unsigned int state)
+int s3c_irq_wake(struct irq_data *data, unsigned int state)
{
unsigned long irqbit;
- switch (irqno) {
+ switch (data->irq) {
case IRQ_RTC_TIC:
case IRQ_RTC_ALARM:
- irqbit = 1 << (irqno + 1 - IRQ_RTC_ALARM);
+ irqbit = 1 << (data->irq + 1 - IRQ_RTC_ALARM);
if (!state)
s3c_irqwake_intmask |= irqbit;
else
diff --git a/arch/arm/plat-s5p/sysmmu.c b/arch/arm/plat-s5p/sysmmu.c
new file mode 100644
index 0000000..d804914
--- /dev/null
+++ b/arch/arm/plat-s5p/sysmmu.c
@@ -0,0 +1,328 @@
+/* linux/arch/arm/plat-s5p/sysmmu.c
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ * http://www.samsung.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/io.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+
+#include <mach/map.h>
+#include <mach/regs-sysmmu.h>
+#include <mach/sysmmu.h>
+
+#include <plat/sysmmu.h>
+
+struct sysmmu_controller s5p_sysmmu_cntlrs[S5P_SYSMMU_TOTAL_IPNUM];
+
+void s5p_sysmmu_register(struct sysmmu_controller *sysmmuconp)
+{
+ unsigned int reg_mmu_ctrl;
+ unsigned int reg_mmu_status;
+ unsigned int reg_pt_base_addr;
+ unsigned int reg_int_status;
+ unsigned int reg_page_ft_addr;
+
+ reg_int_status = __raw_readl(sysmmuconp->regs + S5P_INT_STATUS);
+ reg_mmu_ctrl = __raw_readl(sysmmuconp->regs + S5P_MMU_CTRL);
+ reg_mmu_status = __raw_readl(sysmmuconp->regs + S5P_MMU_STATUS);
+ reg_pt_base_addr = __raw_readl(sysmmuconp->regs + S5P_PT_BASE_ADDR);
+ reg_page_ft_addr = __raw_readl(sysmmuconp->regs + S5P_PAGE_FAULT_ADDR);
+
+ printk(KERN_INFO "%s: ips:%s\n", __func__, sysmmuconp->name);
+ printk(KERN_INFO "%s: MMU_CTRL:0x%X, ", __func__, reg_mmu_ctrl);
+ printk(KERN_INFO "MMU_STATUS:0x%X, PT_BASE_ADDR:0x%X\n", reg_mmu_status, reg_pt_base_addr);
+ printk(KERN_INFO "%s: INT_STATUS:0x%X, PAGE_FAULT_ADDR:0x%X\n", __func__, reg_int_status, reg_page_ft_addr);
+
+ switch (reg_int_status & 0xFF) {
+ case 0x1:
+ printk(KERN_INFO "%s: Page fault\n", __func__);
+ printk(KERN_INFO "%s: Virtual address causing last page fault or bus error : 0x%x\n", __func__ , reg_page_ft_addr);
+ break;
+ case 0x2:
+ printk(KERN_INFO "%s: AR multi-hit fault\n", __func__);
+ break;
+ case 0x4:
+ printk(KERN_INFO "%s: AW multi-hit fault\n", __func__);
+ break;
+ case 0x8:
+ printk(KERN_INFO "%s: Bus error\n", __func__);
+ break;
+ case 0x10:
+ printk(KERN_INFO "%s: AR Security protection fault\n", __func__);
+ break;
+ case 0x20:
+ printk(KERN_INFO "%s: AR Access protection fault\n", __func__);
+ break;
+ case 0x40:
+ printk(KERN_INFO "%s: AW Security protection fault\n", __func__);
+ break;
+ case 0x80:
+ printk(KERN_INFO "%s: AW Access protection fault\n", __func__);
+ break;
+ }
+}
+
+static irqreturn_t s5p_sysmmu_irq(int irq, void *dev_id)
+{
+ unsigned int i;
+ unsigned int reg_int_status;
+ struct sysmmu_controller *sysmmuconp;
+
+ for (i = 0; i < S5P_SYSMMU_TOTAL_IPNUM; i++) {
+ sysmmuconp = &s5p_sysmmu_cntlrs[i];
+
+ if (sysmmuconp->enable == true) {
+ reg_int_status = __raw_readl(sysmmuconp->regs + S5P_INT_STATUS);
+
+ if (reg_int_status & 0xFF)
+ s5p_sysmmu_register(sysmmuconp);
+ }
+ }
+ return IRQ_HANDLED;
+}
+
+int s5p_sysmmu_set_tablebase_pgd(sysmmu_ips ips, unsigned long pgd)
+{
+ struct sysmmu_controller *sysmmuconp = NULL;
+
+ sysmmuconp = &s5p_sysmmu_cntlrs[ips];
+
+ if (sysmmuconp == NULL) {
+ printk(KERN_ERR "failed to get ip's sysmmu info\n");
+ return 1;
+ }
+
+ /* Set sysmmu page table base address */
+ __raw_writel(pgd, sysmmuconp->regs + S5P_PT_BASE_ADDR);
+
+ if (s5p_sysmmu_tlb_invalidate(ips) != 0)
+ printk(KERN_ERR "failed s5p_sysmmu_tlb_invalidate\n");
+
+ return 0;
+}
+
+static int s5p_sysmmu_set_tablebase(sysmmu_ips ips)
+{
+ unsigned int pg;
+ struct sysmmu_controller *sysmmuconp;
+
+ sysmmuconp = &s5p_sysmmu_cntlrs[ips];
+
+ if (sysmmuconp == NULL) {
+ printk(KERN_ERR "failed to get ip's sysmmu info\n");
+ return 1;
+ }
+
+ __asm__("mrc p15, 0, %0, c2, c0, 0" \
+ : "=r" (pg) : : "cc"); \
+ pg &= ~0x3fff;
+
+ sysmmu_debug("CP15 TTBR0 : 0x%x\n", pg);
+
+ /* Set sysmmu page table base address */
+ __raw_writel(pg, sysmmuconp->regs + S5P_PT_BASE_ADDR);
+
+ return 0;
+}
+
+int s5p_sysmmu_enable(sysmmu_ips ips)
+{
+ unsigned int reg;
+
+ struct sysmmu_controller *sysmmuconp;
+
+ sysmmuconp = &s5p_sysmmu_cntlrs[ips];
+
+ if (sysmmuconp == NULL) {
+ printk(KERN_ERR "failed to get ip's sysmmu info\n");
+ return 1;
+ }
+
+ s5p_sysmmu_set_tablebase(ips);
+
+ /* replacement policy : LRU */
+ reg = __raw_readl(sysmmuconp->regs + S5P_MMU_CFG);
+ reg |= 0x1;
+ __raw_writel(reg, sysmmuconp->regs + S5P_MMU_CFG);
+
+ /* Enable interrupt, Enable MMU */
+ reg = __raw_readl(sysmmuconp->regs + S5P_MMU_CTRL);
+ reg |= (0x1 << 2) | (0x1 << 0);
+
+ __raw_writel(reg, sysmmuconp->regs + S5P_MMU_CTRL);
+
+ sysmmuconp->enable = true;
+
+ return 0;
+}
+
+int s5p_sysmmu_disable(sysmmu_ips ips)
+{
+ unsigned int reg;
+
+ struct sysmmu_controller *sysmmuconp = NULL;
+
+ if (ips > S5P_SYSMMU_TOTAL_IPNUM)
+ printk(KERN_ERR "failed to get ips parameter\n");
+
+ sysmmuconp = &s5p_sysmmu_cntlrs[ips];
+
+ if (sysmmuconp == NULL) {
+ printk(KERN_ERR "failed to get ip's sysmmu info\n");
+ return 1;
+ }
+
+ reg = __raw_readl(sysmmuconp->regs + S5P_MMU_CFG);
+
+ /* replacement policy : LRU */
+ reg |= 0x1;
+ __raw_writel(reg, sysmmuconp->regs + S5P_MMU_CFG);
+
+ reg = __raw_readl(sysmmuconp->regs + S5P_MMU_CTRL);
+
+ /* Disable MMU */
+ reg &= ~0x1;
+ __raw_writel(reg, sysmmuconp->regs + S5P_MMU_CTRL);
+
+ sysmmuconp->enable = false;
+
+ return 0;
+}
+
+int s5p_sysmmu_tlb_invalidate(sysmmu_ips ips)
+{
+ unsigned int reg;
+ struct sysmmu_controller *sysmmuconp = NULL;
+
+ sysmmuconp = &s5p_sysmmu_cntlrs[ips];
+
+ if (sysmmuconp == NULL) {
+ printk(KERN_ERR "failed to get ip's sysmmu info\n");
+ return 1;
+ }
+
+ /* set Block MMU for flush TLB */
+ reg = __raw_readl(sysmmuconp->regs + S5P_MMU_CTRL);
+ reg |= 0x1 << 1;
+ __raw_writel(reg, sysmmuconp->regs + S5P_MMU_CTRL);
+
+ /* flush all TLB entry */
+ __raw_writel(0x1, sysmmuconp->regs + S5P_MMU_FLUSH);
+
+ /* set Un-block MMU after flush TLB */
+ reg = __raw_readl(sysmmuconp->regs + S5P_MMU_CTRL);
+ reg &= ~(0x1 << 1);
+ __raw_writel(reg, sysmmuconp->regs + S5P_MMU_CTRL);
+
+ return 0;
+}
+
+static int s5p_sysmmu_probe(struct platform_device *pdev)
+{
+ int i;
+ int ret;
+ struct resource *res;
+ struct sysmmu_controller *sysmmuconp;
+ sysmmu_ips ips;
+
+ for (i = 0; i < S5P_SYSMMU_TOTAL_IPNUM; i++) {
+ sysmmuconp = &s5p_sysmmu_cntlrs[i];
+ if (sysmmuconp == NULL) {
+ printk(KERN_ERR "failed to get ip's sysmmu info\n");
+ ret = -ENOENT;
+ goto err_res;
+ }
+
+ sysmmuconp->name = sysmmu_ips_name[i];
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, i);
+ if (!res) {
+ printk(KERN_ERR "failed to get sysmmu resource\n");
+ ret = -ENODEV;
+ goto err_res;
+ }
+
+ sysmmuconp->mem = request_mem_region(res->start,
+ ((res->end) - (res->start)) + 1, pdev->name);
+ if (!sysmmuconp->mem) {
+ pr_err("failed to request sysmmu memory region\n");
+ ret = -EBUSY;
+ goto err_res;
+ }
+
+ sysmmuconp->regs = ioremap(res->start, res->end - res->start + 1);
+ if (!sysmmuconp->regs) {
+ pr_err("failed to sysmmu ioremap\n");
+ ret = -ENXIO;
+ goto err_reg;
+ }
+
+ sysmmuconp->irq = platform_get_irq(pdev, i);
+ if (sysmmuconp->irq <= 0) {
+ pr_err("failed to get sysmmu irq resource\n");
+ ret = -ENOENT;
+ goto err_map;
+ }
+
+ ret = request_irq(sysmmuconp->irq, s5p_sysmmu_irq, IRQF_DISABLED, pdev->name, sysmmuconp);
+ if (ret) {
+ pr_err("failed to request irq\n");
+ ret = -ENOENT;
+ goto err_map;
+ }
+
+ ips = (sysmmu_ips)i;
+
+ sysmmuconp->ips = ips;
+ }
+
+ return 0;
+
+err_reg:
+ release_mem_region((resource_size_t)sysmmuconp->mem, (resource_size_t)((res->end) - (res->start) + 1));
+err_map:
+ iounmap(sysmmuconp->regs);
+err_res:
+ return ret;
+}
+
+static int s5p_sysmmu_remove(struct platform_device *pdev)
+{
+ return 0;
+}
+int s5p_sysmmu_runtime_suspend(struct device *dev)
+{
+ return 0;
+}
+
+int s5p_sysmmu_runtime_resume(struct device *dev)
+{
+ return 0;
+}
+
+const struct dev_pm_ops s5p_sysmmu_pm_ops = {
+ .runtime_suspend = s5p_sysmmu_runtime_suspend,
+ .runtime_resume = s5p_sysmmu_runtime_resume,
+};
+
+static struct platform_driver s5p_sysmmu_driver = {
+ .probe = s5p_sysmmu_probe,
+ .remove = s5p_sysmmu_remove,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "s5p-sysmmu",
+ .pm = &s5p_sysmmu_pm_ops,
+ }
+};
+
+static int __init s5p_sysmmu_init(void)
+{
+ return platform_driver_register(&s5p_sysmmu_driver);
+}
+arch_initcall(s5p_sysmmu_init);
diff --git a/arch/arm/plat-samsung/Kconfig b/arch/arm/plat-samsung/Kconfig
index dcd6eff4e..32be05c 100644
--- a/arch/arm/plat-samsung/Kconfig
+++ b/arch/arm/plat-samsung/Kconfig
@@ -95,6 +95,12 @@ config S3C_GPIO_PULL_UPDOWN
help
Internal configuration to enable the correct GPIO pull helper
+config S3C_GPIO_PULL_S3C2443
+ bool
+ select S3C_GPIO_PULL_UPDOWN
+ help
+ Internal configuration to enable the correct GPIO pull helper for S3C2443-style GPIO
+
config S3C_GPIO_PULL_DOWN
bool
help
@@ -333,4 +339,12 @@ config SAMSUNG_WAKEMASK
and above. This code allows a set of interrupt to wakeup-mask
mappings. See <plat/wakeup-mask.h>
+comment "Power Domain"
+
+config SAMSUNG_PD
+ bool "Samsung Power Domain"
+ depends on PM_RUNTIME
+ help
+ Say Y here if you want to control Power Domain by Runtime PM.
+
endif
diff --git a/arch/arm/plat-samsung/Makefile b/arch/arm/plat-samsung/Makefile
index 19d8a16..29932f8 100644
--- a/arch/arm/plat-samsung/Makefile
+++ b/arch/arm/plat-samsung/Makefile
@@ -74,6 +74,10 @@ obj-$(CONFIG_SAMSUNG_PM_CHECK) += pm-check.o
obj-$(CONFIG_SAMSUNG_WAKEMASK) += wakeup-mask.o
+# PD support
+
+obj-$(CONFIG_SAMSUNG_PD) += pd.o
+
# PWM support
obj-$(CONFIG_HAVE_PWM) += pwm.o
diff --git a/arch/arm/plat-samsung/clock.c b/arch/arm/plat-samsung/clock.c
index e8d20b0..7728928 100644
--- a/arch/arm/plat-samsung/clock.c
+++ b/arch/arm/plat-samsung/clock.c
@@ -39,6 +39,9 @@
#include <linux/clk.h>
#include <linux/spinlock.h>
#include <linux/io.h>
+#if defined(CONFIG_DEBUG_FS)
+#include <linux/debugfs.h>
+#endif
#include <mach/hardware.h>
#include <asm/irq.h>
@@ -447,3 +450,92 @@ int __init s3c24xx_register_baseclocks(unsigned long xtal)
return 0;
}
+#if defined(CONFIG_PM_DEBUG) && defined(CONFIG_DEBUG_FS)
+/* debugfs support to trace clock tree hierarchy and attributes */
+
+static struct dentry *clk_debugfs_root;
+
+static int clk_debugfs_register_one(struct clk *c)
+{
+ int err;
+ struct dentry *d, *child, *child_tmp;
+ struct clk *pa = c->parent;
+ char s[255];
+ char *p = s;
+
+ p += sprintf(p, "%s", c->name);
+
+ if (c->id >= 0)
+ sprintf(p, ":%d", c->id);
+
+ d = debugfs_create_dir(s, pa ? pa->dent : clk_debugfs_root);
+ if (!d)
+ return -ENOMEM;
+
+ c->dent = d;
+
+ d = debugfs_create_u8("usecount", S_IRUGO, c->dent, (u8 *)&c->usage);
+ if (!d) {
+ err = -ENOMEM;
+ goto err_out;
+ }
+
+ d = debugfs_create_u32("rate", S_IRUGO, c->dent, (u32 *)&c->rate);
+ if (!d) {
+ err = -ENOMEM;
+ goto err_out;
+ }
+ return 0;
+
+err_out:
+ d = c->dent;
+ list_for_each_entry_safe(child, child_tmp, &d->d_subdirs, d_u.d_child)
+ debugfs_remove(child);
+ debugfs_remove(c->dent);
+ return err;
+}
+
+static int clk_debugfs_register(struct clk *c)
+{
+ int err;
+ struct clk *pa = c->parent;
+
+ if (pa && !pa->dent) {
+ err = clk_debugfs_register(pa);
+ if (err)
+ return err;
+ }
+
+ if (!c->dent) {
+ err = clk_debugfs_register_one(c);
+ if (err)
+ return err;
+ }
+ return 0;
+}
+
+static int __init clk_debugfs_init(void)
+{
+ struct clk *c;
+ struct dentry *d;
+ int err;
+
+ d = debugfs_create_dir("clock", NULL);
+ if (!d)
+ return -ENOMEM;
+ clk_debugfs_root = d;
+
+ list_for_each_entry(c, &clocks, list) {
+ err = clk_debugfs_register(c);
+ if (err)
+ goto err_out;
+ }
+ return 0;
+
+err_out:
+ debugfs_remove_recursive(clk_debugfs_root);
+ return err;
+}
+late_initcall(clk_debugfs_init);
+
+#endif /* defined(CONFIG_PM_DEBUG) && defined(CONFIG_DEBUG_FS) */
diff --git a/arch/arm/plat-samsung/dev-nand.c b/arch/arm/plat-samsung/dev-nand.c
index 3a7b889..6927ae8 100644
--- a/arch/arm/plat-samsung/dev-nand.c
+++ b/arch/arm/plat-samsung/dev-nand.c
@@ -126,5 +126,3 @@ void __init s3c_nand_set_platdata(struct s3c2410_platform_nand *nand)
s3c_device_nand.dev.platform_data = npd;
}
-
-EXPORT_SYMBOL_GPL(s3c_nand_set_platdata);
diff --git a/arch/arm/plat-samsung/gpio-config.c b/arch/arm/plat-samsung/gpio-config.c
index 0aa32f2..1c0b040 100644
--- a/arch/arm/plat-samsung/gpio-config.c
+++ b/arch/arm/plat-samsung/gpio-config.c
@@ -278,6 +278,48 @@ s3c_gpio_pull_t s3c_gpio_getpull_updown(struct s3c_gpio_chip *chip,
pup &= 0x3;
return (__force s3c_gpio_pull_t)pup;
}
+
+#ifdef CONFIG_S3C_GPIO_PULL_S3C2443
+int s3c_gpio_setpull_s3c2443(struct s3c_gpio_chip *chip,
+ unsigned int off, s3c_gpio_pull_t pull)
+{
+ switch (pull) {
+ case S3C_GPIO_PULL_NONE:
+ pull = 0x01;
+ break;
+ case S3C_GPIO_PULL_UP:
+ pull = 0x00;
+ break;
+ case S3C_GPIO_PULL_DOWN:
+ pull = 0x02;
+ break;
+ }
+ return s3c_gpio_setpull_updown(chip, off, pull);
+}
+
+s3c_gpio_pull_t s3c_gpio_getpull_s3c2443(struct s3c_gpio_chip *chip,
+ unsigned int off)
+{
+ s3c_gpio_pull_t pull;
+
+ pull = s3c_gpio_getpull_updown(chip, off);
+
+ switch (pull) {
+ case 0x00:
+ pull = S3C_GPIO_PULL_UP;
+ break;
+ case 0x01:
+ case 0x03:
+ pull = S3C_GPIO_PULL_NONE;
+ break;
+ case 0x02:
+ pull = S3C_GPIO_PULL_DOWN;
+ break;
+ }
+
+ return pull;
+}
+#endif
#endif
#if defined(CONFIG_S3C_GPIO_PULL_UP) || defined(CONFIG_S3C_GPIO_PULL_DOWN)
diff --git a/arch/arm/plat-samsung/gpiolib.c b/arch/arm/plat-samsung/gpiolib.c
index c354089..ea37c04 100644
--- a/arch/arm/plat-samsung/gpiolib.c
+++ b/arch/arm/plat-samsung/gpiolib.c
@@ -197,3 +197,10 @@ void __init samsung_gpiolib_add_4bit2_chips(struct s3c_gpio_chip *chip,
s3c_gpiolib_add(chip);
}
}
+
+void __init samsung_gpiolib_add_2bit_chips(struct s3c_gpio_chip *chip,
+ int nr_chips)
+{
+ for (; nr_chips > 0; nr_chips--, chip++)
+ s3c_gpiolib_add(chip);
+}
diff --git a/arch/arm/plat-samsung/include/plat/clock.h b/arch/arm/plat-samsung/include/plat/clock.h
index 0fbcd0e..9a82b88 100644
--- a/arch/arm/plat-samsung/include/plat/clock.h
+++ b/arch/arm/plat-samsung/include/plat/clock.h
@@ -47,6 +47,9 @@ struct clk {
struct clk_ops *ops;
int (*enable)(struct clk *, int enable);
+#if defined(CONFIG_PM_DEBUG) && defined(CONFIG_DEBUG_FS)
+ struct dentry *dent; /* For visible tree hierarchy */
+#endif
};
/* other clocks which may be registered by board support */
diff --git a/arch/arm/plat-samsung/include/plat/devs.h b/arch/arm/plat-samsung/include/plat/devs.h
index e9e3b6e..b4d208b 100644
--- a/arch/arm/plat-samsung/include/plat/devs.h
+++ b/arch/arm/plat-samsung/include/plat/devs.h
@@ -104,6 +104,7 @@ extern struct platform_device s5pv310_device_i2s0;
extern struct platform_device s5pv310_device_i2s1;
extern struct platform_device s5pv310_device_i2s2;
extern struct platform_device s5pv310_device_spdif;
+extern struct platform_device s5pv310_device_pd[];
extern struct platform_device s5p6442_device_pcm0;
extern struct platform_device s5p6442_device_pcm1;
@@ -115,6 +116,8 @@ extern struct platform_device s5p6440_device_pcm;
extern struct platform_device s5p6440_device_iis;
extern struct platform_device s5p6450_device_iis0;
+extern struct platform_device s5p6450_device_iis1;
+extern struct platform_device s5p6450_device_iis2;
extern struct platform_device s5p6450_device_pcm0;
extern struct platform_device s5pc100_device_ac97;
@@ -131,6 +134,11 @@ extern struct platform_device s5p_device_fimc0;
extern struct platform_device s5p_device_fimc1;
extern struct platform_device s5p_device_fimc2;
+extern struct platform_device s5p_device_mipi_csis0;
+extern struct platform_device s5p_device_mipi_csis1;
+
+extern struct platform_device s5pv310_device_sysmmu;
+
/* s3c2440 specific devices */
#ifdef CONFIG_CPU_S3C2440
diff --git a/arch/arm/plat-samsung/include/plat/gpio-cfg-helpers.h b/arch/arm/plat-samsung/include/plat/gpio-cfg-helpers.h
index 0d2c570..5603db0 100644
--- a/arch/arm/plat-samsung/include/plat/gpio-cfg-helpers.h
+++ b/arch/arm/plat-samsung/include/plat/gpio-cfg-helpers.h
@@ -244,7 +244,7 @@ extern int s3c_gpio_setpull_s3c2443(struct s3c_gpio_chip *chip,
* This helper function reads the state of the pull-{up,down} resistor for the
* given GPIO in the same case as s3c_gpio_setpull_upown.
*/
-extern s3c_gpio_pull_t s3c_gpio_getpull_s3c24xx(struct s3c_gpio_chip *chip,
+extern s3c_gpio_pull_t s3c_gpio_getpull_s3c2443(struct s3c_gpio_chip *chip,
unsigned int off);
#endif /* __PLAT_GPIO_CFG_HELPERS_H */
diff --git a/arch/arm/plat-samsung/include/plat/gpio-core.h b/arch/arm/plat-samsung/include/plat/gpio-core.h
index 13a22b8..dac35d0 100644
--- a/arch/arm/plat-samsung/include/plat/gpio-core.h
+++ b/arch/arm/plat-samsung/include/plat/gpio-core.h
@@ -118,6 +118,8 @@ extern void samsung_gpiolib_add_4bit_chips(struct s3c_gpio_chip *chip,
int nr_chips);
extern void samsung_gpiolib_add_4bit2_chips(struct s3c_gpio_chip *chip,
int nr_chips);
+extern void samsung_gpiolib_add_2bit_chips(struct s3c_gpio_chip *chip,
+ int nr_chips);
extern void samsung_gpiolib_add_4bit(struct s3c_gpio_chip *chip);
extern void samsung_gpiolib_add_4bit2(struct s3c_gpio_chip *chip);
diff --git a/arch/arm/plat-samsung/include/plat/pd.h b/arch/arm/plat-samsung/include/plat/pd.h
new file mode 100644
index 0000000..5f0ad85
--- /dev/null
+++ b/arch/arm/plat-samsung/include/plat/pd.h
@@ -0,0 +1,30 @@
+/* linux/arch/arm/plat-samsung/include/plat/pd.h
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ * http://www.samsung.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.
+*/
+
+#ifndef __ASM_PLAT_SAMSUNG_PD_H
+#define __ASM_PLAT_SAMSUNG_PD_H __FILE__
+
+struct samsung_pd_info {
+ int (*enable)(struct device *dev);
+ int (*disable)(struct device *dev);
+ void __iomem *base;
+};
+
+enum s5pv310_pd_block {
+ PD_MFC,
+ PD_G3D,
+ PD_LCD0,
+ PD_LCD1,
+ PD_TV,
+ PD_CAM,
+ PD_GPS
+};
+
+#endif /* __ASM_PLAT_SAMSUNG_PD_H */
diff --git a/arch/arm/plat-samsung/include/plat/pm.h b/arch/arm/plat-samsung/include/plat/pm.h
index 245836d..d9025e3 100644
--- a/arch/arm/plat-samsung/include/plat/pm.h
+++ b/arch/arm/plat-samsung/include/plat/pm.h
@@ -15,6 +15,8 @@
* management
*/
+#include <linux/irq.h>
+
#ifdef CONFIG_PM
extern __init int s3c_pm_init(void);
@@ -100,7 +102,7 @@ extern void s3c_pm_do_restore(struct sleep_save *ptr, int count);
extern void s3c_pm_do_restore_core(struct sleep_save *ptr, int count);
#ifdef CONFIG_PM
-extern int s3c_irqext_wake(unsigned int irqno, unsigned int state);
+extern int s3c_irqext_wake(struct irq_data *data, unsigned int state);
extern int s3c24xx_irq_suspend(struct sys_device *dev, pm_message_t state);
extern int s3c24xx_irq_resume(struct sys_device *dev);
#else
diff --git a/arch/arm/plat-samsung/include/plat/sdhci.h b/arch/arm/plat-samsung/include/plat/sdhci.h
index 85853f8..5a41a0b 100644
--- a/arch/arm/plat-samsung/include/plat/sdhci.h
+++ b/arch/arm/plat-samsung/include/plat/sdhci.h
@@ -107,6 +107,8 @@ extern struct s3c_sdhci_platdata s3c_hsmmc3_def_platdata;
/* Helper function availablity */
+extern void s3c2416_setup_sdhci0_cfg_gpio(struct platform_device *, int w);
+extern void s3c2416_setup_sdhci1_cfg_gpio(struct platform_device *, int w);
extern void s3c64xx_setup_sdhci0_cfg_gpio(struct platform_device *, int w);
extern void s3c64xx_setup_sdhci1_cfg_gpio(struct platform_device *, int w);
extern void s5pc100_setup_sdhci0_cfg_gpio(struct platform_device *, int w);
@@ -122,6 +124,39 @@ extern void s5pv310_setup_sdhci1_cfg_gpio(struct platform_device *, int w);
extern void s5pv310_setup_sdhci2_cfg_gpio(struct platform_device *, int w);
extern void s5pv310_setup_sdhci3_cfg_gpio(struct platform_device *, int w);
+/* S3C2416 SDHCI setup */
+
+#ifdef CONFIG_S3C2416_SETUP_SDHCI
+extern char *s3c2416_hsmmc_clksrcs[4];
+
+extern void s3c2416_setup_sdhci_cfg_card(struct platform_device *dev,
+ void __iomem *r,
+ struct mmc_ios *ios,
+ struct mmc_card *card);
+
+static inline void s3c2416_default_sdhci0(void)
+{
+#ifdef CONFIG_S3C_DEV_HSMMC
+ s3c_hsmmc0_def_platdata.clocks = s3c2416_hsmmc_clksrcs;
+ s3c_hsmmc0_def_platdata.cfg_gpio = s3c2416_setup_sdhci0_cfg_gpio;
+ s3c_hsmmc0_def_platdata.cfg_card = s3c2416_setup_sdhci_cfg_card;
+#endif /* CONFIG_S3C_DEV_HSMMC */
+}
+
+static inline void s3c2416_default_sdhci1(void)
+{
+#ifdef CONFIG_S3C_DEV_HSMMC1
+ s3c_hsmmc1_def_platdata.clocks = s3c2416_hsmmc_clksrcs;
+ s3c_hsmmc1_def_platdata.cfg_gpio = s3c2416_setup_sdhci1_cfg_gpio;
+ s3c_hsmmc1_def_platdata.cfg_card = s3c2416_setup_sdhci_cfg_card;
+#endif /* CONFIG_S3C_DEV_HSMMC1 */
+}
+
+#else
+static inline void s3c2416_default_sdhci0(void) { }
+static inline void s3c2416_default_sdhci1(void) { }
+
+#endif /* CONFIG_S3C2416_SETUP_SDHCI */
/* S3C64XX SDHCI setup */
#ifdef CONFIG_S3C64XX_SETUP_SDHCI
diff --git a/arch/arm/plat-samsung/irq-uart.c b/arch/arm/plat-samsung/irq-uart.c
index 4f8c102..4e77035 100644
--- a/arch/arm/plat-samsung/irq-uart.c
+++ b/arch/arm/plat-samsung/irq-uart.c
@@ -28,9 +28,9 @@
* are consecutive when looking up the interrupt in the demux routines.
*/
-static inline void __iomem *s3c_irq_uart_base(unsigned int irq)
+static inline void __iomem *s3c_irq_uart_base(struct irq_data *data)
{
- struct s3c_uart_irq *uirq = get_irq_chip_data(irq);
+ struct s3c_uart_irq *uirq = irq_data_get_irq_chip_data(data);
return uirq->regs;
}
@@ -39,10 +39,10 @@ static inline unsigned int s3c_irq_uart_bit(unsigned int irq)
return irq & 3;
}
-static void s3c_irq_uart_mask(unsigned int irq)
+static void s3c_irq_uart_mask(struct irq_data *data)
{
- void __iomem *regs = s3c_irq_uart_base(irq);
- unsigned int bit = s3c_irq_uart_bit(irq);
+ void __iomem *regs = s3c_irq_uart_base(data);
+ unsigned int bit = s3c_irq_uart_bit(data->irq);
u32 reg;
reg = __raw_readl(regs + S3C64XX_UINTM);
@@ -50,10 +50,10 @@ static void s3c_irq_uart_mask(unsigned int irq)
__raw_writel(reg, regs + S3C64XX_UINTM);
}
-static void s3c_irq_uart_maskack(unsigned int irq)
+static void s3c_irq_uart_maskack(struct irq_data *data)
{
- void __iomem *regs = s3c_irq_uart_base(irq);
- unsigned int bit = s3c_irq_uart_bit(irq);
+ void __iomem *regs = s3c_irq_uart_base(data);
+ unsigned int bit = s3c_irq_uart_bit(data->irq);
u32 reg;
reg = __raw_readl(regs + S3C64XX_UINTM);
@@ -62,10 +62,10 @@ static void s3c_irq_uart_maskack(unsigned int irq)
__raw_writel(1 << bit, regs + S3C64XX_UINTP);
}
-static void s3c_irq_uart_unmask(unsigned int irq)
+static void s3c_irq_uart_unmask(struct irq_data *data)
{
- void __iomem *regs = s3c_irq_uart_base(irq);
- unsigned int bit = s3c_irq_uart_bit(irq);
+ void __iomem *regs = s3c_irq_uart_base(data);
+ unsigned int bit = s3c_irq_uart_bit(data->irq);
u32 reg;
reg = __raw_readl(regs + S3C64XX_UINTM);
@@ -73,17 +73,17 @@ static void s3c_irq_uart_unmask(unsigned int irq)
__raw_writel(reg, regs + S3C64XX_UINTM);
}
-static void s3c_irq_uart_ack(unsigned int irq)
+static void s3c_irq_uart_ack(struct irq_data *data)
{
- void __iomem *regs = s3c_irq_uart_base(irq);
- unsigned int bit = s3c_irq_uart_bit(irq);
+ void __iomem *regs = s3c_irq_uart_base(data);
+ unsigned int bit = s3c_irq_uart_bit(data->irq);
__raw_writel(1 << bit, regs + S3C64XX_UINTP);
}
static void s3c_irq_demux_uart(unsigned int irq, struct irq_desc *desc)
{
- struct s3c_uart_irq *uirq = desc->handler_data;
+ struct s3c_uart_irq *uirq = desc->irq_data.handler_data;
u32 pend = __raw_readl(uirq->regs + S3C64XX_UINTP);
int base = uirq->base_irq;
@@ -99,10 +99,10 @@ static void s3c_irq_demux_uart(unsigned int irq, struct irq_desc *desc)
static struct irq_chip s3c_irq_uart = {
.name = "s3c-uart",
- .mask = s3c_irq_uart_mask,
- .unmask = s3c_irq_uart_unmask,
- .mask_ack = s3c_irq_uart_maskack,
- .ack = s3c_irq_uart_ack,
+ .irq_mask = s3c_irq_uart_mask,
+ .irq_unmask = s3c_irq_uart_unmask,
+ .irq_mask_ack = s3c_irq_uart_maskack,
+ .irq_ack = s3c_irq_uart_ack,
};
static void __init s3c_init_uart_irq(struct s3c_uart_irq *uirq)
@@ -124,7 +124,7 @@ static void __init s3c_init_uart_irq(struct s3c_uart_irq *uirq)
set_irq_flags(irq, IRQF_VALID);
}
- desc->handler_data = uirq;
+ desc->irq_data.handler_data = uirq;
set_irq_chained_handler(uirq->parent_irq, s3c_irq_demux_uart);
}
diff --git a/arch/arm/plat-samsung/irq-vic-timer.c b/arch/arm/plat-samsung/irq-vic-timer.c
index 0270519..dd8692a 100644
--- a/arch/arm/plat-samsung/irq-vic-timer.c
+++ b/arch/arm/plat-samsung/irq-vic-timer.c
@@ -24,43 +24,46 @@
static void s3c_irq_demux_vic_timer(unsigned int irq, struct irq_desc *desc)
{
- generic_handle_irq((int)desc->handler_data);
+ generic_handle_irq((int)desc->irq_data.handler_data);
}
/* We assume the IRQ_TIMER0..IRQ_TIMER4 range is continuous. */
-static void s3c_irq_timer_mask(unsigned int irq)
+static void s3c_irq_timer_mask(struct irq_data *data)
{
u32 reg = __raw_readl(S3C64XX_TINT_CSTAT);
+ u32 mask = (u32)data->chip_data;
reg &= 0x1f; /* mask out pending interrupts */
- reg &= ~(1 << (irq - IRQ_TIMER0));
+ reg &= ~mask;
__raw_writel(reg, S3C64XX_TINT_CSTAT);
}
-static void s3c_irq_timer_unmask(unsigned int irq)
+static void s3c_irq_timer_unmask(struct irq_data *data)
{
u32 reg = __raw_readl(S3C64XX_TINT_CSTAT);
+ u32 mask = (u32)data->chip_data;
reg &= 0x1f; /* mask out pending interrupts */
- reg |= 1 << (irq - IRQ_TIMER0);
+ reg |= mask;
__raw_writel(reg, S3C64XX_TINT_CSTAT);
}
-static void s3c_irq_timer_ack(unsigned int irq)
+static void s3c_irq_timer_ack(struct irq_data *data)
{
u32 reg = __raw_readl(S3C64XX_TINT_CSTAT);
+ u32 mask = (u32)data->chip_data;
reg &= 0x1f;
- reg |= (1 << 5) << (irq - IRQ_TIMER0);
+ reg |= mask << 5;
__raw_writel(reg, S3C64XX_TINT_CSTAT);
}
static struct irq_chip s3c_irq_timer = {
.name = "s3c-timer",
- .mask = s3c_irq_timer_mask,
- .unmask = s3c_irq_timer_unmask,
- .ack = s3c_irq_timer_ack,
+ .irq_mask = s3c_irq_timer_mask,
+ .irq_unmask = s3c_irq_timer_unmask,
+ .irq_ack = s3c_irq_timer_ack,
};
/**
@@ -79,8 +82,9 @@ void __init s3c_init_vic_timer_irq(unsigned int parent_irq,
set_irq_chained_handler(parent_irq, s3c_irq_demux_vic_timer);
set_irq_chip(timer_irq, &s3c_irq_timer);
+ set_irq_chip_data(timer_irq, (void *)(1 << (timer_irq - IRQ_TIMER0)));
set_irq_handler(timer_irq, handle_level_irq);
set_irq_flags(timer_irq, IRQF_VALID);
- desc->handler_data = (void *)timer_irq;
+ desc->irq_data.handler_data = (void *)timer_irq;
}
diff --git a/arch/arm/plat-samsung/pd.c b/arch/arm/plat-samsung/pd.c
new file mode 100644
index 0000000..efe1d56
--- /dev/null
+++ b/arch/arm/plat-samsung/pd.c
@@ -0,0 +1,95 @@
+/* linux/arch/arm/plat-samsung/pd.c
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * Samsung Power domain support
+ *
+ * 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/module.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/pm_runtime.h>
+
+#include <plat/pd.h>
+
+static int samsung_pd_probe(struct platform_device *pdev)
+{
+ struct samsung_pd_info *pdata = pdev->dev.platform_data;
+ struct device *dev = &pdev->dev;
+
+ if (!pdata) {
+ dev_err(dev, "no device data specified\n");
+ return -ENOENT;
+ }
+
+ pm_runtime_set_active(dev);
+ pm_runtime_enable(dev);
+
+ dev_info(dev, "power domain registered\n");
+ return 0;
+}
+
+static int __devexit samsung_pd_remove(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+
+ pm_runtime_disable(dev);
+ return 0;
+}
+
+static int samsung_pd_runtime_suspend(struct device *dev)
+{
+ struct samsung_pd_info *pdata = dev->platform_data;
+ int ret = 0;
+
+ if (pdata->disable)
+ ret = pdata->disable(dev);
+
+ dev_dbg(dev, "suspended\n");
+ return ret;
+}
+
+static int samsung_pd_runtime_resume(struct device *dev)
+{
+ struct samsung_pd_info *pdata = dev->platform_data;
+ int ret = 0;
+
+ if (pdata->enable)
+ ret = pdata->enable(dev);
+
+ dev_dbg(dev, "resumed\n");
+ return ret;
+}
+
+static const struct dev_pm_ops samsung_pd_pm_ops = {
+ .runtime_suspend = samsung_pd_runtime_suspend,
+ .runtime_resume = samsung_pd_runtime_resume,
+};
+
+static struct platform_driver samsung_pd_driver = {
+ .driver = {
+ .name = "samsung-pd",
+ .owner = THIS_MODULE,
+ .pm = &samsung_pd_pm_ops,
+ },
+ .probe = samsung_pd_probe,
+ .remove = __devexit_p(samsung_pd_remove),
+};
+
+static int __init samsung_pd_init(void)
+{
+ int ret;
+
+ ret = platform_driver_register(&samsung_pd_driver);
+ if (ret)
+ printk(KERN_ERR "%s: failed to add PD driver\n", __func__);
+
+ return ret;
+}
+arch_initcall(samsung_pd_init);
diff --git a/arch/arm/plat-samsung/pm.c b/arch/arm/plat-samsung/pm.c
index 5bf3f2f..02d531f 100644
--- a/arch/arm/plat-samsung/pm.c
+++ b/arch/arm/plat-samsung/pm.c
@@ -136,15 +136,15 @@ static void s3c_pm_restore_uarts(void) { }
unsigned long s3c_irqwake_intmask = 0xffffffffL;
unsigned long s3c_irqwake_eintmask = 0xffffffffL;
-int s3c_irqext_wake(unsigned int irqno, unsigned int state)
+int s3c_irqext_wake(struct irq_data *data, unsigned int state)
{
- unsigned long bit = 1L << IRQ_EINT_BIT(irqno);
+ unsigned long bit = 1L << IRQ_EINT_BIT(data->irq);
if (!(s3c_irqwake_eintallow & bit))
return -ENOENT;
printk(KERN_INFO "wake %s for irq %d\n",
- state ? "enabled" : "disabled", irqno);
+ state ? "enabled" : "disabled", data->irq);
if (!state)
s3c_irqwake_eintmask |= bit;
diff --git a/arch/arm/plat-spear/shirq.c b/arch/arm/plat-spear/shirq.c
index 2172d69..7818903 100644
--- a/arch/arm/plat-spear/shirq.c
+++ b/arch/arm/plat-spear/shirq.c
@@ -20,10 +20,10 @@
struct spear_shirq *shirq;
static DEFINE_SPINLOCK(lock);
-static void shirq_irq_mask(unsigned irq)
+static void shirq_irq_mask(struct irq_data *d)
{
- struct spear_shirq *shirq = get_irq_chip_data(irq);
- u32 val, id = irq - shirq->dev_config[0].virq;
+ struct spear_shirq *shirq = irq_data_get_irq_chip_data(d);
+ u32 val, id = d->irq - shirq->dev_config[0].virq;
unsigned long flags;
if ((shirq->regs.enb_reg == -1) || shirq->dev_config[id].enb_mask == -1)
@@ -39,10 +39,10 @@ static void shirq_irq_mask(unsigned irq)
spin_unlock_irqrestore(&lock, flags);
}
-static void shirq_irq_unmask(unsigned irq)
+static void shirq_irq_unmask(struct irq_data *d)
{
- struct spear_shirq *shirq = get_irq_chip_data(irq);
- u32 val, id = irq - shirq->dev_config[0].virq;
+ struct spear_shirq *shirq = irq_data_get_irq_chip_data(d);
+ u32 val, id = d->irq - shirq->dev_config[0].virq;
unsigned long flags;
if ((shirq->regs.enb_reg == -1) || shirq->dev_config[id].enb_mask == -1)
@@ -60,9 +60,9 @@ static void shirq_irq_unmask(unsigned irq)
static struct irq_chip shirq_chip = {
.name = "spear_shirq",
- .ack = shirq_irq_mask,
- .mask = shirq_irq_mask,
- .unmask = shirq_irq_unmask,
+ .irq_ack = shirq_irq_mask,
+ .irq_mask = shirq_irq_mask,
+ .irq_unmask = shirq_irq_unmask,
};
static void shirq_handler(unsigned irq, struct irq_desc *desc)
@@ -70,7 +70,7 @@ static void shirq_handler(unsigned irq, struct irq_desc *desc)
u32 i, val, mask;
struct spear_shirq *shirq = get_irq_data(irq);
- desc->chip->ack(irq);
+ desc->irq_data.chip->irq_ack(&desc->irq_data);
while ((val = readl(shirq->regs.base + shirq->regs.status_reg) &
shirq->regs.status_reg_mask)) {
for (i = 0; (i < shirq->dev_count) && val; i++) {
@@ -92,7 +92,7 @@ static void shirq_handler(unsigned irq, struct irq_desc *desc)
writel(mask, shirq->regs.base + shirq->regs.clear_reg);
}
}
- desc->chip->unmask(irq);
+ desc->irq_data.chip->irq_unmask(&desc->irq_data);
}
int spear_shirq_register(struct spear_shirq *shirq)
diff --git a/arch/arm/plat-stmp3xxx/irq.c b/arch/arm/plat-stmp3xxx/irq.c
index 20de4e0..aaa1686 100644
--- a/arch/arm/plat-stmp3xxx/irq.c
+++ b/arch/arm/plat-stmp3xxx/irq.c
@@ -34,7 +34,7 @@ void __init stmp3xxx_init_irq(struct irq_chip *chip)
/* Disable all interrupts initially */
for (i = 0; i < NR_REAL_IRQS; i++) {
- chip->mask(i);
+ chip->irq_mask(irq_get_irq_data(i));
set_irq_chip(i, chip);
set_irq_handler(i, handle_level_irq);
set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
diff --git a/arch/arm/plat-stmp3xxx/pinmux.c b/arch/arm/plat-stmp3xxx/pinmux.c
index 6d6b1a4..66d5bac 100644
--- a/arch/arm/plat-stmp3xxx/pinmux.c
+++ b/arch/arm/plat-stmp3xxx/pinmux.c
@@ -351,27 +351,27 @@ void stmp3xxx_release_pin_group(struct pin_group *pin_group, const char *label)
}
EXPORT_SYMBOL(stmp3xxx_release_pin_group);
-static int stmp3xxx_irq_to_gpio(int irq,
+static int stmp3xxx_irq_data_to_gpio(struct irq_data *d,
struct stmp3xxx_pinmux_bank **bank, unsigned *gpio)
{
struct stmp3xxx_pinmux_bank *pm;
for (pm = pinmux_banks; pm < pinmux_banks + NR_BANKS; pm++)
- if (pm->virq <= irq && irq < pm->virq + 32) {
+ if (pm->virq <= d->irq && d->irq < pm->virq + 32) {
*bank = pm;
- *gpio = irq - pm->virq;
+ *gpio = d->irq - pm->virq;
return 0;
}
return -ENOENT;
}
-static int stmp3xxx_set_irqtype(unsigned irq, unsigned type)
+static int stmp3xxx_set_irqtype(struct irq_data *d, unsigned type)
{
struct stmp3xxx_pinmux_bank *pm;
unsigned gpio;
int l, p;
- stmp3xxx_irq_to_gpio(irq, &pm, &gpio);
+ stmp3xxx_irq_data_to_gpio(d, &pm, &gpio);
switch (type) {
case IRQ_TYPE_EDGE_RISING:
l = 0; p = 1; break;
@@ -398,33 +398,33 @@ static int stmp3xxx_set_irqtype(unsigned irq, unsigned type)
return 0;
}
-static void stmp3xxx_pin_ack_irq(unsigned irq)
+static void stmp3xxx_pin_ack_irq(struct irq_data *d)
{
u32 stat;
struct stmp3xxx_pinmux_bank *pm;
unsigned gpio;
- stmp3xxx_irq_to_gpio(irq, &pm, &gpio);
+ stmp3xxx_irq_data_to_gpio(d, &pm, &gpio);
stat = __raw_readl(pm->irqstat) & (1 << gpio);
stmp3xxx_clearl(stat, pm->irqstat);
}
-static void stmp3xxx_pin_mask_irq(unsigned irq)
+static void stmp3xxx_pin_mask_irq(struct irq_data *d)
{
struct stmp3xxx_pinmux_bank *pm;
unsigned gpio;
- stmp3xxx_irq_to_gpio(irq, &pm, &gpio);
+ stmp3xxx_irq_data_to_gpio(d, &pm, &gpio);
stmp3xxx_clearl(1 << gpio, pm->irqen);
stmp3xxx_clearl(1 << gpio, pm->pin2irq);
}
-static void stmp3xxx_pin_unmask_irq(unsigned irq)
+static void stmp3xxx_pin_unmask_irq(struct irq_data *d)
{
struct stmp3xxx_pinmux_bank *pm;
unsigned gpio;
- stmp3xxx_irq_to_gpio(irq, &pm, &gpio);
+ stmp3xxx_irq_data_to_gpio(d, &pm, &gpio);
stmp3xxx_setl(1 << gpio, pm->irqen);
stmp3xxx_setl(1 << gpio, pm->pin2irq);
}
@@ -503,10 +503,10 @@ static void stmp3xxx_gpio_irq(u32 irq, struct irq_desc *desc)
}
static struct irq_chip gpio_irq_chip = {
- .ack = stmp3xxx_pin_ack_irq,
- .mask = stmp3xxx_pin_mask_irq,
- .unmask = stmp3xxx_pin_unmask_irq,
- .set_type = stmp3xxx_set_irqtype,
+ .irq_ack = stmp3xxx_pin_ack_irq,
+ .irq_mask = stmp3xxx_pin_mask_irq,
+ .irq_unmask = stmp3xxx_pin_unmask_irq,
+ .irq_set_type = stmp3xxx_set_irqtype,
};
int __init stmp3xxx_pinmux_init(int virtual_irq_start)
@@ -533,7 +533,7 @@ int __init stmp3xxx_pinmux_init(int virtual_irq_start)
pm->virq = virtual_irq_start + b * 32;
for (virq = pm->virq; virq < pm->virq; virq++) {
- gpio_irq_chip.mask(virq);
+ gpio_irq_chip.irq_mask(irq_get_irq_data(virq));
set_irq_chip(virq, &gpio_irq_chip);
set_irq_handler(virq, handle_level_irq);
set_irq_flags(virq, IRQF_VALID);
diff --git a/arch/avr32/Kconfig b/arch/avr32/Kconfig
index 313b130..cd2062f 100644
--- a/arch/avr32/Kconfig
+++ b/arch/avr32/Kconfig
@@ -1,8 +1,8 @@
config AVR32
def_bool y
- # With EMBEDDED=n, we get lots of stuff automatically selected
+ # With EXPERT=n, we get lots of stuff automatically selected
# that we usually don't need on AVR32.
- select EMBEDDED
+ select EXPERT
select HAVE_CLK
select HAVE_OPROFILE
select HAVE_KPROBES
diff --git a/arch/blackfin/Kconfig b/arch/blackfin/Kconfig
index 0a221d4..c09577d 100644
--- a/arch/blackfin/Kconfig
+++ b/arch/blackfin/Kconfig
@@ -30,6 +30,9 @@ config BLACKFIN
select HAVE_KERNEL_LZO if RAMKERNEL
select HAVE_OPROFILE
select ARCH_WANT_OPTIONAL_GPIOLIB
+ select HAVE_GENERIC_HARDIRQS
+ select GENERIC_IRQ_PROBE
+ select IRQ_PER_CPU if SMP
config GENERIC_CSUM
def_bool y
@@ -44,15 +47,6 @@ config ZONE_DMA
config GENERIC_FIND_NEXT_BIT
def_bool y
-config GENERIC_HARDIRQS
- def_bool y
-
-config GENERIC_IRQ_PROBE
- def_bool y
-
-config GENERIC_HARDIRQS_NO__DO_IRQ
- def_bool y
-
config GENERIC_GPIO
def_bool y
@@ -254,11 +248,6 @@ config HOTPLUG_CPU
depends on SMP && HOTPLUG
default y
-config IRQ_PER_CPU
- bool
- depends on SMP
- default y
-
config HAVE_LEGACY_PER_CPU_AREA
def_bool y
depends on SMP
diff --git a/arch/blackfin/configs/BF518F-EZBRD_defconfig b/arch/blackfin/configs/BF518F-EZBRD_defconfig
index c0b988e..db8d38a 100644
--- a/arch/blackfin/configs/BF518F-EZBRD_defconfig
+++ b/arch/blackfin/configs/BF518F-EZBRD_defconfig
@@ -5,7 +5,7 @@ CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_SYSCTL_SYSCALL is not set
# CONFIG_ELF_CORE is not set
# CONFIG_FUTEX is not set
diff --git a/arch/blackfin/configs/BF526-EZBRD_defconfig b/arch/blackfin/configs/BF526-EZBRD_defconfig
index 864af5b..3e50d78 100644
--- a/arch/blackfin/configs/BF526-EZBRD_defconfig
+++ b/arch/blackfin/configs/BF526-EZBRD_defconfig
@@ -5,7 +5,7 @@ CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_SYSCTL_SYSCALL is not set
# CONFIG_ELF_CORE is not set
# CONFIG_FUTEX is not set
diff --git a/arch/blackfin/configs/BF527-AD7160-EVAL_defconfig b/arch/blackfin/configs/BF527-AD7160-EVAL_defconfig
index 7b6a337..362f59d 100644
--- a/arch/blackfin/configs/BF527-AD7160-EVAL_defconfig
+++ b/arch/blackfin/configs/BF527-AD7160-EVAL_defconfig
@@ -5,7 +5,7 @@ CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_ELF_CORE is not set
# CONFIG_AIO is not set
CONFIG_SLAB=y
diff --git a/arch/blackfin/configs/BF527-EZKIT-V2_defconfig b/arch/blackfin/configs/BF527-EZKIT-V2_defconfig
index 4faa6b4..023ff0d 100644
--- a/arch/blackfin/configs/BF527-EZKIT-V2_defconfig
+++ b/arch/blackfin/configs/BF527-EZKIT-V2_defconfig
@@ -5,7 +5,7 @@ CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_SYSCTL_SYSCALL is not set
# CONFIG_ELF_CORE is not set
# CONFIG_FUTEX is not set
diff --git a/arch/blackfin/configs/BF527-EZKIT_defconfig b/arch/blackfin/configs/BF527-EZKIT_defconfig
index 9d893eb..4e5a121 100644
--- a/arch/blackfin/configs/BF527-EZKIT_defconfig
+++ b/arch/blackfin/configs/BF527-EZKIT_defconfig
@@ -5,7 +5,7 @@ CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_SYSCTL_SYSCALL is not set
# CONFIG_ELF_CORE is not set
# CONFIG_FUTEX is not set
diff --git a/arch/blackfin/configs/BF527-TLL6527M_defconfig b/arch/blackfin/configs/BF527-TLL6527M_defconfig
index 97a2767..cd0636b 100644
--- a/arch/blackfin/configs/BF527-TLL6527M_defconfig
+++ b/arch/blackfin/configs/BF527-TLL6527M_defconfig
@@ -6,7 +6,7 @@ CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_SYSCTL_SYSCALL is not set
# CONFIG_ELF_CORE is not set
# CONFIG_FUTEX is not set
diff --git a/arch/blackfin/configs/BF533-EZKIT_defconfig b/arch/blackfin/configs/BF533-EZKIT_defconfig
index f847743..9f8fc84 100644
--- a/arch/blackfin/configs/BF533-EZKIT_defconfig
+++ b/arch/blackfin/configs/BF533-EZKIT_defconfig
@@ -5,7 +5,7 @@ CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_SYSCTL_SYSCALL is not set
# CONFIG_ELF_CORE is not set
# CONFIG_FUTEX is not set
diff --git a/arch/blackfin/configs/BF533-STAMP_defconfig b/arch/blackfin/configs/BF533-STAMP_defconfig
index 0e7262c..ccc432b 100644
--- a/arch/blackfin/configs/BF533-STAMP_defconfig
+++ b/arch/blackfin/configs/BF533-STAMP_defconfig
@@ -5,7 +5,7 @@ CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_SYSCTL_SYSCALL is not set
# CONFIG_ELF_CORE is not set
# CONFIG_FUTEX is not set
diff --git a/arch/blackfin/configs/BF537-STAMP_defconfig b/arch/blackfin/configs/BF537-STAMP_defconfig
index 4d14a00..5666954 100644
--- a/arch/blackfin/configs/BF537-STAMP_defconfig
+++ b/arch/blackfin/configs/BF537-STAMP_defconfig
@@ -5,7 +5,7 @@ CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_SYSCTL_SYSCALL is not set
# CONFIG_ELF_CORE is not set
# CONFIG_FUTEX is not set
diff --git a/arch/blackfin/configs/BF538-EZKIT_defconfig b/arch/blackfin/configs/BF538-EZKIT_defconfig
index fbee9d7..ac22124 100644
--- a/arch/blackfin/configs/BF538-EZKIT_defconfig
+++ b/arch/blackfin/configs/BF538-EZKIT_defconfig
@@ -5,7 +5,7 @@ CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_SYSCTL_SYSCALL is not set
# CONFIG_ELF_CORE is not set
# CONFIG_FUTEX is not set
diff --git a/arch/blackfin/configs/BF548-EZKIT_defconfig b/arch/blackfin/configs/BF548-EZKIT_defconfig
index 05dd11d..944404b 100644
--- a/arch/blackfin/configs/BF548-EZKIT_defconfig
+++ b/arch/blackfin/configs/BF548-EZKIT_defconfig
@@ -5,7 +5,7 @@ CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_SYSCTL_SYSCALL is not set
# CONFIG_ELF_CORE is not set
# CONFIG_FUTEX is not set
diff --git a/arch/blackfin/configs/BF561-ACVILON_defconfig b/arch/blackfin/configs/BF561-ACVILON_defconfig
index bcb14d1..b7c8451 100644
--- a/arch/blackfin/configs/BF561-ACVILON_defconfig
+++ b/arch/blackfin/configs/BF561-ACVILON_defconfig
@@ -5,7 +5,7 @@ CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_SYSFS_DEPRECATED_V2=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_SYSCTL_SYSCALL is not set
# CONFIG_ELF_CORE is not set
# CONFIG_FUTEX is not set
diff --git a/arch/blackfin/configs/BF561-EZKIT-SMP_defconfig b/arch/blackfin/configs/BF561-EZKIT-SMP_defconfig
index 4cf4510..7e67ba3 100644
--- a/arch/blackfin/configs/BF561-EZKIT-SMP_defconfig
+++ b/arch/blackfin/configs/BF561-EZKIT-SMP_defconfig
@@ -5,7 +5,7 @@ CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_SYSCTL_SYSCALL is not set
# CONFIG_ELF_CORE is not set
# CONFIG_FUTEX is not set
diff --git a/arch/blackfin/configs/BF561-EZKIT_defconfig b/arch/blackfin/configs/BF561-EZKIT_defconfig
index 843aaa5..141e593 100644
--- a/arch/blackfin/configs/BF561-EZKIT_defconfig
+++ b/arch/blackfin/configs/BF561-EZKIT_defconfig
@@ -5,7 +5,7 @@ CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_SYSCTL_SYSCALL is not set
# CONFIG_ELF_CORE is not set
# CONFIG_FUTEX is not set
diff --git a/arch/blackfin/configs/BlackStamp_defconfig b/arch/blackfin/configs/BlackStamp_defconfig
index dae7adf..97ebe09 100644
--- a/arch/blackfin/configs/BlackStamp_defconfig
+++ b/arch/blackfin/configs/BlackStamp_defconfig
@@ -6,7 +6,7 @@ CONFIG_LOG_BUF_SHIFT=14
CONFIG_SYSFS_DEPRECATED_V2=y
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_SYSCTL_SYSCALL is not set
# CONFIG_ELF_CORE is not set
# CONFIG_FUTEX is not set
diff --git a/arch/blackfin/configs/CM-BF527_defconfig b/arch/blackfin/configs/CM-BF527_defconfig
index f341424..c245754 100644
--- a/arch/blackfin/configs/CM-BF527_defconfig
+++ b/arch/blackfin/configs/CM-BF527_defconfig
@@ -8,7 +8,7 @@ CONFIG_BLK_DEV_INITRD=y
# CONFIG_RD_GZIP is not set
CONFIG_RD_LZMA=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_SYSCTL_SYSCALL is not set
# CONFIG_ELF_CORE is not set
# CONFIG_FUTEX is not set
diff --git a/arch/blackfin/configs/CM-BF533_defconfig b/arch/blackfin/configs/CM-BF533_defconfig
index 8c7e08f..baf1c15 100644
--- a/arch/blackfin/configs/CM-BF533_defconfig
+++ b/arch/blackfin/configs/CM-BF533_defconfig
@@ -7,7 +7,7 @@ CONFIG_LOG_BUF_SHIFT=14
CONFIG_BLK_DEV_INITRD=y
# CONFIG_RD_GZIP is not set
CONFIG_RD_LZMA=y
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_UID16 is not set
# CONFIG_SYSCTL_SYSCALL is not set
# CONFIG_ELF_CORE is not set
diff --git a/arch/blackfin/configs/CM-BF537E_defconfig b/arch/blackfin/configs/CM-BF537E_defconfig
index bd3cb76..707cbf8 100644
--- a/arch/blackfin/configs/CM-BF537E_defconfig
+++ b/arch/blackfin/configs/CM-BF537E_defconfig
@@ -8,7 +8,7 @@ CONFIG_BLK_DEV_INITRD=y
# CONFIG_RD_GZIP is not set
CONFIG_RD_LZMA=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_UID16 is not set
# CONFIG_SYSCTL_SYSCALL is not set
# CONFIG_ELF_CORE is not set
diff --git a/arch/blackfin/configs/CM-BF537U_defconfig b/arch/blackfin/configs/CM-BF537U_defconfig
index 82224f3..4596935 100644
--- a/arch/blackfin/configs/CM-BF537U_defconfig
+++ b/arch/blackfin/configs/CM-BF537U_defconfig
@@ -8,7 +8,7 @@ CONFIG_BLK_DEV_INITRD=y
# CONFIG_RD_GZIP is not set
CONFIG_RD_LZMA=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_UID16 is not set
# CONFIG_SYSCTL_SYSCALL is not set
# CONFIG_ELF_CORE is not set
diff --git a/arch/blackfin/configs/CM-BF548_defconfig b/arch/blackfin/configs/CM-BF548_defconfig
index 433598c..df26758 100644
--- a/arch/blackfin/configs/CM-BF548_defconfig
+++ b/arch/blackfin/configs/CM-BF548_defconfig
@@ -8,7 +8,7 @@ CONFIG_BLK_DEV_INITRD=y
# CONFIG_RD_GZIP is not set
CONFIG_RD_LZMA=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_UID16 is not set
# CONFIG_SYSCTL_SYSCALL is not set
# CONFIG_ELF_CORE is not set
diff --git a/arch/blackfin/configs/CM-BF561_defconfig b/arch/blackfin/configs/CM-BF561_defconfig
index ded7d84..6c7b215 100644
--- a/arch/blackfin/configs/CM-BF561_defconfig
+++ b/arch/blackfin/configs/CM-BF561_defconfig
@@ -8,7 +8,7 @@ CONFIG_BLK_DEV_INITRD=y
# CONFIG_RD_GZIP is not set
CONFIG_RD_LZMA=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_UID16 is not set
# CONFIG_SYSCTL_SYSCALL is not set
# CONFIG_ELF_CORE is not set
diff --git a/arch/blackfin/configs/DNP5370_defconfig b/arch/blackfin/configs/DNP5370_defconfig
index 0ebc7d9..f503136 100644
--- a/arch/blackfin/configs/DNP5370_defconfig
+++ b/arch/blackfin/configs/DNP5370_defconfig
@@ -5,7 +5,7 @@ CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_BLK_DEV_INITRD=y
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
CONFIG_SLOB=y
# CONFIG_BLK_DEV_BSG is not set
# CONFIG_IOSCHED_CFQ is not set
diff --git a/arch/blackfin/configs/H8606_defconfig b/arch/blackfin/configs/H8606_defconfig
index 700fb70..7450127 100644
--- a/arch/blackfin/configs/H8606_defconfig
+++ b/arch/blackfin/configs/H8606_defconfig
@@ -2,7 +2,7 @@ CONFIG_EXPERIMENTAL=y
CONFIG_SYSVIPC=y
CONFIG_LOG_BUF_SHIFT=14
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_SYSCTL_SYSCALL is not set
# CONFIG_ELF_CORE is not set
# CONFIG_FUTEX is not set
diff --git a/arch/blackfin/configs/IP0X_defconfig b/arch/blackfin/configs/IP0X_defconfig
index b40156d..5e797cf 100644
--- a/arch/blackfin/configs/IP0X_defconfig
+++ b/arch/blackfin/configs/IP0X_defconfig
@@ -3,7 +3,7 @@ CONFIG_SYSVIPC=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_SYSCTL_SYSCALL is not set
# CONFIG_HOTPLUG is not set
# CONFIG_ELF_CORE is not set
diff --git a/arch/blackfin/configs/PNAV-10_defconfig b/arch/blackfin/configs/PNAV-10_defconfig
index be866d9..a566a2f 100644
--- a/arch/blackfin/configs/PNAV-10_defconfig
+++ b/arch/blackfin/configs/PNAV-10_defconfig
@@ -2,7 +2,7 @@ CONFIG_EXPERIMENTAL=y
CONFIG_SYSVIPC=y
CONFIG_LOG_BUF_SHIFT=14
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_SYSCTL_SYSCALL is not set
# CONFIG_ELF_CORE is not set
# CONFIG_FUTEX is not set
diff --git a/arch/blackfin/configs/SRV1_defconfig b/arch/blackfin/configs/SRV1_defconfig
index b64bdf7..8538095 100644
--- a/arch/blackfin/configs/SRV1_defconfig
+++ b/arch/blackfin/configs/SRV1_defconfig
@@ -3,7 +3,7 @@ CONFIG_SYSVIPC=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_SYSCTL_SYSCALL is not set
CONFIG_KALLSYMS_ALL=y
# CONFIG_ELF_CORE is not set
diff --git a/arch/blackfin/configs/TCM-BF518_defconfig b/arch/blackfin/configs/TCM-BF518_defconfig
index 1bccd9a..d496ae9 100644
--- a/arch/blackfin/configs/TCM-BF518_defconfig
+++ b/arch/blackfin/configs/TCM-BF518_defconfig
@@ -7,7 +7,7 @@ CONFIG_LOG_BUF_SHIFT=14
CONFIG_BLK_DEV_INITRD=y
# CONFIG_RD_GZIP is not set
CONFIG_RD_LZMA=y
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_SYSCTL_SYSCALL is not set
# CONFIG_ELF_CORE is not set
# CONFIG_FUTEX is not set
diff --git a/arch/blackfin/configs/TCM-BF537_defconfig b/arch/blackfin/configs/TCM-BF537_defconfig
index 00ce899..65f6421 100644
--- a/arch/blackfin/configs/TCM-BF537_defconfig
+++ b/arch/blackfin/configs/TCM-BF537_defconfig
@@ -8,7 +8,7 @@ CONFIG_BLK_DEV_INITRD=y
# CONFIG_RD_GZIP is not set
CONFIG_RD_LZMA=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_UID16 is not set
# CONFIG_SYSCTL_SYSCALL is not set
# CONFIG_ELF_CORE is not set
diff --git a/arch/cris/Kconfig b/arch/cris/Kconfig
index 613e628..0a7a4c1 100644
--- a/arch/cris/Kconfig
+++ b/arch/cris/Kconfig
@@ -54,6 +54,8 @@ config CRIS
bool
default y
select HAVE_IDE
+ select HAVE_GENERIC_HARDIRQS
+ select GENERIC_HARDIRQS_NO_DEPRECATED
config HZ
int
@@ -67,10 +69,6 @@ menu "General setup"
source "fs/Kconfig.binfmt"
-config GENERIC_HARDIRQS
- bool
- default y
-
config ETRAX_CMDLINE
string "Kernel command line"
default "root=/dev/mtdblock3"
diff --git a/arch/cris/arch-v10/kernel/irq.c b/arch/cris/arch-v10/kernel/irq.c
index a0c0df8..7328a7c 100644
--- a/arch/cris/arch-v10/kernel/irq.c
+++ b/arch/cris/arch-v10/kernel/irq.c
@@ -104,43 +104,21 @@ static void (*interrupt[NR_IRQS])(void) = {
IRQ31_interrupt
};
-static void enable_crisv10_irq(unsigned int irq);
-
-static unsigned int startup_crisv10_irq(unsigned int irq)
-{
- enable_crisv10_irq(irq);
- return 0;
-}
-
-#define shutdown_crisv10_irq disable_crisv10_irq
-
-static void enable_crisv10_irq(unsigned int irq)
-{
- crisv10_unmask_irq(irq);
-}
-
-static void disable_crisv10_irq(unsigned int irq)
-{
- crisv10_mask_irq(irq);
-}
-
-static void ack_crisv10_irq(unsigned int irq)
+static void enable_crisv10_irq(struct irq_data *data)
{
+ crisv10_unmask_irq(data->irq);
}
-static void end_crisv10_irq(unsigned int irq)
+static void disable_crisv10_irq(struct irq_data *data)
{
+ crisv10_mask_irq(data->irq);
}
static struct irq_chip crisv10_irq_type = {
- .name = "CRISv10",
- .startup = startup_crisv10_irq,
- .shutdown = shutdown_crisv10_irq,
- .enable = enable_crisv10_irq,
- .disable = disable_crisv10_irq,
- .ack = ack_crisv10_irq,
- .end = end_crisv10_irq,
- .set_affinity = NULL
+ .name = "CRISv10",
+ .irq_shutdown = disable_crisv10_irq,
+ .irq_enable = enable_crisv10_irq,
+ .irq_disable = disable_crisv10_irq,
};
void weird_irq(void);
@@ -221,7 +199,8 @@ init_IRQ(void)
/* Initialize IRQ handler descriptors. */
for(i = 2; i < NR_IRQS; i++) {
- irq_desc[i].chip = &crisv10_irq_type;
+ set_irq_desc_and_handler(i, &crisv10_irq_type,
+ handle_simple_irq);
set_int_vector(i, interrupt[i]);
}
diff --git a/arch/cris/arch-v32/kernel/irq.c b/arch/cris/arch-v32/kernel/irq.c
index 2ed48ae3d..0ad9db5 100644
--- a/arch/cris/arch-v32/kernel/irq.c
+++ b/arch/cris/arch-v32/kernel/irq.c
@@ -291,54 +291,33 @@ void crisv32_unmask_irq(int irq)
}
-static unsigned int startup_crisv32_irq(unsigned int irq)
+static void enable_crisv32_irq(struct irq_data *data)
{
- crisv32_unmask_irq(irq);
- return 0;
-}
-
-static void shutdown_crisv32_irq(unsigned int irq)
-{
- crisv32_mask_irq(irq);
+ crisv32_unmask_irq(data->irq);
}
-static void enable_crisv32_irq(unsigned int irq)
+static void disable_crisv32_irq(struct irq_data *data)
{
- crisv32_unmask_irq(irq);
+ crisv32_mask_irq(data->irq);
}
-static void disable_crisv32_irq(unsigned int irq)
-{
- crisv32_mask_irq(irq);
-}
-
-static void ack_crisv32_irq(unsigned int irq)
-{
-}
-
-static void end_crisv32_irq(unsigned int irq)
-{
-}
-
-int set_affinity_crisv32_irq(unsigned int irq, const struct cpumask *dest)
+static int set_affinity_crisv32_irq(struct irq_data *data,
+ const struct cpumask *dest, bool force)
{
unsigned long flags;
+
spin_lock_irqsave(&irq_lock, flags);
- irq_allocations[irq - FIRST_IRQ].mask = *dest;
+ irq_allocations[data->irq - FIRST_IRQ].mask = *dest;
spin_unlock_irqrestore(&irq_lock, flags);
-
return 0;
}
static struct irq_chip crisv32_irq_type = {
- .name = "CRISv32",
- .startup = startup_crisv32_irq,
- .shutdown = shutdown_crisv32_irq,
- .enable = enable_crisv32_irq,
- .disable = disable_crisv32_irq,
- .ack = ack_crisv32_irq,
- .end = end_crisv32_irq,
- .set_affinity = set_affinity_crisv32_irq
+ .name = "CRISv32",
+ .irq_shutdown = disable_crisv32_irq,
+ .irq_enable = enable_crisv32_irq,
+ .irq_disable = disable_crisv32_irq,
+ .irq_set_affinity = set_affinity_crisv32_irq,
};
void
@@ -472,7 +451,8 @@ init_IRQ(void)
/* Point all IRQ's to bad handlers. */
for (i = FIRST_IRQ, j = 0; j < NR_IRQS; i++, j++) {
- irq_desc[j].chip = &crisv32_irq_type;
+ set_irq_chip_and_handler(j, &crisv32_irq_type,
+ handle_simple_irq);
set_exception_vector(i, interrupt[j]);
}
diff --git a/arch/cris/configs/artpec_3_defconfig b/arch/cris/configs/artpec_3_defconfig
index 590f72c..71854d4 100644
--- a/arch/cris/configs/artpec_3_defconfig
+++ b/arch/cris/configs/artpec_3_defconfig
@@ -2,7 +2,7 @@ CONFIG_EXPERIMENTAL=y
# CONFIG_SWAP is not set
CONFIG_LOG_BUF_SHIFT=14
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_KALLSYMS is not set
# CONFIG_HOTPLUG is not set
# CONFIG_BLK_DEV_BSG is not set
diff --git a/arch/cris/configs/etrax-100lx_v2_defconfig b/arch/cris/configs/etrax-100lx_v2_defconfig
index 1b2853e..a85aabf 100644
--- a/arch/cris/configs/etrax-100lx_v2_defconfig
+++ b/arch/cris/configs/etrax-100lx_v2_defconfig
@@ -2,7 +2,7 @@ CONFIG_EXPERIMENTAL=y
# CONFIG_SWAP is not set
CONFIG_LOG_BUF_SHIFT=14
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_KALLSYMS is not set
# CONFIG_HOTPLUG is not set
# CONFIG_BLK_DEV_BSG is not set
diff --git a/arch/cris/configs/etraxfs_defconfig b/arch/cris/configs/etraxfs_defconfig
index f73d38c..87c7227 100644
--- a/arch/cris/configs/etraxfs_defconfig
+++ b/arch/cris/configs/etraxfs_defconfig
@@ -2,7 +2,7 @@ CONFIG_EXPERIMENTAL=y
# CONFIG_SWAP is not set
CONFIG_LOG_BUF_SHIFT=14
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_KALLSYMS is not set
# CONFIG_HOTPLUG is not set
# CONFIG_BLK_DEV_BSG is not set
diff --git a/arch/cris/kernel/irq.c b/arch/cris/kernel/irq.c
index 469f7f9..c346952 100644
--- a/arch/cris/kernel/irq.c
+++ b/arch/cris/kernel/irq.c
@@ -62,7 +62,7 @@ int show_interrupts(struct seq_file *p, void *v)
for_each_online_cpu(j)
seq_printf(p, "%10u ", kstat_irqs_cpu(i, j));
#endif
- seq_printf(p, " %14s", irq_desc[i].chip->name);
+ seq_printf(p, " %14s", irq_desc[i].irq_data.chip->name);
seq_printf(p, " %s", action->name);
for (action=action->next; action; action = action->next)
@@ -93,8 +93,8 @@ asmlinkage void do_IRQ(int irq, struct pt_regs * regs)
printk("do_IRQ: stack overflow: %lX\n", sp);
show_stack(NULL, (unsigned long *)sp);
}
- __do_IRQ(irq);
- irq_exit();
+ generic_handle_irq(irq);
+ irq_exit();
set_irq_regs(old_regs);
}
diff --git a/arch/frv/Kconfig b/arch/frv/Kconfig
index f6bcb03..747499a 100644
--- a/arch/frv/Kconfig
+++ b/arch/frv/Kconfig
@@ -5,6 +5,7 @@ config FRV
select HAVE_ARCH_TRACEHOOK
select HAVE_IRQ_WORK
select HAVE_PERF_EVENTS
+ select HAVE_GENERIC_HARDIRQS
config ZONE_DMA
bool
@@ -29,14 +30,6 @@ config GENERIC_CALIBRATE_DELAY
bool
default n
-config GENERIC_HARDIRQS
- bool
- default y
-
-config GENERIC_HARDIRQS_NO__DO_IRQ
- bool
- default y
-
config TIME_LOW_RES
bool
default y
diff --git a/arch/frv/defconfig b/arch/frv/defconfig
index b8ebe9e..b1b7926 100644
--- a/arch/frv/defconfig
+++ b/arch/frv/defconfig
@@ -3,7 +3,7 @@ CONFIG_SYSVIPC=y
CONFIG_POSIX_MQUEUE=y
CONFIG_LOG_BUF_SHIFT=14
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_HOTPLUG is not set
CONFIG_MMU=y
CONFIG_FRV_OUTOFLINE_ATOMIC_OPS=y
diff --git a/arch/h8300/Kconfig b/arch/h8300/Kconfig
index 65f897d8..6df692d 100644
--- a/arch/h8300/Kconfig
+++ b/arch/h8300/Kconfig
@@ -2,6 +2,8 @@ config H8300
bool
default y
select HAVE_IDE
+ select HAVE_GENERIC_HARDIRQS
+ select GENERIC_HARDIRQS_NO_DEPRECATED
config SYMBOL_PREFIX
string
@@ -47,10 +49,6 @@ config GENERIC_HWEIGHT
bool
default y
-config GENERIC_HARDIRQS
- bool
- default y
-
config GENERIC_CALIBRATE_DELAY
bool
default y
diff --git a/arch/h8300/defconfig b/arch/h8300/defconfig
index 342f777..042425a 100644
--- a/arch/h8300/defconfig
+++ b/arch/h8300/defconfig
@@ -1,7 +1,7 @@
CONFIG_EXPERIMENTAL=y
# CONFIG_LOCALVERSION_AUTO is not set
CONFIG_LOG_BUF_SHIFT=14
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_UID16 is not set
# CONFIG_SYSCTL_SYSCALL is not set
# CONFIG_KALLSYMS is not set
diff --git a/arch/h8300/kernel/irq.c b/arch/h8300/kernel/irq.c
index c25dc2c..7643d39 100644
--- a/arch/h8300/kernel/irq.c
+++ b/arch/h8300/kernel/irq.c
@@ -38,34 +38,30 @@ static inline int is_ext_irq(unsigned int irq)
return (irq >= EXT_IRQ0 && irq <= (EXT_IRQ0 + EXT_IRQS));
}
-static void h8300_enable_irq(unsigned int irq)
+static void h8300_enable_irq(struct irq_data *data)
{
- if (is_ext_irq(irq))
- IER_REGS |= 1 << (irq - EXT_IRQ0);
+ if (is_ext_irq(data->irq))
+ IER_REGS |= 1 << (data->irq - EXT_IRQ0);
}
-static void h8300_disable_irq(unsigned int irq)
+static void h8300_disable_irq(struct irq_data *data)
{
- if (is_ext_irq(irq))
- IER_REGS &= ~(1 << (irq - EXT_IRQ0));
+ if (is_ext_irq(data->irq))
+ IER_REGS &= ~(1 << (data->irq - EXT_IRQ0));
}
-static void h8300_end_irq(unsigned int irq)
+static unsigned int h8300_startup_irq(struct irq_data *data)
{
-}
-
-static unsigned int h8300_startup_irq(unsigned int irq)
-{
- if (is_ext_irq(irq))
- return h8300_enable_irq_pin(irq);
+ if (is_ext_irq(data->irq))
+ return h8300_enable_irq_pin(data->irq);
else
return 0;
}
-static void h8300_shutdown_irq(unsigned int irq)
+static void h8300_shutdown_irq(struct irq_data *data)
{
- if (is_ext_irq(irq))
- h8300_disable_irq_pin(irq);
+ if (is_ext_irq(data->irq))
+ h8300_disable_irq_pin(data->irq);
}
/*
@@ -73,12 +69,10 @@ static void h8300_shutdown_irq(unsigned int irq)
*/
struct irq_chip h8300irq_chip = {
.name = "H8300-INTC",
- .startup = h8300_startup_irq,
- .shutdown = h8300_shutdown_irq,
- .enable = h8300_enable_irq,
- .disable = h8300_disable_irq,
- .ack = NULL,
- .end = h8300_end_irq,
+ .irq_startup = h8300_startup_irq,
+ .irq_shutdown = h8300_shutdown_irq,
+ .irq_enable = h8300_enable_irq,
+ .irq_disable = h8300_disable_irq,
};
#if defined(CONFIG_RAMKERNEL)
@@ -160,18 +154,14 @@ void __init init_IRQ(void)
setup_vector();
- for (c = 0; c < NR_IRQS; c++) {
- irq_desc[c].status = IRQ_DISABLED;
- irq_desc[c].action = NULL;
- irq_desc[c].depth = 1;
- irq_desc[c].chip = &h8300irq_chip;
- }
+ for (c = 0; c < NR_IRQS; c++)
+ set_irq_chip_and_handler(c, &h8300irq_chip, handle_simple_irq);
}
asmlinkage void do_IRQ(int irq)
{
irq_enter();
- __do_IRQ(irq);
+ generic_handle_irq(irq);
irq_exit();
}
@@ -192,7 +182,7 @@ int show_interrupts(struct seq_file *p, void *v)
goto unlock;
seq_printf(p, "%3d: ",i);
seq_printf(p, "%10u ", kstat_irqs(i));
- seq_printf(p, " %14s", irq_desc[i].chip->name);
+ seq_printf(p, " %14s", irq_desc[i].irq_data.chip->name);
seq_printf(p, "-%-8s", irq_desc[i].name);
seq_printf(p, " %s", action->name);
diff --git a/arch/ia64/Kconfig b/arch/ia64/Kconfig
index e0f5b6d..fcf3b43 100644
--- a/arch/ia64/Kconfig
+++ b/arch/ia64/Kconfig
@@ -22,6 +22,10 @@ config IA64
select HAVE_KVM
select HAVE_ARCH_TRACEHOOK
select HAVE_DMA_API_DEBUG
+ select HAVE_GENERIC_HARDIRQS
+ select GENERIC_IRQ_PROBE
+ select GENERIC_PENDING_IRQ if SMP
+ select IRQ_PER_CPU
default y
help
The Itanium Processor Family is Intel's 64-bit successor to
@@ -678,28 +682,6 @@ source "arch/ia64/kvm/Kconfig"
source "lib/Kconfig"
-#
-# Use the generic interrupt handling code in kernel/irq/:
-#
-config GENERIC_HARDIRQS
- def_bool y
-
-config GENERIC_HARDIRQS_NO__DO_IRQ
- def_bool y
-
-config GENERIC_IRQ_PROBE
- bool
- default y
-
-config GENERIC_PENDING_IRQ
- bool
- depends on GENERIC_HARDIRQS && SMP
- default y
-
-config IRQ_PER_CPU
- bool
- default y
-
config IOMMU_HELPER
def_bool (IA64_HP_ZX1 || IA64_HP_ZX1_SWIOTLB || IA64_GENERIC || SWIOTLB)
diff --git a/arch/ia64/include/asm/io.h b/arch/ia64/include/asm/io.h
index cc8335e..e5a6c35 100644
--- a/arch/ia64/include/asm/io.h
+++ b/arch/ia64/include/asm/io.h
@@ -426,6 +426,11 @@ extern void __iomem * ioremap_nocache (unsigned long offset, unsigned long size)
extern void iounmap (volatile void __iomem *addr);
extern void __iomem * early_ioremap (unsigned long phys_addr, unsigned long size);
extern void early_iounmap (volatile void __iomem *addr, unsigned long size);
+static inline void __iomem * ioremap_cache (unsigned long phys_addr, unsigned long size)
+{
+ return ioremap(phys_addr, size);
+}
+
/*
* String version of IO memory access ops:
diff --git a/arch/ia64/include/asm/page.h b/arch/ia64/include/asm/page.h
index 41b6d31..961a16f 100644
--- a/arch/ia64/include/asm/page.h
+++ b/arch/ia64/include/asm/page.h
@@ -189,6 +189,7 @@ get_order (unsigned long size)
# define pgprot_val(x) ((x).pgprot)
# define __pte(x) ((pte_t) { (x) } )
+# define __pmd(x) ((pmd_t) { (x) } )
# define __pgprot(x) ((pgprot_t) { (x) } )
#else /* !STRICT_MM_TYPECHECKS */
diff --git a/arch/ia64/include/asm/processor.h b/arch/ia64/include/asm/processor.h
index 348e44d..03afe79 100644
--- a/arch/ia64/include/asm/processor.h
+++ b/arch/ia64/include/asm/processor.h
@@ -717,8 +717,9 @@ prefetchw (const void *x)
#define spin_lock_prefetch(x) prefetchw(x)
extern unsigned long boot_option_idle_override;
-extern unsigned long idle_halt;
-extern unsigned long idle_nomwait;
+
+enum idle_boot_override {IDLE_NO_OVERRIDE=0, IDLE_HALT, IDLE_FORCE_MWAIT,
+ IDLE_NOMWAIT, IDLE_POLL};
#endif /* !__ASSEMBLY__ */
diff --git a/arch/ia64/kernel/process.c b/arch/ia64/kernel/process.c
index 16f1c7b..6d33c5c 100644
--- a/arch/ia64/kernel/process.c
+++ b/arch/ia64/kernel/process.c
@@ -53,12 +53,8 @@
void (*ia64_mark_idle)(int);
-unsigned long boot_option_idle_override = 0;
+unsigned long boot_option_idle_override = IDLE_NO_OVERRIDE;
EXPORT_SYMBOL(boot_option_idle_override);
-unsigned long idle_halt;
-EXPORT_SYMBOL(idle_halt);
-unsigned long idle_nomwait;
-EXPORT_SYMBOL(idle_nomwait);
void (*pm_idle) (void);
EXPORT_SYMBOL(pm_idle);
void (*pm_power_off) (void);
diff --git a/arch/m32r/Kconfig b/arch/m32r/Kconfig
index 5c291d6..ef4c1e4 100644
--- a/arch/m32r/Kconfig
+++ b/arch/m32r/Kconfig
@@ -7,6 +7,9 @@ config M32R
select HAVE_KERNEL_GZIP
select HAVE_KERNEL_BZIP2
select HAVE_KERNEL_LZMA
+ select HAVE_GENERIC_HARDIRQS
+ select GENERIC_HARDIRQS_NO_DEPRECATED
+ select GENERIC_IRQ_PROBE
config SBUS
bool
@@ -19,14 +22,6 @@ config ZONE_DMA
bool
default y
-config GENERIC_HARDIRQS
- bool
- default y
-
-config GENERIC_IRQ_PROBE
- bool
- default y
-
config NO_IOPORT
def_bool y
diff --git a/arch/m32r/configs/m32700ut.smp_defconfig b/arch/m32r/configs/m32700ut.smp_defconfig
index 816c3ec..a3d727e 100644
--- a/arch/m32r/configs/m32700ut.smp_defconfig
+++ b/arch/m32r/configs/m32700ut.smp_defconfig
@@ -5,7 +5,7 @@ CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=15
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_KALLSYMS is not set
# CONFIG_FUTEX is not set
# CONFIG_EPOLL is not set
diff --git a/arch/m32r/configs/m32700ut.up_defconfig b/arch/m32r/configs/m32700ut.up_defconfig
index 8478568..b833416 100644
--- a/arch/m32r/configs/m32700ut.up_defconfig
+++ b/arch/m32r/configs/m32700ut.up_defconfig
@@ -5,7 +5,7 @@ CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=14
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_KALLSYMS is not set
# CONFIG_FUTEX is not set
# CONFIG_EPOLL is not set
diff --git a/arch/m32r/configs/mappi.nommu_defconfig b/arch/m32r/configs/mappi.nommu_defconfig
index 354a964..7c90ce2 100644
--- a/arch/m32r/configs/mappi.nommu_defconfig
+++ b/arch/m32r/configs/mappi.nommu_defconfig
@@ -3,7 +3,7 @@ CONFIG_BSD_PROCESS_ACCT=y
CONFIG_IKCONFIG=y
CONFIG_LOG_BUF_SHIFT=14
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_KALLSYMS is not set
# CONFIG_FUTEX is not set
# CONFIG_EPOLL is not set
diff --git a/arch/m32r/configs/mappi.smp_defconfig b/arch/m32r/configs/mappi.smp_defconfig
index 9022307..367d07c 100644
--- a/arch/m32r/configs/mappi.smp_defconfig
+++ b/arch/m32r/configs/mappi.smp_defconfig
@@ -5,7 +5,7 @@ CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=15
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_KALLSYMS is not set
# CONFIG_FUTEX is not set
# CONFIG_EPOLL is not set
diff --git a/arch/m32r/configs/mappi.up_defconfig b/arch/m32r/configs/mappi.up_defconfig
index 3726068..cb11384 100644
--- a/arch/m32r/configs/mappi.up_defconfig
+++ b/arch/m32r/configs/mappi.up_defconfig
@@ -5,7 +5,7 @@ CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_KALLSYMS is not set
# CONFIG_FUTEX is not set
# CONFIG_EPOLL is not set
diff --git a/arch/m32r/configs/mappi2.opsp_defconfig b/arch/m32r/configs/mappi2.opsp_defconfig
index 6136fad..3bff779 100644
--- a/arch/m32r/configs/mappi2.opsp_defconfig
+++ b/arch/m32r/configs/mappi2.opsp_defconfig
@@ -4,7 +4,7 @@ CONFIG_BSD_PROCESS_ACCT=y
CONFIG_IKCONFIG=y
CONFIG_LOG_BUF_SHIFT=14
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_KALLSYMS is not set
# CONFIG_FUTEX is not set
# CONFIG_EPOLL is not set
diff --git a/arch/m32r/configs/mappi2.vdec2_defconfig b/arch/m32r/configs/mappi2.vdec2_defconfig
index dce1fc7..75246c9 100644
--- a/arch/m32r/configs/mappi2.vdec2_defconfig
+++ b/arch/m32r/configs/mappi2.vdec2_defconfig
@@ -4,7 +4,7 @@ CONFIG_BSD_PROCESS_ACCT=y
CONFIG_IKCONFIG=y
CONFIG_LOG_BUF_SHIFT=14
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_KALLSYMS is not set
# CONFIG_FUTEX is not set
# CONFIG_EPOLL is not set
diff --git a/arch/m32r/configs/mappi3.smp_defconfig b/arch/m32r/configs/mappi3.smp_defconfig
index b204e2e..27cefd4 100644
--- a/arch/m32r/configs/mappi3.smp_defconfig
+++ b/arch/m32r/configs/mappi3.smp_defconfig
@@ -5,7 +5,7 @@ CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=15
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_KALLSYMS is not set
# CONFIG_FUTEX is not set
# CONFIG_EPOLL is not set
diff --git a/arch/m32r/configs/oaks32r_defconfig b/arch/m32r/configs/oaks32r_defconfig
index 5aa4ea9..5087a51 100644
--- a/arch/m32r/configs/oaks32r_defconfig
+++ b/arch/m32r/configs/oaks32r_defconfig
@@ -2,7 +2,7 @@ CONFIG_EXPERIMENTAL=y
CONFIG_BSD_PROCESS_ACCT=y
CONFIG_LOG_BUF_SHIFT=14
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_KALLSYMS is not set
# CONFIG_FUTEX is not set
# CONFIG_EPOLL is not set
diff --git a/arch/m32r/configs/opsput_defconfig b/arch/m32r/configs/opsput_defconfig
index 8494c6a..50c6f52 100644
--- a/arch/m32r/configs/opsput_defconfig
+++ b/arch/m32r/configs/opsput_defconfig
@@ -4,7 +4,7 @@ CONFIG_BSD_PROCESS_ACCT=y
CONFIG_IKCONFIG=y
CONFIG_LOG_BUF_SHIFT=14
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_KALLSYMS is not set
# CONFIG_FUTEX is not set
# CONFIG_EPOLL is not set
diff --git a/arch/m32r/configs/usrv_defconfig b/arch/m32r/configs/usrv_defconfig
index 1df293b..a3cfaae 100644
--- a/arch/m32r/configs/usrv_defconfig
+++ b/arch/m32r/configs/usrv_defconfig
@@ -5,7 +5,7 @@ CONFIG_BSD_PROCESS_ACCT=y
CONFIG_LOG_BUF_SHIFT=15
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
CONFIG_KALLSYMS_EXTRA_PASS=y
CONFIG_SLAB=y
CONFIG_MODULES=y
diff --git a/arch/m32r/kernel/irq.c b/arch/m32r/kernel/irq.c
index 7db26f1..f745c12 100644
--- a/arch/m32r/kernel/irq.c
+++ b/arch/m32r/kernel/irq.c
@@ -40,8 +40,10 @@ int show_interrupts(struct seq_file *p, void *v)
}
if (i < NR_IRQS) {
- raw_spin_lock_irqsave(&irq_desc[i].lock, flags);
- action = irq_desc[i].action;
+ struct irq_desc *desc = irq_to_desc(i);
+
+ raw_spin_lock_irqsave(&desc->lock, flags);
+ action = desc->action;
if (!action)
goto skip;
seq_printf(p, "%3d: ",i);
@@ -51,7 +53,7 @@ int show_interrupts(struct seq_file *p, void *v)
for_each_online_cpu(j)
seq_printf(p, "%10u ", kstat_irqs_cpu(i, j));
#endif
- seq_printf(p, " %14s", irq_desc[i].chip->name);
+ seq_printf(p, " %14s", desc->irq_data.chip->name);
seq_printf(p, " %s", action->name);
for (action=action->next; action; action = action->next)
@@ -59,7 +61,7 @@ int show_interrupts(struct seq_file *p, void *v)
seq_putc(p, '\n');
skip:
- raw_spin_unlock_irqrestore(&irq_desc[i].lock, flags);
+ raw_spin_unlock_irqrestore(&desc->lock, flags);
}
return 0;
}
diff --git a/arch/m32r/platforms/m32104ut/setup.c b/arch/m32r/platforms/m32104ut/setup.c
index 402a59d..4a693d0 100644
--- a/arch/m32r/platforms/m32104ut/setup.c
+++ b/arch/m32r/platforms/m32104ut/setup.c
@@ -39,39 +39,30 @@ static void enable_m32104ut_irq(unsigned int irq)
outl(data, port);
}
-static void mask_and_ack_m32104ut(unsigned int irq)
+static void mask_m32104ut_irq(struct irq_data *data)
{
- disable_m32104ut_irq(irq);
+ disable_m32104ut_irq(data->irq);
}
-static void end_m32104ut_irq(unsigned int irq)
+static void unmask_m32104ut_irq(struct irq_data *data)
{
- enable_m32104ut_irq(irq);
+ enable_m32104ut_irq(data->irq);
}
-static unsigned int startup_m32104ut_irq(unsigned int irq)
+static void shutdown_m32104ut_irq(struct irq_data *data)
{
- enable_m32104ut_irq(irq);
- return (0);
-}
-
-static void shutdown_m32104ut_irq(unsigned int irq)
-{
- unsigned long port;
+ unsigned int irq = data->irq;
+ unsigned long port = irq2port(irq);
- port = irq2port(irq);
outl(M32R_ICUCR_ILEVEL7, port);
}
static struct irq_chip m32104ut_irq_type =
{
- .name = "M32104UT-IRQ",
- .startup = startup_m32104ut_irq,
- .shutdown = shutdown_m32104ut_irq,
- .enable = enable_m32104ut_irq,
- .disable = disable_m32104ut_irq,
- .ack = mask_and_ack_m32104ut,
- .end = end_m32104ut_irq
+ .name = "M32104UT-IRQ",
+ .irq_shutdown = shutdown_m32104ut_irq,
+ .irq_unmask = unmask_m32104ut_irq,
+ .irq_mask = mask_m32104ut_irq,
};
void __init init_IRQ(void)
@@ -85,36 +76,29 @@ void __init init_IRQ(void)
#if defined(CONFIG_SMC91X)
/* INT#0: LAN controller on M32104UT-LAN (SMC91C111)*/
- irq_desc[M32R_IRQ_INT0].status = IRQ_DISABLED;
- irq_desc[M32R_IRQ_INT0].chip = &m32104ut_irq_type;
- irq_desc[M32R_IRQ_INT0].action = 0;
- irq_desc[M32R_IRQ_INT0].depth = 1;
- icu_data[M32R_IRQ_INT0].icucr = M32R_ICUCR_IEN | M32R_ICUCR_ISMOD11; /* "H" level sense */
+ set_irq_chip_and_handler(M32R_IRQ_INT0, &m32104ut_irq_type,
+ handle_level_irq);
+ /* "H" level sense */
+ cu_data[M32R_IRQ_INT0].icucr = M32R_ICUCR_IEN | M32R_ICUCR_ISMOD11;
disable_m32104ut_irq(M32R_IRQ_INT0);
#endif /* CONFIG_SMC91X */
/* MFT2 : system timer */
- irq_desc[M32R_IRQ_MFT2].status = IRQ_DISABLED;
- irq_desc[M32R_IRQ_MFT2].chip = &m32104ut_irq_type;
- irq_desc[M32R_IRQ_MFT2].action = 0;
- irq_desc[M32R_IRQ_MFT2].depth = 1;
+ set_irq_chip_and_handler(M32R_IRQ_MFT2, &m32104ut_irq_type,
+ handle_level_irq);
icu_data[M32R_IRQ_MFT2].icucr = M32R_ICUCR_IEN;
disable_m32104ut_irq(M32R_IRQ_MFT2);
#ifdef CONFIG_SERIAL_M32R_SIO
/* SIO0_R : uart receive data */
- irq_desc[M32R_IRQ_SIO0_R].status = IRQ_DISABLED;
- irq_desc[M32R_IRQ_SIO0_R].chip = &m32104ut_irq_type;
- irq_desc[M32R_IRQ_SIO0_R].action = 0;
- irq_desc[M32R_IRQ_SIO0_R].depth = 1;
+ set_irq_chip_and_handler(M32R_IRQ_SIO0_R, &m32104ut_irq_type,
+ handle_level_irq);
icu_data[M32R_IRQ_SIO0_R].icucr = M32R_ICUCR_IEN;
disable_m32104ut_irq(M32R_IRQ_SIO0_R);
/* SIO0_S : uart send data */
- irq_desc[M32R_IRQ_SIO0_S].status = IRQ_DISABLED;
- irq_desc[M32R_IRQ_SIO0_S].chip = &m32104ut_irq_type;
- irq_desc[M32R_IRQ_SIO0_S].action = 0;
- irq_desc[M32R_IRQ_SIO0_S].depth = 1;
+ set_irq_chip_and_handler(M32R_IRQ_SIO0_S, &m32104ut_irq_type,
+ handle_level_irq);
icu_data[M32R_IRQ_SIO0_S].icucr = M32R_ICUCR_IEN;
disable_m32104ut_irq(M32R_IRQ_SIO0_S);
#endif /* CONFIG_SERIAL_M32R_SIO */
diff --git a/arch/m32r/platforms/m32700ut/setup.c b/arch/m32r/platforms/m32700ut/setup.c
index 80b1a02..2074bcc 100644
--- a/arch/m32r/platforms/m32700ut/setup.c
+++ b/arch/m32r/platforms/m32700ut/setup.c
@@ -45,39 +45,30 @@ static void enable_m32700ut_irq(unsigned int irq)
outl(data, port);
}
-static void mask_and_ack_m32700ut(unsigned int irq)
+static void mask_m32700ut(struct irq_data *data)
{
- disable_m32700ut_irq(irq);
+ disable_m32700ut_irq(data->irq);
}
-static void end_m32700ut_irq(unsigned int irq)
+static void unmask_m32700ut(struct irq_data *data)
{
- enable_m32700ut_irq(irq);
+ enable_m32700ut_irq(data->irq);
}
-static unsigned int startup_m32700ut_irq(unsigned int irq)
-{
- enable_m32700ut_irq(irq);
- return (0);
-}
-
-static void shutdown_m32700ut_irq(unsigned int irq)
+static void shutdown_m32700ut(struct irq_data *data)
{
unsigned long port;
- port = irq2port(irq);
+ port = irq2port(data->irq);
outl(M32R_ICUCR_ILEVEL7, port);
}
static struct irq_chip m32700ut_irq_type =
{
- .name = "M32700UT-IRQ",
- .startup = startup_m32700ut_irq,
- .shutdown = shutdown_m32700ut_irq,
- .enable = enable_m32700ut_irq,
- .disable = disable_m32700ut_irq,
- .ack = mask_and_ack_m32700ut,
- .end = end_m32700ut_irq
+ .name = "M32700UT-IRQ",
+ .irq_shutdown = shutdown_m32700ut,
+ .irq_mask = mask_m32700ut,
+ .irq_unmask = unmask_m32700ut
};
/*
@@ -99,7 +90,6 @@ static void disable_m32700ut_pld_irq(unsigned int irq)
unsigned int pldirq;
pldirq = irq2pldirq(irq);
-// disable_m32700ut_irq(M32R_IRQ_INT1);
port = pldirq2port(pldirq);
data = pld_icu_data[pldirq].icucr|PLD_ICUCR_ILEVEL7;
outw(data, port);
@@ -111,50 +101,38 @@ static void enable_m32700ut_pld_irq(unsigned int irq)
unsigned int pldirq;
pldirq = irq2pldirq(irq);
-// enable_m32700ut_irq(M32R_IRQ_INT1);
port = pldirq2port(pldirq);
data = pld_icu_data[pldirq].icucr|PLD_ICUCR_IEN|PLD_ICUCR_ILEVEL6;
outw(data, port);
}
-static void mask_and_ack_m32700ut_pld(unsigned int irq)
-{
- disable_m32700ut_pld_irq(irq);
-// mask_and_ack_m32700ut(M32R_IRQ_INT1);
-}
-
-static void end_m32700ut_pld_irq(unsigned int irq)
+static void mask_m32700ut_pld(struct irq_data *data)
{
- enable_m32700ut_pld_irq(irq);
- end_m32700ut_irq(M32R_IRQ_INT1);
+ disable_m32700ut_pld_irq(data->irq);
}
-static unsigned int startup_m32700ut_pld_irq(unsigned int irq)
+static void unmask_m32700ut_pld(struct irq_data *data)
{
- enable_m32700ut_pld_irq(irq);
- return (0);
+ enable_m32700ut_pld_irq(data->irq);
+ enable_m32700ut_irq(M32R_IRQ_INT1);
}
-static void shutdown_m32700ut_pld_irq(unsigned int irq)
+static void shutdown_m32700ut_pld_irq(struct irq_data *data)
{
unsigned long port;
unsigned int pldirq;
- pldirq = irq2pldirq(irq);
-// shutdown_m32700ut_irq(M32R_IRQ_INT1);
+ pldirq = irq2pldirq(data->irq);
port = pldirq2port(pldirq);
outw(PLD_ICUCR_ILEVEL7, port);
}
static struct irq_chip m32700ut_pld_irq_type =
{
- .name = "M32700UT-PLD-IRQ",
- .startup = startup_m32700ut_pld_irq,
- .shutdown = shutdown_m32700ut_pld_irq,
- .enable = enable_m32700ut_pld_irq,
- .disable = disable_m32700ut_pld_irq,
- .ack = mask_and_ack_m32700ut_pld,
- .end = end_m32700ut_pld_irq
+ .name = "M32700UT-PLD-IRQ",
+ .irq_shutdown = shutdown_m32700ut_pld_irq,
+ .irq_mask = mask_m32700ut_pld,
+ .irq_unmask = unmask_m32700ut_pld,
};
/*
@@ -188,42 +166,33 @@ static void enable_m32700ut_lanpld_irq(unsigned int irq)
outw(data, port);
}
-static void mask_and_ack_m32700ut_lanpld(unsigned int irq)
+static void mask_m32700ut_lanpld(struct irq_data *data)
{
- disable_m32700ut_lanpld_irq(irq);
+ disable_m32700ut_lanpld_irq(data->irq);
}
-static void end_m32700ut_lanpld_irq(unsigned int irq)
+static void unmask_m32700ut_lanpld(struct irq_data *data)
{
- enable_m32700ut_lanpld_irq(irq);
- end_m32700ut_irq(M32R_IRQ_INT0);
-}
-
-static unsigned int startup_m32700ut_lanpld_irq(unsigned int irq)
-{
- enable_m32700ut_lanpld_irq(irq);
- return (0);
+ enable_m32700ut_lanpld_irq(data->irq);
+ enable_m32700ut_irq(M32R_IRQ_INT0);
}
-static void shutdown_m32700ut_lanpld_irq(unsigned int irq)
+static void shutdown_m32700ut_lanpld(struct irq_data *data)
{
unsigned long port;
unsigned int pldirq;
- pldirq = irq2lanpldirq(irq);
+ pldirq = irq2lanpldirq(data->irq);
port = lanpldirq2port(pldirq);
outw(PLD_ICUCR_ILEVEL7, port);
}
static struct irq_chip m32700ut_lanpld_irq_type =
{
- .name = "M32700UT-PLD-LAN-IRQ",
- .startup = startup_m32700ut_lanpld_irq,
- .shutdown = shutdown_m32700ut_lanpld_irq,
- .enable = enable_m32700ut_lanpld_irq,
- .disable = disable_m32700ut_lanpld_irq,
- .ack = mask_and_ack_m32700ut_lanpld,
- .end = end_m32700ut_lanpld_irq
+ .name = "M32700UT-PLD-LAN-IRQ",
+ .irq_shutdown = shutdown_m32700ut_lanpld,
+ .irq_mask = mask_m32700ut_lanpld,
+ .irq_unmask = unmask_m32700ut_lanpld,
};
/*
@@ -257,143 +226,110 @@ static void enable_m32700ut_lcdpld_irq(unsigned int irq)
outw(data, port);
}
-static void mask_and_ack_m32700ut_lcdpld(unsigned int irq)
+static void mask_m32700ut_lcdpld(struct irq_data *data)
{
- disable_m32700ut_lcdpld_irq(irq);
+ disable_m32700ut_lcdpld_irq(data->irq);
}
-static void end_m32700ut_lcdpld_irq(unsigned int irq)
+static void unmask_m32700ut_lcdpld(struct irq_data *data)
{
- enable_m32700ut_lcdpld_irq(irq);
- end_m32700ut_irq(M32R_IRQ_INT2);
-}
-
-static unsigned int startup_m32700ut_lcdpld_irq(unsigned int irq)
-{
- enable_m32700ut_lcdpld_irq(irq);
- return (0);
+ enable_m32700ut_lcdpld_irq(data->irq);
+ enable_m32700ut_irq(M32R_IRQ_INT2);
}
-static void shutdown_m32700ut_lcdpld_irq(unsigned int irq)
+static void shutdown_m32700ut_lcdpld(struct irq_data *data)
{
unsigned long port;
unsigned int pldirq;
- pldirq = irq2lcdpldirq(irq);
+ pldirq = irq2lcdpldirq(data->irq);
port = lcdpldirq2port(pldirq);
outw(PLD_ICUCR_ILEVEL7, port);
}
static struct irq_chip m32700ut_lcdpld_irq_type =
{
- .name = "M32700UT-PLD-LCD-IRQ",
- .startup = startup_m32700ut_lcdpld_irq,
- .shutdown = shutdown_m32700ut_lcdpld_irq,
- .enable = enable_m32700ut_lcdpld_irq,
- .disable = disable_m32700ut_lcdpld_irq,
- .ack = mask_and_ack_m32700ut_lcdpld,
- .end = end_m32700ut_lcdpld_irq
+ .name = "M32700UT-PLD-LCD-IRQ",
+ .irq_shutdown = shutdown_m32700ut_lcdpld,
+ .irq_mask = mask_m32700ut_lcdpld,
+ .irq_unmask = unmask_m32700ut_lcdpld,
};
void __init init_IRQ(void)
{
#if defined(CONFIG_SMC91X)
/* INT#0: LAN controller on M32700UT-LAN (SMC91C111)*/
- irq_desc[M32700UT_LAN_IRQ_LAN].status = IRQ_DISABLED;
- irq_desc[M32700UT_LAN_IRQ_LAN].chip = &m32700ut_lanpld_irq_type;
- irq_desc[M32700UT_LAN_IRQ_LAN].action = 0;
- irq_desc[M32700UT_LAN_IRQ_LAN].depth = 1; /* disable nested irq */
+ set_irq_chip_and_handler(M32700UT_LAN_IRQ_LAN,
+ &m32700ut_lanpld_irq_type, handle_level_irq);
lanpld_icu_data[irq2lanpldirq(M32700UT_LAN_IRQ_LAN)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD02; /* "H" edge sense */
disable_m32700ut_lanpld_irq(M32700UT_LAN_IRQ_LAN);
#endif /* CONFIG_SMC91X */
/* MFT2 : system timer */
- irq_desc[M32R_IRQ_MFT2].status = IRQ_DISABLED;
- irq_desc[M32R_IRQ_MFT2].chip = &m32700ut_irq_type;
- irq_desc[M32R_IRQ_MFT2].action = 0;
- irq_desc[M32R_IRQ_MFT2].depth = 1;
+ set_irq_chip_and_handler(M32R_IRQ_MFT2, &m32700ut_irq_type,
+ handle_level_irq);
icu_data[M32R_IRQ_MFT2].icucr = M32R_ICUCR_IEN;
disable_m32700ut_irq(M32R_IRQ_MFT2);
/* SIO0 : receive */
- irq_desc[M32R_IRQ_SIO0_R].status = IRQ_DISABLED;
- irq_desc[M32R_IRQ_SIO0_R].chip = &m32700ut_irq_type;
- irq_desc[M32R_IRQ_SIO0_R].action = 0;
- irq_desc[M32R_IRQ_SIO0_R].depth = 1;
+ set_irq_chip_and_handler(M32R_IRQ_SIO0_R, &m32700ut_irq_type,
+ handle_level_irq);
icu_data[M32R_IRQ_SIO0_R].icucr = 0;
disable_m32700ut_irq(M32R_IRQ_SIO0_R);
/* SIO0 : send */
- irq_desc[M32R_IRQ_SIO0_S].status = IRQ_DISABLED;
- irq_desc[M32R_IRQ_SIO0_S].chip = &m32700ut_irq_type;
- irq_desc[M32R_IRQ_SIO0_S].action = 0;
- irq_desc[M32R_IRQ_SIO0_S].depth = 1;
+ set_irq_chip_and_handler(M32R_IRQ_SIO0_S, &m32700ut_irq_type,
+ handle_level_irq);
icu_data[M32R_IRQ_SIO0_S].icucr = 0;
disable_m32700ut_irq(M32R_IRQ_SIO0_S);
/* SIO1 : receive */
- irq_desc[M32R_IRQ_SIO1_R].status = IRQ_DISABLED;
- irq_desc[M32R_IRQ_SIO1_R].chip = &m32700ut_irq_type;
- irq_desc[M32R_IRQ_SIO1_R].action = 0;
- irq_desc[M32R_IRQ_SIO1_R].depth = 1;
+ set_irq_chip_and_handler(M32R_IRQ_SIO1_R, &m32700ut_irq_type,
+ handle_level_irq);
icu_data[M32R_IRQ_SIO1_R].icucr = 0;
disable_m32700ut_irq(M32R_IRQ_SIO1_R);
/* SIO1 : send */
- irq_desc[M32R_IRQ_SIO1_S].status = IRQ_DISABLED;
- irq_desc[M32R_IRQ_SIO1_S].chip = &m32700ut_irq_type;
- irq_desc[M32R_IRQ_SIO1_S].action = 0;
- irq_desc[M32R_IRQ_SIO1_S].depth = 1;
+ set_irq_chip_and_handler(M32R_IRQ_SIO1_S, &m32700ut_irq_type,
+ handle_level_irq);
icu_data[M32R_IRQ_SIO1_S].icucr = 0;
disable_m32700ut_irq(M32R_IRQ_SIO1_S);
/* DMA1 : */
- irq_desc[M32R_IRQ_DMA1].status = IRQ_DISABLED;
- irq_desc[M32R_IRQ_DMA1].chip = &m32700ut_irq_type;
- irq_desc[M32R_IRQ_DMA1].action = 0;
- irq_desc[M32R_IRQ_DMA1].depth = 1;
+ set_irq_chip_and_handler(M32R_IRQ_DMA1, &m32700ut_irq_type,
+ handle_level_irq);
icu_data[M32R_IRQ_DMA1].icucr = 0;
disable_m32700ut_irq(M32R_IRQ_DMA1);
#ifdef CONFIG_SERIAL_M32R_PLDSIO
/* INT#1: SIO0 Receive on PLD */
- irq_desc[PLD_IRQ_SIO0_RCV].status = IRQ_DISABLED;
- irq_desc[PLD_IRQ_SIO0_RCV].chip = &m32700ut_pld_irq_type;
- irq_desc[PLD_IRQ_SIO0_RCV].action = 0;
- irq_desc[PLD_IRQ_SIO0_RCV].depth = 1; /* disable nested irq */
+ set_irq_chip_and_handler(PLD_IRQ_SIO0_RCV, &m32700ut_pld_irq_type,
+ handle_level_irq);
pld_icu_data[irq2pldirq(PLD_IRQ_SIO0_RCV)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD03;
disable_m32700ut_pld_irq(PLD_IRQ_SIO0_RCV);
/* INT#1: SIO0 Send on PLD */
- irq_desc[PLD_IRQ_SIO0_SND].status = IRQ_DISABLED;
- irq_desc[PLD_IRQ_SIO0_SND].chip = &m32700ut_pld_irq_type;
- irq_desc[PLD_IRQ_SIO0_SND].action = 0;
- irq_desc[PLD_IRQ_SIO0_SND].depth = 1; /* disable nested irq */
+ set_irq_chip_and_handler(PLD_IRQ_SIO0_SND, &m32700ut_pld_irq_type,
+ handle_level_irq);
pld_icu_data[irq2pldirq(PLD_IRQ_SIO0_SND)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD03;
disable_m32700ut_pld_irq(PLD_IRQ_SIO0_SND);
#endif /* CONFIG_SERIAL_M32R_PLDSIO */
/* INT#1: CFC IREQ on PLD */
- irq_desc[PLD_IRQ_CFIREQ].status = IRQ_DISABLED;
- irq_desc[PLD_IRQ_CFIREQ].chip = &m32700ut_pld_irq_type;
- irq_desc[PLD_IRQ_CFIREQ].action = 0;
- irq_desc[PLD_IRQ_CFIREQ].depth = 1; /* disable nested irq */
+ set_irq_chip_and_handler(PLD_IRQ_CFIREQ, &m32700ut_pld_irq_type,
+ handle_level_irq);
pld_icu_data[irq2pldirq(PLD_IRQ_CFIREQ)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD01; /* 'L' level sense */
disable_m32700ut_pld_irq(PLD_IRQ_CFIREQ);
/* INT#1: CFC Insert on PLD */
- irq_desc[PLD_IRQ_CFC_INSERT].status = IRQ_DISABLED;
- irq_desc[PLD_IRQ_CFC_INSERT].chip = &m32700ut_pld_irq_type;
- irq_desc[PLD_IRQ_CFC_INSERT].action = 0;
- irq_desc[PLD_IRQ_CFC_INSERT].depth = 1; /* disable nested irq */
+ set_irq_chip_and_handler(PLD_IRQ_CFC_INSERT, &m32700ut_pld_irq_type,
+ handle_level_irq);
pld_icu_data[irq2pldirq(PLD_IRQ_CFC_INSERT)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD00; /* 'L' edge sense */
disable_m32700ut_pld_irq(PLD_IRQ_CFC_INSERT);
/* INT#1: CFC Eject on PLD */
- irq_desc[PLD_IRQ_CFC_EJECT].status = IRQ_DISABLED;
- irq_desc[PLD_IRQ_CFC_EJECT].chip = &m32700ut_pld_irq_type;
- irq_desc[PLD_IRQ_CFC_EJECT].action = 0;
- irq_desc[PLD_IRQ_CFC_EJECT].depth = 1; /* disable nested irq */
+ set_irq_chip_and_handler(PLD_IRQ_CFC_EJECT, &m32700ut_pld_irq_type,
+ handle_level_irq);
pld_icu_data[irq2pldirq(PLD_IRQ_CFC_EJECT)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD02; /* 'H' edge sense */
disable_m32700ut_pld_irq(PLD_IRQ_CFC_EJECT);
@@ -413,13 +349,11 @@ void __init init_IRQ(void)
#if defined(CONFIG_USB)
outw(USBCR_OTGS, USBCR); /* USBCR: non-OTG */
+ set_irq_chip_and_handler(M32700UT_LCD_IRQ_USB_INT1,
+ &m32700ut_lcdpld_irq_type, handle_level_irq);
- irq_desc[M32700UT_LCD_IRQ_USB_INT1].status = IRQ_DISABLED;
- irq_desc[M32700UT_LCD_IRQ_USB_INT1].chip = &m32700ut_lcdpld_irq_type;
- irq_desc[M32700UT_LCD_IRQ_USB_INT1].action = 0;
- irq_desc[M32700UT_LCD_IRQ_USB_INT1].depth = 1;
- lcdpld_icu_data[irq2lcdpldirq(M32700UT_LCD_IRQ_USB_INT1)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD01; /* "L" level sense */
- disable_m32700ut_lcdpld_irq(M32700UT_LCD_IRQ_USB_INT1);
+ lcdpld_icu_data[irq2lcdpldirq(M32700UT_LCD_IRQ_USB_INT1)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD01; /* "L" level sense */
+ disable_m32700ut_lcdpld_irq(M32700UT_LCD_IRQ_USB_INT1);
#endif
/*
* INT2# is used for BAT, USB, AUDIO
@@ -432,10 +366,8 @@ void __init init_IRQ(void)
/*
* INT3# is used for AR
*/
- irq_desc[M32R_IRQ_INT3].status = IRQ_DISABLED;
- irq_desc[M32R_IRQ_INT3].chip = &m32700ut_irq_type;
- irq_desc[M32R_IRQ_INT3].action = 0;
- irq_desc[M32R_IRQ_INT3].depth = 1;
+ set_irq_chip_and_handler(M32R_IRQ_INT3, &m32700ut_irq_type,
+ handle_level_irq);
icu_data[M32R_IRQ_INT3].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD10;
disable_m32700ut_irq(M32R_IRQ_INT3);
#endif /* CONFIG_VIDEO_M32R_AR */
diff --git a/arch/m32r/platforms/mappi/setup.c b/arch/m32r/platforms/mappi/setup.c
index ea00c84..cdd8c45 100644
--- a/arch/m32r/platforms/mappi/setup.c
+++ b/arch/m32r/platforms/mappi/setup.c
@@ -38,40 +38,30 @@ static void enable_mappi_irq(unsigned int irq)
outl(data, port);
}
-static void mask_and_ack_mappi(unsigned int irq)
+static void mask_mappi(struct irq_data *data)
{
- disable_mappi_irq(irq);
+ disable_mappi_irq(data->irq);
}
-static void end_mappi_irq(unsigned int irq)
+static void unmask_mappi(struct irq_data *data)
{
- if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
- enable_mappi_irq(irq);
+ enable_mappi_irq(data->irq);
}
-static unsigned int startup_mappi_irq(unsigned int irq)
-{
- enable_mappi_irq(irq);
- return (0);
-}
-
-static void shutdown_mappi_irq(unsigned int irq)
+static void shutdown_mappi(struct irq_data *data)
{
unsigned long port;
- port = irq2port(irq);
+ port = irq2port(data->irq);
outl(M32R_ICUCR_ILEVEL7, port);
}
static struct irq_chip mappi_irq_type =
{
- .name = "MAPPI-IRQ",
- .startup = startup_mappi_irq,
- .shutdown = shutdown_mappi_irq,
- .enable = enable_mappi_irq,
- .disable = disable_mappi_irq,
- .ack = mask_and_ack_mappi,
- .end = end_mappi_irq
+ .name = "MAPPI-IRQ",
+ .irq_shutdown = shutdown_mappi,
+ .irq_mask = mask_mappi,
+ .irq_unmask = unmask_mappi,
};
void __init init_IRQ(void)
@@ -85,70 +75,54 @@ void __init init_IRQ(void)
#ifdef CONFIG_NE2000
/* INT0 : LAN controller (RTL8019AS) */
- irq_desc[M32R_IRQ_INT0].status = IRQ_DISABLED;
- irq_desc[M32R_IRQ_INT0].chip = &mappi_irq_type;
- irq_desc[M32R_IRQ_INT0].action = NULL;
- irq_desc[M32R_IRQ_INT0].depth = 1;
+ set_irq_chip_and_handler(M32R_IRQ_INT0, &mappi_irq_type,
+ handle_level_irq);
icu_data[M32R_IRQ_INT0].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD11;
disable_mappi_irq(M32R_IRQ_INT0);
#endif /* CONFIG_M32R_NE2000 */
/* MFT2 : system timer */
- irq_desc[M32R_IRQ_MFT2].status = IRQ_DISABLED;
- irq_desc[M32R_IRQ_MFT2].chip = &mappi_irq_type;
- irq_desc[M32R_IRQ_MFT2].action = NULL;
- irq_desc[M32R_IRQ_MFT2].depth = 1;
+ set_irq_chip_and_handler(M32R_IRQ_MFT2, &mappi_irq_type,
+ handle_level_irq);
icu_data[M32R_IRQ_MFT2].icucr = M32R_ICUCR_IEN;
disable_mappi_irq(M32R_IRQ_MFT2);
#ifdef CONFIG_SERIAL_M32R_SIO
/* SIO0_R : uart receive data */
- irq_desc[M32R_IRQ_SIO0_R].status = IRQ_DISABLED;
- irq_desc[M32R_IRQ_SIO0_R].chip = &mappi_irq_type;
- irq_desc[M32R_IRQ_SIO0_R].action = NULL;
- irq_desc[M32R_IRQ_SIO0_R].depth = 1;
+ set_irq_chip_and_handler(M32R_IRQ_SIO0_R, &mappi_irq_type,
+ handle_level_irq);
icu_data[M32R_IRQ_SIO0_R].icucr = 0;
disable_mappi_irq(M32R_IRQ_SIO0_R);
/* SIO0_S : uart send data */
- irq_desc[M32R_IRQ_SIO0_S].status = IRQ_DISABLED;
- irq_desc[M32R_IRQ_SIO0_S].chip = &mappi_irq_type;
- irq_desc[M32R_IRQ_SIO0_S].action = NULL;
- irq_desc[M32R_IRQ_SIO0_S].depth = 1;
+ set_irq_chip_and_handler(M32R_IRQ_SIO0_S, &mappi_irq_type,
+ handle_level_irq);
icu_data[M32R_IRQ_SIO0_S].icucr = 0;
disable_mappi_irq(M32R_IRQ_SIO0_S);
/* SIO1_R : uart receive data */
- irq_desc[M32R_IRQ_SIO1_R].status = IRQ_DISABLED;
- irq_desc[M32R_IRQ_SIO1_R].chip = &mappi_irq_type;
- irq_desc[M32R_IRQ_SIO1_R].action = NULL;
- irq_desc[M32R_IRQ_SIO1_R].depth = 1;
+ set_irq_chip_and_handler(M32R_IRQ_SIO1_R, &mappi_irq_type,
+ handle_level_irq);
icu_data[M32R_IRQ_SIO1_R].icucr = 0;
disable_mappi_irq(M32R_IRQ_SIO1_R);
/* SIO1_S : uart send data */
- irq_desc[M32R_IRQ_SIO1_S].status = IRQ_DISABLED;
- irq_desc[M32R_IRQ_SIO1_S].chip = &mappi_irq_type;
- irq_desc[M32R_IRQ_SIO1_S].action = NULL;
- irq_desc[M32R_IRQ_SIO1_S].depth = 1;
+ set_irq_chip_and_handler(M32R_IRQ_SIO1_S, &mappi_irq_type,
+ handle_level_irq);
icu_data[M32R_IRQ_SIO1_S].icucr = 0;
disable_mappi_irq(M32R_IRQ_SIO1_S);
#endif /* CONFIG_SERIAL_M32R_SIO */
#if defined(CONFIG_M32R_PCC)
/* INT1 : pccard0 interrupt */
- irq_desc[M32R_IRQ_INT1].status = IRQ_DISABLED;
- irq_desc[M32R_IRQ_INT1].chip = &mappi_irq_type;
- irq_desc[M32R_IRQ_INT1].action = NULL;
- irq_desc[M32R_IRQ_INT1].depth = 1;
+ set_irq_chip_and_handler(M32R_IRQ_INT1, &mappi_irq_type,
+ handle_level_irq);
icu_data[M32R_IRQ_INT1].icucr = M32R_ICUCR_IEN | M32R_ICUCR_ISMOD00;
disable_mappi_irq(M32R_IRQ_INT1);
/* INT2 : pccard1 interrupt */
- irq_desc[M32R_IRQ_INT2].status = IRQ_DISABLED;
- irq_desc[M32R_IRQ_INT2].chip = &mappi_irq_type;
- irq_desc[M32R_IRQ_INT2].action = NULL;
- irq_desc[M32R_IRQ_INT2].depth = 1;
+ set_irq_chip_and_handler(M32R_IRQ_INT2, &mappi_irq_type,
+ handle_level_irq);
icu_data[M32R_IRQ_INT2].icucr = M32R_ICUCR_IEN | M32R_ICUCR_ISMOD00;
disable_mappi_irq(M32R_IRQ_INT2);
#endif /* CONFIG_M32RPCC */
diff --git a/arch/m32r/platforms/mappi2/setup.c b/arch/m32r/platforms/mappi2/setup.c
index c049376..9117c30 100644
--- a/arch/m32r/platforms/mappi2/setup.c
+++ b/arch/m32r/platforms/mappi2/setup.c
@@ -46,126 +46,97 @@ static void enable_mappi2_irq(unsigned int irq)
outl(data, port);
}
-static void mask_and_ack_mappi2(unsigned int irq)
+static void mask_mappi2(struct irq_data *data)
{
- disable_mappi2_irq(irq);
+ disable_mappi2_irq(data->irq);
}
-static void end_mappi2_irq(unsigned int irq)
+static void unmask_mappi2(struct irq_data *data)
{
- enable_mappi2_irq(irq);
+ enable_mappi2_irq(data->irq);
}
-static unsigned int startup_mappi2_irq(unsigned int irq)
-{
- enable_mappi2_irq(irq);
- return (0);
-}
-
-static void shutdown_mappi2_irq(unsigned int irq)
+static void shutdown_mappi2(struct irq_data *data)
{
unsigned long port;
- port = irq2port(irq);
+ port = irq2port(data->irq);
outl(M32R_ICUCR_ILEVEL7, port);
}
static struct irq_chip mappi2_irq_type =
{
- .name = "MAPPI2-IRQ",
- .startup = startup_mappi2_irq,
- .shutdown = shutdown_mappi2_irq,
- .enable = enable_mappi2_irq,
- .disable = disable_mappi2_irq,
- .ack = mask_and_ack_mappi2,
- .end = end_mappi2_irq
+ .name = "MAPPI2-IRQ",
+ .irq_shutdown = shutdown_mappi2,
+ .irq_mask = mask_mappi2,
+ .irq_unmask = unmask_mappi2,
};
void __init init_IRQ(void)
{
#if defined(CONFIG_SMC91X)
/* INT0 : LAN controller (SMC91111) */
- irq_desc[M32R_IRQ_INT0].status = IRQ_DISABLED;
- irq_desc[M32R_IRQ_INT0].chip = &mappi2_irq_type;
- irq_desc[M32R_IRQ_INT0].action = 0;
- irq_desc[M32R_IRQ_INT0].depth = 1;
+ set_irq_chip_and_handler(M32R_IRQ_INT0, &mappi2_irq_type,
+ handle_level_irq);
icu_data[M32R_IRQ_INT0].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD10;
disable_mappi2_irq(M32R_IRQ_INT0);
#endif /* CONFIG_SMC91X */
/* MFT2 : system timer */
- irq_desc[M32R_IRQ_MFT2].status = IRQ_DISABLED;
- irq_desc[M32R_IRQ_MFT2].chip = &mappi2_irq_type;
- irq_desc[M32R_IRQ_MFT2].action = 0;
- irq_desc[M32R_IRQ_MFT2].depth = 1;
+ set_irq_chip_and_handler(M32R_IRQ_MFT2, &mappi2_irq_type,
+ handle_level_irq);
icu_data[M32R_IRQ_MFT2].icucr = M32R_ICUCR_IEN;
disable_mappi2_irq(M32R_IRQ_MFT2);
#ifdef CONFIG_SERIAL_M32R_SIO
/* SIO0_R : uart receive data */
- irq_desc[M32R_IRQ_SIO0_R].status = IRQ_DISABLED;
- irq_desc[M32R_IRQ_SIO0_R].chip = &mappi2_irq_type;
- irq_desc[M32R_IRQ_SIO0_R].action = 0;
- irq_desc[M32R_IRQ_SIO0_R].depth = 1;
+ set_irq_chip_and_handler(M32R_IRQ_SIO0_R, &mappi2_irq_type,
+ handle_level_irq);
icu_data[M32R_IRQ_SIO0_R].icucr = 0;
disable_mappi2_irq(M32R_IRQ_SIO0_R);
/* SIO0_S : uart send data */
- irq_desc[M32R_IRQ_SIO0_S].status = IRQ_DISABLED;
- irq_desc[M32R_IRQ_SIO0_S].chip = &mappi2_irq_type;
- irq_desc[M32R_IRQ_SIO0_S].action = 0;
- irq_desc[M32R_IRQ_SIO0_S].depth = 1;
+ set_irq_chip_and_handler(M32R_IRQ_SIO0_S, &mappi2_irq_type,
+ handle_level_irq);
icu_data[M32R_IRQ_SIO0_S].icucr = 0;
disable_mappi2_irq(M32R_IRQ_SIO0_S);
/* SIO1_R : uart receive data */
- irq_desc[M32R_IRQ_SIO1_R].status = IRQ_DISABLED;
- irq_desc[M32R_IRQ_SIO1_R].chip = &mappi2_irq_type;
- irq_desc[M32R_IRQ_SIO1_R].action = 0;
- irq_desc[M32R_IRQ_SIO1_R].depth = 1;
+ set_irq_chip_and_handler(M32R_IRQ_SIO1_R, &mappi2_irq_type,
+ handle_level_irq);
icu_data[M32R_IRQ_SIO1_R].icucr = 0;
disable_mappi2_irq(M32R_IRQ_SIO1_R);
/* SIO1_S : uart send data */
- irq_desc[M32R_IRQ_SIO1_S].status = IRQ_DISABLED;
- irq_desc[M32R_IRQ_SIO1_S].chip = &mappi2_irq_type;
- irq_desc[M32R_IRQ_SIO1_S].action = 0;
- irq_desc[M32R_IRQ_SIO1_S].depth = 1;
+ set_irq_chip_and_handler(M32R_IRQ_SIO1_S, &mappi2_irq_type,
+ handle_level_irq);
icu_data[M32R_IRQ_SIO1_S].icucr = 0;
disable_mappi2_irq(M32R_IRQ_SIO1_S);
#endif /* CONFIG_M32R_USE_DBG_CONSOLE */
#if defined(CONFIG_USB)
/* INT1 : USB Host controller interrupt */
- irq_desc[M32R_IRQ_INT1].status = IRQ_DISABLED;
- irq_desc[M32R_IRQ_INT1].chip = &mappi2_irq_type;
- irq_desc[M32R_IRQ_INT1].action = 0;
- irq_desc[M32R_IRQ_INT1].depth = 1;
+ set_irq_chip_and_handler(M32R_IRQ_INT1, &mappi2_irq_type,
+ handle_level_irq);
icu_data[M32R_IRQ_INT1].icucr = M32R_ICUCR_ISMOD01;
disable_mappi2_irq(M32R_IRQ_INT1);
#endif /* CONFIG_USB */
/* ICUCR40: CFC IREQ */
- irq_desc[PLD_IRQ_CFIREQ].status = IRQ_DISABLED;
- irq_desc[PLD_IRQ_CFIREQ].chip = &mappi2_irq_type;
- irq_desc[PLD_IRQ_CFIREQ].action = 0;
- irq_desc[PLD_IRQ_CFIREQ].depth = 1; /* disable nested irq */
+ set_irq_chip_and_handler(PLD_IRQ_CFIREQ, &mappi2_irq_type,
+ handle_level_irq);
icu_data[PLD_IRQ_CFIREQ].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD01;
disable_mappi2_irq(PLD_IRQ_CFIREQ);
#if defined(CONFIG_M32R_CFC)
/* ICUCR41: CFC Insert */
- irq_desc[PLD_IRQ_CFC_INSERT].status = IRQ_DISABLED;
- irq_desc[PLD_IRQ_CFC_INSERT].chip = &mappi2_irq_type;
- irq_desc[PLD_IRQ_CFC_INSERT].action = 0;
- irq_desc[PLD_IRQ_CFC_INSERT].depth = 1; /* disable nested irq */
+ set_irq_chip_and_handler(PLD_IRQ_CFC_INSERT, &mappi2_irq_type,
+ handle_level_irq);
icu_data[PLD_IRQ_CFC_INSERT].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD00;
disable_mappi2_irq(PLD_IRQ_CFC_INSERT);
/* ICUCR42: CFC Eject */
- irq_desc[PLD_IRQ_CFC_EJECT].status = IRQ_DISABLED;
- irq_desc[PLD_IRQ_CFC_EJECT].chip = &mappi2_irq_type;
- irq_desc[PLD_IRQ_CFC_EJECT].action = 0;
- irq_desc[PLD_IRQ_CFC_EJECT].depth = 1; /* disable nested irq */
+ set_irq_chip_and_handler(PLD_IRQ_CFC_EJECT, &mappi2_irq_type,
+ handle_level_irq);
icu_data[PLD_IRQ_CFC_EJECT].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD10;
disable_mappi2_irq(PLD_IRQ_CFC_EJECT);
#endif /* CONFIG_MAPPI2_CFC */
diff --git a/arch/m32r/platforms/mappi3/setup.c b/arch/m32r/platforms/mappi3/setup.c
index 882de25..b44f5de 100644
--- a/arch/m32r/platforms/mappi3/setup.c
+++ b/arch/m32r/platforms/mappi3/setup.c
@@ -46,128 +46,98 @@ static void enable_mappi3_irq(unsigned int irq)
outl(data, port);
}
-static void mask_and_ack_mappi3(unsigned int irq)
+static void mask_mappi3(struct irq_data *data)
{
- disable_mappi3_irq(irq);
+ disable_mappi3_irq(data->irq);
}
-static void end_mappi3_irq(unsigned int irq)
+static void unmask_mappi3(struct irq_data *data)
{
- enable_mappi3_irq(irq);
+ enable_mappi3_irq(data->irq);
}
-static unsigned int startup_mappi3_irq(unsigned int irq)
-{
- enable_mappi3_irq(irq);
- return (0);
-}
-
-static void shutdown_mappi3_irq(unsigned int irq)
+static void shutdown_mappi3(struct irq_data *data)
{
unsigned long port;
- port = irq2port(irq);
+ port = irq2port(data->irq);
outl(M32R_ICUCR_ILEVEL7, port);
}
-static struct irq_chip mappi3_irq_type =
-{
- .name = "MAPPI3-IRQ",
- .startup = startup_mappi3_irq,
- .shutdown = shutdown_mappi3_irq,
- .enable = enable_mappi3_irq,
- .disable = disable_mappi3_irq,
- .ack = mask_and_ack_mappi3,
- .end = end_mappi3_irq
+static struct irq_chip mappi3_irq_type = {
+ .name = "MAPPI3-IRQ",
+ .irq_shutdown = shutdown_mappi3,
+ .irq_mask = mask_mappi3,
+ .irq_unmask = unmask_mappi3,
};
void __init init_IRQ(void)
{
#if defined(CONFIG_SMC91X)
/* INT0 : LAN controller (SMC91111) */
- irq_desc[M32R_IRQ_INT0].status = IRQ_DISABLED;
- irq_desc[M32R_IRQ_INT0].chip = &mappi3_irq_type;
- irq_desc[M32R_IRQ_INT0].action = 0;
- irq_desc[M32R_IRQ_INT0].depth = 1;
+ set_irq_chip_and_handler(M32R_IRQ_INT0, &mappi3_irq_type,
+ handle_level_irq);
icu_data[M32R_IRQ_INT0].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD10;
disable_mappi3_irq(M32R_IRQ_INT0);
#endif /* CONFIG_SMC91X */
/* MFT2 : system timer */
- irq_desc[M32R_IRQ_MFT2].status = IRQ_DISABLED;
- irq_desc[M32R_IRQ_MFT2].chip = &mappi3_irq_type;
- irq_desc[M32R_IRQ_MFT2].action = 0;
- irq_desc[M32R_IRQ_MFT2].depth = 1;
+ set_irq_chip_and_handler(M32R_IRQ_MFT2, &mappi3_irq_type,
+ handle_level_irq);
icu_data[M32R_IRQ_MFT2].icucr = M32R_ICUCR_IEN;
disable_mappi3_irq(M32R_IRQ_MFT2);
#ifdef CONFIG_SERIAL_M32R_SIO
/* SIO0_R : uart receive data */
- irq_desc[M32R_IRQ_SIO0_R].status = IRQ_DISABLED;
- irq_desc[M32R_IRQ_SIO0_R].chip = &mappi3_irq_type;
- irq_desc[M32R_IRQ_SIO0_R].action = 0;
- irq_desc[M32R_IRQ_SIO0_R].depth = 1;
+ set_irq_chip_and_handler(M32R_IRQ_SIO0_R, &mappi3_irq_type,
+ handle_level_irq);
icu_data[M32R_IRQ_SIO0_R].icucr = 0;
disable_mappi3_irq(M32R_IRQ_SIO0_R);
/* SIO0_S : uart send data */
- irq_desc[M32R_IRQ_SIO0_S].status = IRQ_DISABLED;
- irq_desc[M32R_IRQ_SIO0_S].chip = &mappi3_irq_type;
- irq_desc[M32R_IRQ_SIO0_S].action = 0;
- irq_desc[M32R_IRQ_SIO0_S].depth = 1;
+ set_irq_chip_and_handler(M32R_IRQ_SIO0_S, &mappi3_irq_type,
+ handle_level_irq);
icu_data[M32R_IRQ_SIO0_S].icucr = 0;
disable_mappi3_irq(M32R_IRQ_SIO0_S);
/* SIO1_R : uart receive data */
- irq_desc[M32R_IRQ_SIO1_R].status = IRQ_DISABLED;
- irq_desc[M32R_IRQ_SIO1_R].chip = &mappi3_irq_type;
- irq_desc[M32R_IRQ_SIO1_R].action = 0;
- irq_desc[M32R_IRQ_SIO1_R].depth = 1;
+ set_irq_chip_and_handler(M32R_IRQ_SIO1_R, &mappi3_irq_type,
+ handle_level_irq);
icu_data[M32R_IRQ_SIO1_R].icucr = 0;
disable_mappi3_irq(M32R_IRQ_SIO1_R);
/* SIO1_S : uart send data */
- irq_desc[M32R_IRQ_SIO1_S].status = IRQ_DISABLED;
- irq_desc[M32R_IRQ_SIO1_S].chip = &mappi3_irq_type;
- irq_desc[M32R_IRQ_SIO1_S].action = 0;
- irq_desc[M32R_IRQ_SIO1_S].depth = 1;
+ set_irq_chip_and_handler(M32R_IRQ_SIO1_S, &mappi3_irq_type,
+ handle_level_irq);
icu_data[M32R_IRQ_SIO1_S].icucr = 0;
disable_mappi3_irq(M32R_IRQ_SIO1_S);
#endif /* CONFIG_M32R_USE_DBG_CONSOLE */
#if defined(CONFIG_USB)
/* INT1 : USB Host controller interrupt */
- irq_desc[M32R_IRQ_INT1].status = IRQ_DISABLED;
- irq_desc[M32R_IRQ_INT1].chip = &mappi3_irq_type;
- irq_desc[M32R_IRQ_INT1].action = 0;
- irq_desc[M32R_IRQ_INT1].depth = 1;
+ set_irq_chip_and_handler(M32R_IRQ_INT1, &mappi3_irq_type,
+ handle_level_irq);
icu_data[M32R_IRQ_INT1].icucr = M32R_ICUCR_ISMOD01;
disable_mappi3_irq(M32R_IRQ_INT1);
#endif /* CONFIG_USB */
/* CFC IREQ */
- irq_desc[PLD_IRQ_CFIREQ].status = IRQ_DISABLED;
- irq_desc[PLD_IRQ_CFIREQ].chip = &mappi3_irq_type;
- irq_desc[PLD_IRQ_CFIREQ].action = 0;
- irq_desc[PLD_IRQ_CFIREQ].depth = 1; /* disable nested irq */
+ set_irq_chip_and_handler(PLD_IRQ_CFIREQ, &mappi3_irq_type,
+ handle_level_irq);
icu_data[PLD_IRQ_CFIREQ].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD01;
disable_mappi3_irq(PLD_IRQ_CFIREQ);
#if defined(CONFIG_M32R_CFC)
/* ICUCR41: CFC Insert & eject */
- irq_desc[PLD_IRQ_CFC_INSERT].status = IRQ_DISABLED;
- irq_desc[PLD_IRQ_CFC_INSERT].chip = &mappi3_irq_type;
- irq_desc[PLD_IRQ_CFC_INSERT].action = 0;
- irq_desc[PLD_IRQ_CFC_INSERT].depth = 1; /* disable nested irq */
+ set_irq_chip_and_handler(PLD_IRQ_CFC_INSERT, &mappi3_irq_type,
+ handle_level_irq);
icu_data[PLD_IRQ_CFC_INSERT].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD00;
disable_mappi3_irq(PLD_IRQ_CFC_INSERT);
#endif /* CONFIG_M32R_CFC */
/* IDE IREQ */
- irq_desc[PLD_IRQ_IDEIREQ].status = IRQ_DISABLED;
- irq_desc[PLD_IRQ_IDEIREQ].chip = &mappi3_irq_type;
- irq_desc[PLD_IRQ_IDEIREQ].action = 0;
- irq_desc[PLD_IRQ_IDEIREQ].depth = 1; /* disable nested irq */
+ set_irq_chip_and_handler(PLD_IRQ_IDEIREQ, &mappi3_irq_type,
+ handle_level_irq);
icu_data[PLD_IRQ_IDEIREQ].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD10;
disable_mappi3_irq(PLD_IRQ_IDEIREQ);
diff --git a/arch/m32r/platforms/oaks32r/setup.c b/arch/m32r/platforms/oaks32r/setup.c
index d11d93b..19a02db 100644
--- a/arch/m32r/platforms/oaks32r/setup.c
+++ b/arch/m32r/platforms/oaks32r/setup.c
@@ -37,39 +37,30 @@ static void enable_oaks32r_irq(unsigned int irq)
outl(data, port);
}
-static void mask_and_ack_mappi(unsigned int irq)
+static void mask_oaks32r(struct irq_data *data)
{
- disable_oaks32r_irq(irq);
+ disable_oaks32r_irq(data->irq);
}
-static void end_oaks32r_irq(unsigned int irq)
+static void unmask_oaks32r(struct irq_data *data)
{
- enable_oaks32r_irq(irq);
+ enable_oaks32r_irq(data->irq);
}
-static unsigned int startup_oaks32r_irq(unsigned int irq)
-{
- enable_oaks32r_irq(irq);
- return (0);
-}
-
-static void shutdown_oaks32r_irq(unsigned int irq)
+static void shutdown_oaks32r(struct irq_data *data)
{
unsigned long port;
- port = irq2port(irq);
+ port = irq2port(data->irq);
outl(M32R_ICUCR_ILEVEL7, port);
}
static struct irq_chip oaks32r_irq_type =
{
- .name = "OAKS32R-IRQ",
- .startup = startup_oaks32r_irq,
- .shutdown = shutdown_oaks32r_irq,
- .enable = enable_oaks32r_irq,
- .disable = disable_oaks32r_irq,
- .ack = mask_and_ack_mappi,
- .end = end_oaks32r_irq
+ .name = "OAKS32R-IRQ",
+ .irq_shutdown = shutdown_oaks32r,
+ .irq_mask = mask_oaks32r,
+ .irq_unmask = unmask_oaks32r,
};
void __init init_IRQ(void)
@@ -83,52 +74,40 @@ void __init init_IRQ(void)
#ifdef CONFIG_NE2000
/* INT3 : LAN controller (RTL8019AS) */
- irq_desc[M32R_IRQ_INT3].status = IRQ_DISABLED;
- irq_desc[M32R_IRQ_INT3].chip = &oaks32r_irq_type;
- irq_desc[M32R_IRQ_INT3].action = 0;
- irq_desc[M32R_IRQ_INT3].depth = 1;
+ set_irq_chip_and_handler(M32R_IRQ_INT3, &oaks32r_irq_type,
+ handle_level_irq);
icu_data[M32R_IRQ_INT3].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD10;
disable_oaks32r_irq(M32R_IRQ_INT3);
#endif /* CONFIG_M32R_NE2000 */
/* MFT2 : system timer */
- irq_desc[M32R_IRQ_MFT2].status = IRQ_DISABLED;
- irq_desc[M32R_IRQ_MFT2].chip = &oaks32r_irq_type;
- irq_desc[M32R_IRQ_MFT2].action = 0;
- irq_desc[M32R_IRQ_MFT2].depth = 1;
+ set_irq_chip_and_handler(M32R_IRQ_MFT2, &oaks32r_irq_type,
+ handle_level_irq);
icu_data[M32R_IRQ_MFT2].icucr = M32R_ICUCR_IEN;
disable_oaks32r_irq(M32R_IRQ_MFT2);
#ifdef CONFIG_SERIAL_M32R_SIO
/* SIO0_R : uart receive data */
- irq_desc[M32R_IRQ_SIO0_R].status = IRQ_DISABLED;
- irq_desc[M32R_IRQ_SIO0_R].chip = &oaks32r_irq_type;
- irq_desc[M32R_IRQ_SIO0_R].action = 0;
- irq_desc[M32R_IRQ_SIO0_R].depth = 1;
+ set_irq_chip_and_handler(M32R_IRQ_SIO0_R, &oaks32r_irq_type,
+ handle_level_irq);
icu_data[M32R_IRQ_SIO0_R].icucr = 0;
disable_oaks32r_irq(M32R_IRQ_SIO0_R);
/* SIO0_S : uart send data */
- irq_desc[M32R_IRQ_SIO0_S].status = IRQ_DISABLED;
- irq_desc[M32R_IRQ_SIO0_S].chip = &oaks32r_irq_type;
- irq_desc[M32R_IRQ_SIO0_S].action = 0;
- irq_desc[M32R_IRQ_SIO0_S].depth = 1;
+ set_irq_chip_and_handler(M32R_IRQ_SIO0_S, &oaks32r_irq_type,
+ handle_level_irq);
icu_data[M32R_IRQ_SIO0_S].icucr = 0;
disable_oaks32r_irq(M32R_IRQ_SIO0_S);
/* SIO1_R : uart receive data */
- irq_desc[M32R_IRQ_SIO1_R].status = IRQ_DISABLED;
- irq_desc[M32R_IRQ_SIO1_R].chip = &oaks32r_irq_type;
- irq_desc[M32R_IRQ_SIO1_R].action = 0;
- irq_desc[M32R_IRQ_SIO1_R].depth = 1;
+ set_irq_chip_and_handler(M32R_IRQ_SIO1_R, &oaks32r_irq_type,
+ handle_level_irq);
icu_data[M32R_IRQ_SIO1_R].icucr = 0;
disable_oaks32r_irq(M32R_IRQ_SIO1_R);
/* SIO1_S : uart send data */
- irq_desc[M32R_IRQ_SIO1_S].status = IRQ_DISABLED;
- irq_desc[M32R_IRQ_SIO1_S].chip = &oaks32r_irq_type;
- irq_desc[M32R_IRQ_SIO1_S].action = 0;
- irq_desc[M32R_IRQ_SIO1_S].depth = 1;
+ set_irq_chip_and_handler(M32R_IRQ_SIO1_S, &oaks32r_irq_type,
+ handle_level_irq);
icu_data[M32R_IRQ_SIO1_S].icucr = 0;
disable_oaks32r_irq(M32R_IRQ_SIO1_S);
#endif /* CONFIG_SERIAL_M32R_SIO */
diff --git a/arch/m32r/platforms/opsput/setup.c b/arch/m32r/platforms/opsput/setup.c
index 5f3402a..1273154 100644
--- a/arch/m32r/platforms/opsput/setup.c
+++ b/arch/m32r/platforms/opsput/setup.c
@@ -46,39 +46,30 @@ static void enable_opsput_irq(unsigned int irq)
outl(data, port);
}
-static void mask_and_ack_opsput(unsigned int irq)
+static void mask_opsput(struct irq_data *data)
{
- disable_opsput_irq(irq);
+ disable_opsput_irq(data->irq);
}
-static void end_opsput_irq(unsigned int irq)
+static void unmask_opsput(struct irq_data *data)
{
- enable_opsput_irq(irq);
+ enable_opsput_irq(data->irq);
}
-static unsigned int startup_opsput_irq(unsigned int irq)
-{
- enable_opsput_irq(irq);
- return (0);
-}
-
-static void shutdown_opsput_irq(unsigned int irq)
+static void shutdown_opsput(struct irq_data *data)
{
unsigned long port;
- port = irq2port(irq);
+ port = irq2port(data->irq);
outl(M32R_ICUCR_ILEVEL7, port);
}
static struct irq_chip opsput_irq_type =
{
- .name = "OPSPUT-IRQ",
- .startup = startup_opsput_irq,
- .shutdown = shutdown_opsput_irq,
- .enable = enable_opsput_irq,
- .disable = disable_opsput_irq,
- .ack = mask_and_ack_opsput,
- .end = end_opsput_irq
+ .name = "OPSPUT-IRQ",
+ .irq_shutdown = shutdown_opsput,
+ .irq_mask = mask_opsput,
+ .irq_unmask = unmask_opsput,
};
/*
@@ -100,7 +91,6 @@ static void disable_opsput_pld_irq(unsigned int irq)
unsigned int pldirq;
pldirq = irq2pldirq(irq);
-// disable_opsput_irq(M32R_IRQ_INT1);
port = pldirq2port(pldirq);
data = pld_icu_data[pldirq].icucr|PLD_ICUCR_ILEVEL7;
outw(data, port);
@@ -112,50 +102,38 @@ static void enable_opsput_pld_irq(unsigned int irq)
unsigned int pldirq;
pldirq = irq2pldirq(irq);
-// enable_opsput_irq(M32R_IRQ_INT1);
port = pldirq2port(pldirq);
data = pld_icu_data[pldirq].icucr|PLD_ICUCR_IEN|PLD_ICUCR_ILEVEL6;
outw(data, port);
}
-static void mask_and_ack_opsput_pld(unsigned int irq)
-{
- disable_opsput_pld_irq(irq);
-// mask_and_ack_opsput(M32R_IRQ_INT1);
-}
-
-static void end_opsput_pld_irq(unsigned int irq)
+static void mask_opsput_pld(struct irq_data *data)
{
- enable_opsput_pld_irq(irq);
- end_opsput_irq(M32R_IRQ_INT1);
+ disable_opsput_pld_irq(data->irq);
}
-static unsigned int startup_opsput_pld_irq(unsigned int irq)
+static void unmask_opsput_pld(struct irq_data *data)
{
- enable_opsput_pld_irq(irq);
- return (0);
+ enable_opsput_pld_irq(data->irq);
+ enable_opsput_irq(M32R_IRQ_INT1);
}
-static void shutdown_opsput_pld_irq(unsigned int irq)
+static void shutdown_opsput_pld(struct irq_data *data)
{
unsigned long port;
unsigned int pldirq;
- pldirq = irq2pldirq(irq);
-// shutdown_opsput_irq(M32R_IRQ_INT1);
+ pldirq = irq2pldirq(data->irq);
port = pldirq2port(pldirq);
outw(PLD_ICUCR_ILEVEL7, port);
}
static struct irq_chip opsput_pld_irq_type =
{
- .name = "OPSPUT-PLD-IRQ",
- .startup = startup_opsput_pld_irq,
- .shutdown = shutdown_opsput_pld_irq,
- .enable = enable_opsput_pld_irq,
- .disable = disable_opsput_pld_irq,
- .ack = mask_and_ack_opsput_pld,
- .end = end_opsput_pld_irq
+ .name = "OPSPUT-PLD-IRQ",
+ .irq_shutdown = shutdown_opsput_pld,
+ .irq_mask = mask_opsput_pld,
+ .irq_unmask = unmask_opsput_pld,
};
/*
@@ -189,42 +167,33 @@ static void enable_opsput_lanpld_irq(unsigned int irq)
outw(data, port);
}
-static void mask_and_ack_opsput_lanpld(unsigned int irq)
-{
- disable_opsput_lanpld_irq(irq);
-}
-
-static void end_opsput_lanpld_irq(unsigned int irq)
+static void mask_opsput_lanpld(struct irq_data *data)
{
- enable_opsput_lanpld_irq(irq);
- end_opsput_irq(M32R_IRQ_INT0);
+ disable_opsput_lanpld_irq(data->irq);
}
-static unsigned int startup_opsput_lanpld_irq(unsigned int irq)
+static void unmask_opsput_lanpld(struct irq_data *data)
{
- enable_opsput_lanpld_irq(irq);
- return (0);
+ enable_opsput_lanpld_irq(data->irq);
+ enable_opsput_irq(M32R_IRQ_INT0);
}
-static void shutdown_opsput_lanpld_irq(unsigned int irq)
+static void shutdown_opsput_lanpld(struct irq_data *data)
{
unsigned long port;
unsigned int pldirq;
- pldirq = irq2lanpldirq(irq);
+ pldirq = irq2lanpldirq(data->irq);
port = lanpldirq2port(pldirq);
outw(PLD_ICUCR_ILEVEL7, port);
}
static struct irq_chip opsput_lanpld_irq_type =
{
- .name = "OPSPUT-PLD-LAN-IRQ",
- .startup = startup_opsput_lanpld_irq,
- .shutdown = shutdown_opsput_lanpld_irq,
- .enable = enable_opsput_lanpld_irq,
- .disable = disable_opsput_lanpld_irq,
- .ack = mask_and_ack_opsput_lanpld,
- .end = end_opsput_lanpld_irq
+ .name = "OPSPUT-PLD-LAN-IRQ",
+ .irq_shutdown = shutdown_opsput_lanpld,
+ .irq_mask = mask_opsput_lanpld,
+ .irq_unmask = unmask_opsput_lanpld,
};
/*
@@ -258,143 +227,109 @@ static void enable_opsput_lcdpld_irq(unsigned int irq)
outw(data, port);
}
-static void mask_and_ack_opsput_lcdpld(unsigned int irq)
-{
- disable_opsput_lcdpld_irq(irq);
-}
-
-static void end_opsput_lcdpld_irq(unsigned int irq)
+static void mask_opsput_lcdpld(struct irq_data *data)
{
- enable_opsput_lcdpld_irq(irq);
- end_opsput_irq(M32R_IRQ_INT2);
+ disable_opsput_lcdpld_irq(data->irq);
}
-static unsigned int startup_opsput_lcdpld_irq(unsigned int irq)
+static void unmask_opsput_lcdpld(struct irq_data *data)
{
- enable_opsput_lcdpld_irq(irq);
- return (0);
+ enable_opsput_lcdpld_irq(data->irq);
+ enable_opsput_irq(M32R_IRQ_INT2);
}
-static void shutdown_opsput_lcdpld_irq(unsigned int irq)
+static void shutdown_opsput_lcdpld(struct irq_data *data)
{
unsigned long port;
unsigned int pldirq;
- pldirq = irq2lcdpldirq(irq);
+ pldirq = irq2lcdpldirq(data->irq);
port = lcdpldirq2port(pldirq);
outw(PLD_ICUCR_ILEVEL7, port);
}
-static struct irq_chip opsput_lcdpld_irq_type =
-{
- "OPSPUT-PLD-LCD-IRQ",
- startup_opsput_lcdpld_irq,
- shutdown_opsput_lcdpld_irq,
- enable_opsput_lcdpld_irq,
- disable_opsput_lcdpld_irq,
- mask_and_ack_opsput_lcdpld,
- end_opsput_lcdpld_irq
+static struct irq_chip opsput_lcdpld_irq_type = {
+ .name = "OPSPUT-PLD-LCD-IRQ",
+ .irq_shutdown = shutdown_opsput_lcdpld,
+ .irq_mask = mask_opsput_lcdpld,
+ .irq_unmask = unmask_opsput_lcdpld,
};
void __init init_IRQ(void)
{
#if defined(CONFIG_SMC91X)
/* INT#0: LAN controller on OPSPUT-LAN (SMC91C111)*/
- irq_desc[OPSPUT_LAN_IRQ_LAN].status = IRQ_DISABLED;
- irq_desc[OPSPUT_LAN_IRQ_LAN].chip = &opsput_lanpld_irq_type;
- irq_desc[OPSPUT_LAN_IRQ_LAN].action = 0;
- irq_desc[OPSPUT_LAN_IRQ_LAN].depth = 1; /* disable nested irq */
+ set_irq_chip_and_handler(OPSPUT_LAN_IRQ_LAN, &opsput_lanpld_irq_type,
+ handle_level_irq);
lanpld_icu_data[irq2lanpldirq(OPSPUT_LAN_IRQ_LAN)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD02; /* "H" edge sense */
disable_opsput_lanpld_irq(OPSPUT_LAN_IRQ_LAN);
#endif /* CONFIG_SMC91X */
/* MFT2 : system timer */
- irq_desc[M32R_IRQ_MFT2].status = IRQ_DISABLED;
- irq_desc[M32R_IRQ_MFT2].chip = &opsput_irq_type;
- irq_desc[M32R_IRQ_MFT2].action = 0;
- irq_desc[M32R_IRQ_MFT2].depth = 1;
+ set_irq_chip_and_handler(M32R_IRQ_MFT2, &opsput_irq_type,
+ handle_level_irq);
icu_data[M32R_IRQ_MFT2].icucr = M32R_ICUCR_IEN;
disable_opsput_irq(M32R_IRQ_MFT2);
/* SIO0 : receive */
- irq_desc[M32R_IRQ_SIO0_R].status = IRQ_DISABLED;
- irq_desc[M32R_IRQ_SIO0_R].chip = &opsput_irq_type;
- irq_desc[M32R_IRQ_SIO0_R].action = 0;
- irq_desc[M32R_IRQ_SIO0_R].depth = 1;
+ set_irq_chip_and_handler(M32R_IRQ_SIO0_R, &opsput_irq_type,
+ handle_level_irq);
icu_data[M32R_IRQ_SIO0_R].icucr = 0;
disable_opsput_irq(M32R_IRQ_SIO0_R);
/* SIO0 : send */
- irq_desc[M32R_IRQ_SIO0_S].status = IRQ_DISABLED;
- irq_desc[M32R_IRQ_SIO0_S].chip = &opsput_irq_type;
- irq_desc[M32R_IRQ_SIO0_S].action = 0;
- irq_desc[M32R_IRQ_SIO0_S].depth = 1;
+ set_irq_chip_and_handler(M32R_IRQ_SIO0_S, &opsput_irq_type,
+ handle_level_irq);
icu_data[M32R_IRQ_SIO0_S].icucr = 0;
disable_opsput_irq(M32R_IRQ_SIO0_S);
/* SIO1 : receive */
- irq_desc[M32R_IRQ_SIO1_R].status = IRQ_DISABLED;
- irq_desc[M32R_IRQ_SIO1_R].chip = &opsput_irq_type;
- irq_desc[M32R_IRQ_SIO1_R].action = 0;
- irq_desc[M32R_IRQ_SIO1_R].depth = 1;
+ set_irq_chip_and_handler(M32R_IRQ_SIO1_R, &opsput_irq_type,
+ handle_level_irq);
icu_data[M32R_IRQ_SIO1_R].icucr = 0;
disable_opsput_irq(M32R_IRQ_SIO1_R);
/* SIO1 : send */
- irq_desc[M32R_IRQ_SIO1_S].status = IRQ_DISABLED;
- irq_desc[M32R_IRQ_SIO1_S].chip = &opsput_irq_type;
- irq_desc[M32R_IRQ_SIO1_S].action = 0;
- irq_desc[M32R_IRQ_SIO1_S].depth = 1;
+ set_irq_chip_and_handler(M32R_IRQ_SIO1_S, &opsput_irq_type,
+ handle_level_irq);
icu_data[M32R_IRQ_SIO1_S].icucr = 0;
disable_opsput_irq(M32R_IRQ_SIO1_S);
/* DMA1 : */
- irq_desc[M32R_IRQ_DMA1].status = IRQ_DISABLED;
- irq_desc[M32R_IRQ_DMA1].chip = &opsput_irq_type;
- irq_desc[M32R_IRQ_DMA1].action = 0;
- irq_desc[M32R_IRQ_DMA1].depth = 1;
+ set_irq_chip_and_handler(M32R_IRQ_DMA1, &opsput_irq_type,
+ handle_level_irq);
icu_data[M32R_IRQ_DMA1].icucr = 0;
disable_opsput_irq(M32R_IRQ_DMA1);
#ifdef CONFIG_SERIAL_M32R_PLDSIO
/* INT#1: SIO0 Receive on PLD */
- irq_desc[PLD_IRQ_SIO0_RCV].status = IRQ_DISABLED;
- irq_desc[PLD_IRQ_SIO0_RCV].chip = &opsput_pld_irq_type;
- irq_desc[PLD_IRQ_SIO0_RCV].action = 0;
- irq_desc[PLD_IRQ_SIO0_RCV].depth = 1; /* disable nested irq */
+ set_irq_chip_and_handler(PLD_IRQ_SIO0_RCV, &opsput_pld_irq_type,
+ handle_level_irq);
pld_icu_data[irq2pldirq(PLD_IRQ_SIO0_RCV)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD03;
disable_opsput_pld_irq(PLD_IRQ_SIO0_RCV);
/* INT#1: SIO0 Send on PLD */
- irq_desc[PLD_IRQ_SIO0_SND].status = IRQ_DISABLED;
- irq_desc[PLD_IRQ_SIO0_SND].chip = &opsput_pld_irq_type;
- irq_desc[PLD_IRQ_SIO0_SND].action = 0;
- irq_desc[PLD_IRQ_SIO0_SND].depth = 1; /* disable nested irq */
+ set_irq_chip_and_handler(PLD_IRQ_SIO0_SND, &opsput_pld_irq_type,
+ handle_level_irq);
pld_icu_data[irq2pldirq(PLD_IRQ_SIO0_SND)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD03;
disable_opsput_pld_irq(PLD_IRQ_SIO0_SND);
#endif /* CONFIG_SERIAL_M32R_PLDSIO */
/* INT#1: CFC IREQ on PLD */
- irq_desc[PLD_IRQ_CFIREQ].status = IRQ_DISABLED;
- irq_desc[PLD_IRQ_CFIREQ].chip = &opsput_pld_irq_type;
- irq_desc[PLD_IRQ_CFIREQ].action = 0;
- irq_desc[PLD_IRQ_CFIREQ].depth = 1; /* disable nested irq */
+ set_irq_chip_and_handler(PLD_IRQ_CFIREQ, &opsput_pld_irq_type,
+ handle_level_irq);
pld_icu_data[irq2pldirq(PLD_IRQ_CFIREQ)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD01; /* 'L' level sense */
disable_opsput_pld_irq(PLD_IRQ_CFIREQ);
/* INT#1: CFC Insert on PLD */
- irq_desc[PLD_IRQ_CFC_INSERT].status = IRQ_DISABLED;
- irq_desc[PLD_IRQ_CFC_INSERT].chip = &opsput_pld_irq_type;
- irq_desc[PLD_IRQ_CFC_INSERT].action = 0;
- irq_desc[PLD_IRQ_CFC_INSERT].depth = 1; /* disable nested irq */
+ set_irq_chip_and_handler(PLD_IRQ_CFC_INSERT, &opsput_pld_irq_type,
+ handle_level_irq);
pld_icu_data[irq2pldirq(PLD_IRQ_CFC_INSERT)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD00; /* 'L' edge sense */
disable_opsput_pld_irq(PLD_IRQ_CFC_INSERT);
/* INT#1: CFC Eject on PLD */
- irq_desc[PLD_IRQ_CFC_EJECT].status = IRQ_DISABLED;
- irq_desc[PLD_IRQ_CFC_EJECT].chip = &opsput_pld_irq_type;
- irq_desc[PLD_IRQ_CFC_EJECT].action = 0;
- irq_desc[PLD_IRQ_CFC_EJECT].depth = 1; /* disable nested irq */
+ set_irq_chip_and_handler(PLD_IRQ_CFC_EJECT, &opsput_pld_irq_type,
+ handle_level_irq);
pld_icu_data[irq2pldirq(PLD_IRQ_CFC_EJECT)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD02; /* 'H' edge sense */
disable_opsput_pld_irq(PLD_IRQ_CFC_EJECT);
@@ -413,14 +348,11 @@ void __init init_IRQ(void)
enable_opsput_irq(M32R_IRQ_INT1);
#if defined(CONFIG_USB)
- outw(USBCR_OTGS, USBCR); /* USBCR: non-OTG */
-
- irq_desc[OPSPUT_LCD_IRQ_USB_INT1].status = IRQ_DISABLED;
- irq_desc[OPSPUT_LCD_IRQ_USB_INT1].chip = &opsput_lcdpld_irq_type;
- irq_desc[OPSPUT_LCD_IRQ_USB_INT1].action = 0;
- irq_desc[OPSPUT_LCD_IRQ_USB_INT1].depth = 1;
- lcdpld_icu_data[irq2lcdpldirq(OPSPUT_LCD_IRQ_USB_INT1)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD01; /* "L" level sense */
- disable_opsput_lcdpld_irq(OPSPUT_LCD_IRQ_USB_INT1);
+ outw(USBCR_OTGS, USBCR); /* USBCR: non-OTG */
+ set_irq_chip_and_handler(OPSPUT_LCD_IRQ_USB_INT1,
+ &opsput_lcdpld_irq_type, handle_level_irq);
+ lcdpld_icu_data[irq2lcdpldirq(OPSPUT_LCD_IRQ_USB_INT1)].icucr = PLD_ICUCR_IEN|PLD_ICUCR_ISMOD01; /* "L" level sense */
+ disable_opsput_lcdpld_irq(OPSPUT_LCD_IRQ_USB_INT1);
#endif
/*
* INT2# is used for BAT, USB, AUDIO
@@ -433,10 +365,8 @@ void __init init_IRQ(void)
/*
* INT3# is used for AR
*/
- irq_desc[M32R_IRQ_INT3].status = IRQ_DISABLED;
- irq_desc[M32R_IRQ_INT3].chip = &opsput_irq_type;
- irq_desc[M32R_IRQ_INT3].action = 0;
- irq_desc[M32R_IRQ_INT3].depth = 1;
+ set_irq_chip_and_handler(M32R_IRQ_INT3, &opsput_irq_type,
+ handle_level_irq);
icu_data[M32R_IRQ_INT3].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD10;
disable_opsput_irq(M32R_IRQ_INT3);
#endif /* CONFIG_VIDEO_M32R_AR */
diff --git a/arch/m32r/platforms/usrv/setup.c b/arch/m32r/platforms/usrv/setup.c
index 1beac7a..f3cff26 100644
--- a/arch/m32r/platforms/usrv/setup.c
+++ b/arch/m32r/platforms/usrv/setup.c
@@ -37,39 +37,30 @@ static void enable_mappi_irq(unsigned int irq)
outl(data, port);
}
-static void mask_and_ack_mappi(unsigned int irq)
+static void mask_mappi(struct irq_data *data)
{
- disable_mappi_irq(irq);
+ disable_mappi_irq(data->irq);
}
-static void end_mappi_irq(unsigned int irq)
+static void unmask_mappi(struct irq_data *data)
{
- enable_mappi_irq(irq);
+ enable_mappi_irq(data->irq);
}
-static unsigned int startup_mappi_irq(unsigned int irq)
-{
- enable_mappi_irq(irq);
- return 0;
-}
-
-static void shutdown_mappi_irq(unsigned int irq)
+static void shutdown_mappi(struct irq_data *data)
{
unsigned long port;
- port = irq2port(irq);
+ port = irq2port(data->irq);
outl(M32R_ICUCR_ILEVEL7, port);
}
static struct irq_chip mappi_irq_type =
{
- .name = "M32700-IRQ",
- .startup = startup_mappi_irq,
- .shutdown = shutdown_mappi_irq,
- .enable = enable_mappi_irq,
- .disable = disable_mappi_irq,
- .ack = mask_and_ack_mappi,
- .end = end_mappi_irq
+ .name = "M32700-IRQ",
+ .irq_shutdown = shutdown_mappi,
+ .irq_mask = mask_mappi,
+ .irq_unmask = unmask_mappi,
};
/*
@@ -107,42 +98,33 @@ static void enable_m32700ut_pld_irq(unsigned int irq)
outw(data, port);
}
-static void mask_and_ack_m32700ut_pld(unsigned int irq)
+static void mask_m32700ut_pld(struct irq_data *data)
{
- disable_m32700ut_pld_irq(irq);
+ disable_m32700ut_pld_irq(data->irq);
}
-static void end_m32700ut_pld_irq(unsigned int irq)
+static void unmask_m32700ut_pld(struct irq_data *data)
{
- enable_m32700ut_pld_irq(irq);
- end_mappi_irq(M32R_IRQ_INT1);
-}
-
-static unsigned int startup_m32700ut_pld_irq(unsigned int irq)
-{
- enable_m32700ut_pld_irq(irq);
- return 0;
+ enable_m32700ut_pld_irq(data->irq);
+ enable_mappi_irq(M32R_IRQ_INT1);
}
-static void shutdown_m32700ut_pld_irq(unsigned int irq)
+static void shutdown_m32700ut_pld(struct irq_data *data)
{
unsigned long port;
unsigned int pldirq;
- pldirq = irq2pldirq(irq);
+ pldirq = irq2pldirq(data->irq);
port = pldirq2port(pldirq);
outw(PLD_ICUCR_ILEVEL7, port);
}
static struct irq_chip m32700ut_pld_irq_type =
{
- .name = "USRV-PLD-IRQ",
- .startup = startup_m32700ut_pld_irq,
- .shutdown = shutdown_m32700ut_pld_irq,
- .enable = enable_m32700ut_pld_irq,
- .disable = disable_m32700ut_pld_irq,
- .ack = mask_and_ack_m32700ut_pld,
- .end = end_m32700ut_pld_irq
+ .name = "USRV-PLD-IRQ",
+ .irq_shutdown = shutdown_m32700ut_pld,
+ .irq_mask = mask_m32700ut_pld,
+ .irq_unmask = unmask_m32700ut_pld,
};
void __init init_IRQ(void)
@@ -156,53 +138,42 @@ void __init init_IRQ(void)
once++;
/* MFT2 : system timer */
- irq_desc[M32R_IRQ_MFT2].status = IRQ_DISABLED;
- irq_desc[M32R_IRQ_MFT2].chip = &mappi_irq_type;
- irq_desc[M32R_IRQ_MFT2].action = 0;
- irq_desc[M32R_IRQ_MFT2].depth = 1;
+ set_irq_chip_and_handler(M32R_IRQ_MFT2, &mappi_irq_type,
+ handle_level_irq);
icu_data[M32R_IRQ_MFT2].icucr = M32R_ICUCR_IEN;
disable_mappi_irq(M32R_IRQ_MFT2);
#if defined(CONFIG_SERIAL_M32R_SIO)
/* SIO0_R : uart receive data */
- irq_desc[M32R_IRQ_SIO0_R].status = IRQ_DISABLED;
- irq_desc[M32R_IRQ_SIO0_R].chip = &mappi_irq_type;
- irq_desc[M32R_IRQ_SIO0_R].action = 0;
- irq_desc[M32R_IRQ_SIO0_R].depth = 1;
+ set_irq_chip_and_handler(M32R_IRQ_SIO0_R, &mappi_irq_type,
+ handle_level_irq);
icu_data[M32R_IRQ_SIO0_R].icucr = 0;
disable_mappi_irq(M32R_IRQ_SIO0_R);
/* SIO0_S : uart send data */
- irq_desc[M32R_IRQ_SIO0_S].status = IRQ_DISABLED;
- irq_desc[M32R_IRQ_SIO0_S].chip = &mappi_irq_type;
- irq_desc[M32R_IRQ_SIO0_S].action = 0;
- irq_desc[M32R_IRQ_SIO0_S].depth = 1;
+ set_irq_chip_and_handler(M32R_IRQ_SIO0_S, &mappi_irq_type,
+ handle_level_irq);
icu_data[M32R_IRQ_SIO0_S].icucr = 0;
disable_mappi_irq(M32R_IRQ_SIO0_S);
/* SIO1_R : uart receive data */
- irq_desc[M32R_IRQ_SIO1_R].status = IRQ_DISABLED;
- irq_desc[M32R_IRQ_SIO1_R].chip = &mappi_irq_type;
- irq_desc[M32R_IRQ_SIO1_R].action = 0;
- irq_desc[M32R_IRQ_SIO1_R].depth = 1;
+ set_irq_chip_and_handler(M32R_IRQ_SIO1_R, &mappi_irq_type,
+ handle_level_irq);
icu_data[M32R_IRQ_SIO1_R].icucr = 0;
disable_mappi_irq(M32R_IRQ_SIO1_R);
/* SIO1_S : uart send data */
- irq_desc[M32R_IRQ_SIO1_S].status = IRQ_DISABLED;
- irq_desc[M32R_IRQ_SIO1_S].chip = &mappi_irq_type;
- irq_desc[M32R_IRQ_SIO1_S].action = 0;
- irq_desc[M32R_IRQ_SIO1_S].depth = 1;
+ set_irq_chip_and_handler(M32R_IRQ_SIO1_S, &mappi_irq_type,
+ handle_level_irq);
icu_data[M32R_IRQ_SIO1_S].icucr = 0;
disable_mappi_irq(M32R_IRQ_SIO1_S);
#endif /* CONFIG_SERIAL_M32R_SIO */
/* INT#67-#71: CFC#0 IREQ on PLD */
for (i = 0 ; i < CONFIG_M32R_CFC_NUM ; i++ ) {
- irq_desc[PLD_IRQ_CF0 + i].status = IRQ_DISABLED;
- irq_desc[PLD_IRQ_CF0 + i].chip = &m32700ut_pld_irq_type;
- irq_desc[PLD_IRQ_CF0 + i].action = 0;
- irq_desc[PLD_IRQ_CF0 + i].depth = 1; /* disable nested irq */
+ set_irq_chip_and_handler(PLD_IRQ_CF0 + i,
+ &m32700ut_pld_irq_type,
+ handle_level_irq);
pld_icu_data[irq2pldirq(PLD_IRQ_CF0 + i)].icucr
= PLD_ICUCR_ISMOD01; /* 'L' level sense */
disable_m32700ut_pld_irq(PLD_IRQ_CF0 + i);
@@ -210,19 +181,15 @@ void __init init_IRQ(void)
#if defined(CONFIG_SERIAL_8250) || defined(CONFIG_SERIAL_8250_MODULE)
/* INT#76: 16552D#0 IREQ on PLD */
- irq_desc[PLD_IRQ_UART0].status = IRQ_DISABLED;
- irq_desc[PLD_IRQ_UART0].chip = &m32700ut_pld_irq_type;
- irq_desc[PLD_IRQ_UART0].action = 0;
- irq_desc[PLD_IRQ_UART0].depth = 1; /* disable nested irq */
+ set_irq_chip_and_handler(PLD_IRQ_UART0, &m32700ut_pld_irq_type,
+ handle_level_irq);
pld_icu_data[irq2pldirq(PLD_IRQ_UART0)].icucr
= PLD_ICUCR_ISMOD03; /* 'H' level sense */
disable_m32700ut_pld_irq(PLD_IRQ_UART0);
/* INT#77: 16552D#1 IREQ on PLD */
- irq_desc[PLD_IRQ_UART1].status = IRQ_DISABLED;
- irq_desc[PLD_IRQ_UART1].chip = &m32700ut_pld_irq_type;
- irq_desc[PLD_IRQ_UART1].action = 0;
- irq_desc[PLD_IRQ_UART1].depth = 1; /* disable nested irq */
+ set_irq_chip_and_handler(PLD_IRQ_UART1, &m32700ut_pld_irq_type,
+ handle_level_irq);
pld_icu_data[irq2pldirq(PLD_IRQ_UART1)].icucr
= PLD_ICUCR_ISMOD03; /* 'H' level sense */
disable_m32700ut_pld_irq(PLD_IRQ_UART1);
@@ -230,10 +197,8 @@ void __init init_IRQ(void)
#if defined(CONFIG_IDC_AK4524) || defined(CONFIG_IDC_AK4524_MODULE)
/* INT#80: AK4524 IREQ on PLD */
- irq_desc[PLD_IRQ_SNDINT].status = IRQ_DISABLED;
- irq_desc[PLD_IRQ_SNDINT].chip = &m32700ut_pld_irq_type;
- irq_desc[PLD_IRQ_SNDINT].action = 0;
- irq_desc[PLD_IRQ_SNDINT].depth = 1; /* disable nested irq */
+ set_irq_chip_and_handler(PLD_IRQ_SNDINT, &m32700ut_pld_irq_type,
+ handle_level_irq);
pld_icu_data[irq2pldirq(PLD_IRQ_SNDINT)].icucr
= PLD_ICUCR_ISMOD01; /* 'L' level sense */
disable_m32700ut_pld_irq(PLD_IRQ_SNDINT);
diff --git a/arch/m68k/include/asm/cacheflush_no.h b/arch/m68k/include/asm/cacheflush_no.h
index 7085bd5..cb88aa9 100644
--- a/arch/m68k/include/asm/cacheflush_no.h
+++ b/arch/m68k/include/asm/cacheflush_no.h
@@ -2,21 +2,22 @@
#define _M68KNOMMU_CACHEFLUSH_H
/*
- * (C) Copyright 2000-2004, Greg Ungerer <gerg@snapgear.com>
+ * (C) Copyright 2000-2010, Greg Ungerer <gerg@snapgear.com>
*/
#include <linux/mm.h>
+#include <asm/mcfsim.h>
#define flush_cache_all() __flush_cache_all()
#define flush_cache_mm(mm) do { } while (0)
#define flush_cache_dup_mm(mm) do { } while (0)
-#define flush_cache_range(vma, start, end) __flush_cache_all()
+#define flush_cache_range(vma, start, end) do { } while (0)
#define flush_cache_page(vma, vmaddr) do { } while (0)
-#define flush_dcache_range(start,len) __flush_cache_all()
+#define flush_dcache_range(start, len) __flush_dcache_all()
#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0
#define flush_dcache_page(page) do { } while (0)
#define flush_dcache_mmap_lock(mapping) do { } while (0)
#define flush_dcache_mmap_unlock(mapping) do { } while (0)
-#define flush_icache_range(start,len) __flush_cache_all()
+#define flush_icache_range(start, len) __flush_icache_all()
#define flush_icache_page(vma,pg) do { } while (0)
#define flush_icache_user_range(vma,pg,adr,len) do { } while (0)
#define flush_cache_vmap(start, end) do { } while (0)
@@ -27,66 +28,52 @@
#define copy_from_user_page(vma, page, vaddr, dst, src, len) \
memcpy(dst, src, len)
+void mcf_cache_push(void);
+
static inline void __flush_cache_all(void)
{
-#if defined(CONFIG_M5407) || defined(CONFIG_M548x)
- /*
- * Use cpushl to push and invalidate all cache lines.
- * Gas doesn't seem to know how to generate the ColdFire
- * cpushl instruction... Oh well, bit stuff it for now.
- */
- __asm__ __volatile__ (
- "nop\n\t"
- "clrl %%d0\n\t"
- "1:\n\t"
- "movel %%d0,%%a0\n\t"
- "2:\n\t"
- ".word 0xf468\n\t"
- "addl #0x10,%%a0\n\t"
- "cmpl #0x00000800,%%a0\n\t"
- "blt 2b\n\t"
- "addql #1,%%d0\n\t"
- "cmpil #4,%%d0\n\t"
- "bne 1b\n\t"
- "movel #0xb6088500,%%d0\n\t"
- "movec %%d0,%%CACR\n\t"
- : : : "d0", "a0" );
-#endif /* CONFIG_M5407 */
-#if defined(CONFIG_M523x) || defined(CONFIG_M527x)
- __asm__ __volatile__ (
- "movel #0x81400100, %%d0\n\t"
- "movec %%d0, %%CACR\n\t"
- "nop\n\t"
- : : : "d0" );
-#endif /* CONFIG_M523x || CONFIG_M527x */
-#if defined(CONFIG_M528x)
- __asm__ __volatile__ (
- "movel #0x81000200, %%d0\n\t"
- "movec %%d0, %%CACR\n\t"
- "nop\n\t"
- : : : "d0" );
-#endif /* CONFIG_M528x */
-#if defined(CONFIG_M5206) || defined(CONFIG_M5206e) || defined(CONFIG_M5272)
+#ifdef CACHE_PUSH
+ mcf_cache_push();
+#endif
+#ifdef CACHE_INVALIDATE
__asm__ __volatile__ (
- "movel #0x81000100, %%d0\n\t"
+ "movel %0, %%d0\n\t"
"movec %%d0, %%CACR\n\t"
"nop\n\t"
- : : : "d0" );
-#endif /* CONFIG_M5206 || CONFIG_M5206e || CONFIG_M5272 */
-#ifdef CONFIG_M5249
+ : : "i" (CACHE_INVALIDATE) : "d0" );
+#endif
+}
+
+/*
+ * Some ColdFire parts implement separate instruction and data caches,
+ * on those we should just flush the appropriate cache. If we don't need
+ * to do any specific flushing then this will be optimized away.
+ */
+static inline void __flush_icache_all(void)
+{
+#ifdef CACHE_INVALIDATEI
__asm__ __volatile__ (
- "movel #0xa1000200, %%d0\n\t"
+ "movel %0, %%d0\n\t"
"movec %%d0, %%CACR\n\t"
"nop\n\t"
- : : : "d0" );
-#endif /* CONFIG_M5249 */
-#ifdef CONFIG_M532x
+ : : "i" (CACHE_INVALIDATEI) : "d0" );
+#endif
+}
+
+static inline void __flush_dcache_all(void)
+{
+#ifdef CACHE_PUSH
+ mcf_cache_push();
+#endif
+#ifdef CACHE_INVALIDATED
__asm__ __volatile__ (
- "movel #0x81000200, %%d0\n\t"
+ "movel %0, %%d0\n\t"
"movec %%d0, %%CACR\n\t"
"nop\n\t"
- : : : "d0" );
-#endif /* CONFIG_M532x */
+ : : "i" (CACHE_INVALIDATED) : "d0" );
+#else
+ /* Flush the wrtite buffer */
+ __asm__ __volatile__ ( "nop" );
+#endif
}
-
#endif /* _M68KNOMMU_CACHEFLUSH_H */
diff --git a/arch/m68k/include/asm/coldfire.h b/arch/m68k/include/asm/coldfire.h
index 3b0a34d..213028c 100644
--- a/arch/m68k/include/asm/coldfire.h
+++ b/arch/m68k/include/asm/coldfire.h
@@ -32,7 +32,7 @@
*/
#define MCF_MBAR 0x10000000
#define MCF_MBAR2 0x80000000
-#if defined(CONFIG_M548x)
+#if defined(CONFIG_M54xx)
#define MCF_IPSBAR MCF_MBAR
#elif defined(CONFIG_M520x)
#define MCF_IPSBAR 0xFC000000
diff --git a/arch/m68k/include/asm/entry_no.h b/arch/m68k/include/asm/entry_no.h
index 26be277..627d69b 100644
--- a/arch/m68k/include/asm/entry_no.h
+++ b/arch/m68k/include/asm/entry_no.h
@@ -42,12 +42,16 @@
*/
#ifdef CONFIG_COLDFIRE
+#ifdef CONFIG_COLDFIRE_SW_A7
/*
- * This is made a little more tricky on the ColdFire. There is no
- * separate kernel and user stack pointers. Need to artificially
+ * This is made a little more tricky on older ColdFires. There is no
+ * separate supervisor and user stack pointers. Need to artificially
* construct a usp in software... When doing this we need to disable
- * interrupts, otherwise bad things could happen.
+ * interrupts, otherwise bad things will happen.
*/
+.globl sw_usp
+.globl sw_ksp
+
.macro SAVE_ALL
move #0x2700,%sr /* disable intrs */
btst #5,%sp@(2) /* from user? */
@@ -74,9 +78,7 @@
7:
.endm
-.macro RESTORE_ALL
- btst #5,%sp@(PT_SR) /* going user? */
- bnes 8f /* no, skip */
+.macro RESTORE_USER
move #0x2700,%sr /* disable intrs */
movel sw_usp,%a0 /* get usp */
movel %sp@(PT_OFF_PC),%a0@- /* copy exception program counter */
@@ -91,19 +93,22 @@
subql #8,sw_usp /* set exception */
movel sw_usp,%sp /* restore usp */
rte
- 8:
- moveml %sp@,%d1-%d5/%a0-%a2
- lea %sp@(32),%sp /* space for 8 regs */
- movel %sp@+,%d0
- addql #4,%sp /* orig d0 */
- addl %sp@+,%sp /* stkadj */
- rte
.endm
+.macro RDUSP
+ movel sw_usp,%a2
+.endm
+
+.macro WRUSP
+ movel %a0,sw_usp
+.endm
+
+#else /* !CONFIG_COLDFIRE_SW_A7 */
/*
- * Quick exception save, use current stack only.
+ * Modern ColdFire parts have separate supervisor and user stack
+ * pointers. Simple load and restore macros for this case.
*/
-.macro SAVE_LOCAL
+.macro SAVE_ALL
move #0x2700,%sr /* disable intrs */
clrl %sp@- /* stkadj */
movel %d0,%sp@- /* orig d0 */
@@ -112,7 +117,7 @@
moveml %d1-%d5/%a0-%a2,%sp@
.endm
-.macro RESTORE_LOCAL
+.macro RESTORE_USER
moveml %sp@,%d1-%d5/%a0-%a2
lea %sp@(32),%sp /* space for 8 regs */
movel %sp@+,%d0
@@ -121,6 +126,18 @@
rte
.endm
+.macro RDUSP
+ /*move %usp,%a2*/
+ .word 0x4e6a
+.endm
+
+.macro WRUSP
+ /*move %a0,%usp*/
+ .word 0x4e60
+.endm
+
+#endif /* !CONFIG_COLDFIRE_SW_A7 */
+
.macro SAVE_SWITCH_STACK
lea %sp@(-24),%sp /* 6 regs */
moveml %a3-%a6/%d6-%d7,%sp@
@@ -131,14 +148,6 @@
lea %sp@(24),%sp /* 6 regs */
.endm
-/*
- * Software copy of the user and kernel stack pointers... Ugh...
- * Need these to get around ColdFire not having separate kernel
- * and user stack pointers.
- */
-.globl sw_usp
-.globl sw_ksp
-
#else /* !CONFIG_COLDFIRE */
/*
@@ -167,6 +176,6 @@
moveml %sp@+,%a3-%a6/%d6-%d7
.endm
-#endif /* !CONFIG_COLDFIRE */
+#endif /* !COLDFIRE_SW_A7 */
#endif /* __ASSEMBLY__ */
#endif /* __M68KNOMMU_ENTRY_H */
diff --git a/arch/m68k/include/asm/gpio.h b/arch/m68k/include/asm/gpio.h
index 1b57adb..c64c7b7 100644
--- a/arch/m68k/include/asm/gpio.h
+++ b/arch/m68k/include/asm/gpio.h
@@ -37,7 +37,7 @@
#if defined(CONFIG_M5206) || defined(CONFIG_M5206e) || \
defined(CONFIG_M520x) || defined(CONFIG_M523x) || \
defined(CONFIG_M527x) || defined(CONFIG_M528x) || \
- defined(CONFIG_M532x) || defined(CONFIG_M548x)
+ defined(CONFIG_M532x) || defined(CONFIG_M54xx)
/* These parts have GPIO organized by 8 bit ports */
diff --git a/arch/m68k/include/asm/io_no.h b/arch/m68k/include/asm/io_no.h
index 6e2413e..cf20f30 100644
--- a/arch/m68k/include/asm/io_no.h
+++ b/arch/m68k/include/asm/io_no.h
@@ -145,7 +145,6 @@ static inline void io_insl(unsigned int addr, void *buf, int len)
#define IOMAP_WRITETHROUGH 3
extern void *__ioremap(unsigned long physaddr, unsigned long size, int cacheflag);
-extern void __iounmap(void *addr, unsigned long size);
static inline void *ioremap(unsigned long physaddr, unsigned long size)
{
diff --git a/arch/m68k/include/asm/m5206sim.h b/arch/m68k/include/asm/m5206sim.h
index 9c384e2..561b03b5 100644
--- a/arch/m68k/include/asm/m5206sim.h
+++ b/arch/m68k/include/asm/m5206sim.h
@@ -12,6 +12,10 @@
#define m5206sim_h
/****************************************************************************/
+#define CPU_NAME "COLDFIRE(m5206)"
+#define CPU_INSTR_PER_JIFFY 3
+
+#include <asm/m52xxacr.h>
/*
* Define the 5206 SIM register set addresses.
@@ -88,6 +92,14 @@
#define MCFSIM_PADDR (MCF_MBAR + 0x1c5) /* Parallel Direction (r/w) */
#define MCFSIM_PADAT (MCF_MBAR + 0x1c9) /* Parallel Port Value (r/w) */
+#if defined(CONFIG_NETtel)
+#define MCFUART_BASE1 0x180 /* Base address of UART1 */
+#define MCFUART_BASE2 0x140 /* Base address of UART2 */
+#else
+#define MCFUART_BASE1 0x140 /* Base address of UART1 */
+#define MCFUART_BASE2 0x180 /* Base address of UART2 */
+#endif
+
/*
* Define system peripheral IRQ usage.
*/
@@ -95,7 +107,7 @@
#define MCF_IRQ_PROFILER 31 /* Timer1, Level 7 */
/*
- * Generic GPIO
+ * Generic GPIO
*/
#define MCFGPIO_PIN_MAX 8
#define MCFGPIO_IRQ_VECBASE -1
diff --git a/arch/m68k/include/asm/m520xsim.h b/arch/m68k/include/asm/m520xsim.h
index db824a4..88ed823 100644
--- a/arch/m68k/include/asm/m520xsim.h
+++ b/arch/m68k/include/asm/m520xsim.h
@@ -11,6 +11,11 @@
#define m520xsim_h
/****************************************************************************/
+#define CPU_NAME "COLDFIRE(m520x)"
+#define CPU_INSTR_PER_JIFFY 3
+
+#include <asm/m52xxacr.h>
+
/*
* Define the 520x SIM register set addresses.
*/
@@ -54,6 +59,9 @@
#define MCFSIM_SDCS0 0x000a8110 /* SDRAM Chip Select 0 Configuration */
#define MCFSIM_SDCS1 0x000a8114 /* SDRAM Chip Select 1 Configuration */
+/*
+ * EPORT and GPIO registers.
+ */
#define MCFEPORT_EPDDR 0xFC088002
#define MCFEPORT_EPDR 0xFC088004
#define MCFEPORT_EPPDR 0xFC088005
@@ -97,6 +105,7 @@
#define MCFGPIO_PCLRR_UART 0xFC0A402A
#define MCFGPIO_PCLRR_FECH 0xFC0A402B
#define MCFGPIO_PCLRR_FECL 0xFC0A402C
+
/*
* Generic GPIO support
*/
@@ -109,7 +118,6 @@
#define MCFGPIO_PIN_MAX 80
#define MCFGPIO_IRQ_MAX 8
#define MCFGPIO_IRQ_VECBASE MCFINT_VECBASE
-/****************************************************************************/
#define MCF_GPIO_PAR_UART (0xA4036)
#define MCF_GPIO_PAR_FECI2C (0xA4033)
@@ -126,6 +134,13 @@
#define MCF_GPIO_PAR_FECI2C_PAR_SCL_UTXD2 (0x04)
/*
+ * UART module.
+ */
+#define MCFUART_BASE1 0x60000 /* Base address of UART1 */
+#define MCFUART_BASE2 0x64000 /* Base address of UART2 */
+#define MCFUART_BASE3 0x68000 /* Base address of UART2 */
+
+/*
* Reset Controll Unit.
*/
#define MCF_RCR 0xFC0A0000
diff --git a/arch/m68k/include/asm/m523xsim.h b/arch/m68k/include/asm/m523xsim.h
index e8d06b2..4ad7a00 100644
--- a/arch/m68k/include/asm/m523xsim.h
+++ b/arch/m68k/include/asm/m523xsim.h
@@ -11,6 +11,10 @@
#define m523xsim_h
/****************************************************************************/
+#define CPU_NAME "COLDFIRE(m523x)"
+#define CPU_INSTR_PER_JIFFY 3
+
+#include <asm/m52xxacr.h>
/*
* Define the 523x SIM register set addresses.
@@ -50,6 +54,13 @@
#define MCF_RCR_SWRESET 0x80 /* Software reset bit */
#define MCF_RCR_FRCSTOUT 0x40 /* Force external reset */
+/*
+ * UART module.
+ */
+#define MCFUART_BASE1 0x200 /* Base address of UART1 */
+#define MCFUART_BASE2 0x240 /* Base address of UART2 */
+#define MCFUART_BASE3 0x280 /* Base address of UART3 */
+
#define MCFGPIO_PODR_ADDR (MCF_IPSBAR + 0x100000)
#define MCFGPIO_PODR_DATAH (MCF_IPSBAR + 0x100001)
#define MCFGPIO_PODR_DATAL (MCF_IPSBAR + 0x100002)
diff --git a/arch/m68k/include/asm/m5249sim.h b/arch/m68k/include/asm/m5249sim.h
index 79b7b40..4908b11 100644
--- a/arch/m68k/include/asm/m5249sim.h
+++ b/arch/m68k/include/asm/m5249sim.h
@@ -11,6 +11,11 @@
#define m5249sim_h
/****************************************************************************/
+#define CPU_NAME "COLDFIRE(m5249)"
+#define CPU_INSTR_PER_JIFFY 3
+
+#include <asm/m52xxacr.h>
+
/*
* Define the 5249 SIM register set addresses.
*/
@@ -56,6 +61,11 @@
#define MCFSIM_DACR1 0x110 /* DRAM 1 Addr and Ctrl (r/w) */
#define MCFSIM_DMR1 0x114 /* DRAM 1 Mask reg (r/w) */
+/*
+ * UART module.
+ */
+#define MCFUART_BASE1 0x1c0 /* Base address of UART1 */
+#define MCFUART_BASE2 0x200 /* Base address of UART2 */
/*
* Some symbol defines for the above...
diff --git a/arch/m68k/include/asm/m5272sim.h b/arch/m68k/include/asm/m5272sim.h
index df3332c..b7cc50a 100644
--- a/arch/m68k/include/asm/m5272sim.h
+++ b/arch/m68k/include/asm/m5272sim.h
@@ -12,6 +12,11 @@
#define m5272sim_h
/****************************************************************************/
+#define CPU_NAME "COLDFIRE(m5272)"
+#define CPU_INSTR_PER_JIFFY 3
+
+#include <asm/m52xxacr.h>
+
/*
* Define the 5272 SIM register set addresses.
*/
@@ -62,6 +67,9 @@
#define MCFSIM_DCMR1 0x5c /* DRAM 1 Mask reg (r/w) */
#define MCFSIM_DCCR1 0x63 /* DRAM 1 Control reg (r/w) */
+#define MCFUART_BASE1 0x100 /* Base address of UART1 */
+#define MCFUART_BASE2 0x140 /* Base address of UART2 */
+
#define MCFSIM_PACNT (MCF_MBAR + 0x80) /* Port A Control (r/w) */
#define MCFSIM_PADDR (MCF_MBAR + 0x84) /* Port A Direction (r/w) */
#define MCFSIM_PADAT (MCF_MBAR + 0x86) /* Port A Data (r/w) */
diff --git a/arch/m68k/include/asm/m527xsim.h b/arch/m68k/include/asm/m527xsim.h
index 1feb46f..e8042e8 100644
--- a/arch/m68k/include/asm/m527xsim.h
+++ b/arch/m68k/include/asm/m527xsim.h
@@ -11,6 +11,10 @@
#define m527xsim_h
/****************************************************************************/
+#define CPU_NAME "COLDFIRE(m527x)"
+#define CPU_INSTR_PER_JIFFY 3
+
+#include <asm/m52xxacr.h>
/*
* Define the 5270/5271 SIM register set addresses.
@@ -55,6 +59,12 @@
#define MCFSIM_DMR1 0x5c /* SDRAM address mask 1 */
#endif
+/*
+ * UART module.
+ */
+#define MCFUART_BASE1 0x200 /* Base address of UART1 */
+#define MCFUART_BASE2 0x240 /* Base address of UART2 */
+#define MCFUART_BASE3 0x280 /* Base address of UART3 */
#ifdef CONFIG_M5271
#define MCFGPIO_PODR_ADDR (MCF_IPSBAR + 0x100000)
diff --git a/arch/m68k/include/asm/m528xsim.h b/arch/m68k/include/asm/m528xsim.h
index 891cbed..a6d2f4d 100644
--- a/arch/m68k/include/asm/m528xsim.h
+++ b/arch/m68k/include/asm/m528xsim.h
@@ -11,6 +11,10 @@
#define m528xsim_h
/****************************************************************************/
+#define CPU_NAME "COLDFIRE(m528x)"
+#define CPU_INSTR_PER_JIFFY 3
+
+#include <asm/m52xxacr.h>
/*
* Define the 5280/5282 SIM register set addresses.
@@ -42,6 +46,13 @@
#define MCFSIM_DMR1 0x54 /* SDRAM address mask 1 */
/*
+ * UART module.
+ */
+#define MCFUART_BASE1 0x200 /* Base address of UART1 */
+#define MCFUART_BASE2 0x240 /* Base address of UART2 */
+#define MCFUART_BASE3 0x280 /* Base address of UART3 */
+
+/*
* GPIO registers
*/
#define MCFGPIO_PORTA (MCF_IPSBAR + 0x00100000)
diff --git a/arch/m68k/include/asm/m52xxacr.h b/arch/m68k/include/asm/m52xxacr.h
new file mode 100644
index 0000000..abc391a
--- /dev/null
+++ b/arch/m68k/include/asm/m52xxacr.h
@@ -0,0 +1,94 @@
+/****************************************************************************/
+
+/*
+ * m52xxacr.h -- ColdFire version 2 core cache support
+ *
+ * (C) Copyright 2010, Greg Ungerer <gerg@snapgear.com>
+ */
+
+/****************************************************************************/
+#ifndef m52xxacr_h
+#define m52xxacr_h
+/****************************************************************************/
+
+/*
+ * All varients of the ColdFire using version 2 cores have a similar
+ * cache setup. Although not absolutely identical the cache register
+ * definitions are compatible for all of them. Mostly they support a
+ * configurable cache memory that can be instruction only, data only,
+ * or split instruction and data. The exception is the very old version 2
+ * core based parts, like the 5206(e), 5249 and 5272, which are instruction
+ * cache only. Cache size varies from 2k up to 16k.
+ */
+
+/*
+ * Define the Cache Control register flags.
+ */
+#define CACR_CENB 0x80000000 /* Enable cache */
+#define CACR_CDPI 0x10000000 /* Disable invalidation by CPUSHL */
+#define CACR_CFRZ 0x08000000 /* Cache freeze mode */
+#define CACR_CINV 0x01000000 /* Invalidate cache */
+#define CACR_DISI 0x00800000 /* Disable instruction cache */
+#define CACR_DISD 0x00400000 /* Disable data cache */
+#define CACR_INVI 0x00200000 /* Invalidate instruction cache */
+#define CACR_INVD 0x00100000 /* Invalidate data cache */
+#define CACR_CEIB 0x00000400 /* Non-cachable instruction burst */
+#define CACR_DCM 0x00000200 /* Default cache mode */
+#define CACR_DBWE 0x00000100 /* Buffered write enable */
+#define CACR_DWP 0x00000020 /* Write protection */
+#define CACR_EUSP 0x00000010 /* Enable separate user a7 */
+
+/*
+ * Define the Access Control register flags.
+ */
+#define ACR_BASE_POS 24 /* Address Base (upper 8 bits) */
+#define ACR_MASK_POS 16 /* Address Mask (next 8 bits) */
+#define ACR_ENABLE 0x00008000 /* Enable this ACR */
+#define ACR_USER 0x00000000 /* Allow only user accesses */
+#define ACR_SUPER 0x00002000 /* Allow supervisor access only */
+#define ACR_ANY 0x00004000 /* Allow any access type */
+#define ACR_CENB 0x00000000 /* Caching of region enabled */
+#define ACR_CDIS 0x00000040 /* Caching of region disabled */
+#define ACR_BWE 0x00000020 /* Write buffer enabled */
+#define ACR_WPROTECT 0x00000004 /* Write protect region */
+
+/*
+ * Set the cache controller settings we will use. On the cores that support
+ * a split cache configuration we allow all the combinations at Kconfig
+ * time. For those cores that only have an instruction cache we just set
+ * that as on.
+ */
+#if defined(CONFIG_CACHE_I)
+#define CACHE_TYPE (CACR_DISD + CACR_EUSP)
+#define CACHE_INVTYPEI 0
+#elif defined(CONFIG_CACHE_D)
+#define CACHE_TYPE (CACR_DISI + CACR_EUSP)
+#define CACHE_INVTYPED 0
+#elif defined(CONFIG_CACHE_BOTH)
+#define CACHE_TYPE CACR_EUSP
+#define CACHE_INVTYPEI CACR_INVI
+#define CACHE_INVTYPED CACR_INVD
+#else
+/* This is the instruction cache only devices (no split cache, no eusp) */
+#define CACHE_TYPE 0
+#define CACHE_INVTYPEI 0
+#endif
+
+#define CACHE_INIT (CACR_CINV + CACHE_TYPE)
+#define CACHE_MODE (CACR_CENB + CACHE_TYPE + CACR_DCM)
+
+#define CACHE_INVALIDATE (CACHE_MODE + CACR_CINV)
+#if defined(CACHE_INVTYPEI)
+#define CACHE_INVALIDATEI (CACHE_MODE + CACR_CINV + CACHE_INVTYPEI)
+#endif
+#if defined(CACHE_INVTYPED)
+#define CACHE_INVALIDATED (CACHE_MODE + CACR_CINV + CACHE_INVTYPED)
+#endif
+
+#define ACR0_MODE ((CONFIG_RAMBASE & 0xff000000) + \
+ (0x000f0000) + \
+ (ACR_ENABLE + ACR_ANY + ACR_CENB + ACR_BWE))
+#define ACR1_MODE 0
+
+/****************************************************************************/
+#endif /* m52xxsim_h */
diff --git a/arch/m68k/include/asm/m5307sim.h b/arch/m68k/include/asm/m5307sim.h
index c6830e5..0bf5739 100644
--- a/arch/m68k/include/asm/m5307sim.h
+++ b/arch/m68k/include/asm/m5307sim.h
@@ -14,6 +14,11 @@
#define m5307sim_h
/****************************************************************************/
+#define CPU_NAME "COLDFIRE(m5307)"
+#define CPU_INSTR_PER_JIFFY 3
+
+#include <asm/m53xxacr.h>
+
/*
* Define the 5307 SIM register set addresses.
*/
@@ -94,6 +99,17 @@
#define MCFSIM_PADAT (MCF_MBAR + 0x248)
/*
+ * UART module.
+ */
+#if defined(CONFIG_NETtel) || defined(CONFIG_SECUREEDGEMP3)
+#define MCFUART_BASE1 0x200 /* Base address of UART1 */
+#define MCFUART_BASE2 0x1c0 /* Base address of UART2 */
+#else
+#define MCFUART_BASE1 0x1c0 /* Base address of UART1 */
+#define MCFUART_BASE2 0x200 /* Base address of UART2 */
+#endif
+
+/*
* Generic GPIO support
*/
#define MCFGPIO_PIN_MAX 16
@@ -146,32 +162,5 @@
#define MCF_IRQ_TIMER 30 /* Timer0, Level 6 */
#define MCF_IRQ_PROFILER 31 /* Timer1, Level 7 */
-/*
- * Define the Cache register flags.
- */
-#define CACR_EC (1<<31)
-#define CACR_ESB (1<<29)
-#define CACR_DPI (1<<28)
-#define CACR_HLCK (1<<27)
-#define CACR_CINVA (1<<24)
-#define CACR_DNFB (1<<10)
-#define CACR_DCM_WTHRU (0<<8)
-#define CACR_DCM_WBACK (1<<8)
-#define CACR_DCM_OFF_PRE (2<<8)
-#define CACR_DCM_OFF_IMP (3<<8)
-#define CACR_DW (1<<5)
-
-#define ACR_BASE_POS 24
-#define ACR_MASK_POS 16
-#define ACR_ENABLE (1<<15)
-#define ACR_USER (0<<13)
-#define ACR_SUPER (1<<13)
-#define ACR_ANY (2<<13)
-#define ACR_CM_WTHRU (0<<5)
-#define ACR_CM_WBACK (1<<5)
-#define ACR_CM_OFF_PRE (2<<5)
-#define ACR_CM_OFF_IMP (3<<5)
-#define ACR_WPROTECT (1<<2)
-
/****************************************************************************/
#endif /* m5307sim_h */
diff --git a/arch/m68k/include/asm/m532xsim.h b/arch/m68k/include/asm/m532xsim.h
index c4bf1c8..e6470f8 100644
--- a/arch/m68k/include/asm/m532xsim.h
+++ b/arch/m68k/include/asm/m532xsim.h
@@ -9,6 +9,11 @@
#define m532xsim_h
/****************************************************************************/
+#define CPU_NAME "COLDFIRE(m532x)"
+#define CPU_INSTR_PER_JIFFY 3
+
+#include <asm/m53xxacr.h>
+
#define MCF_REG32(x) (*(volatile unsigned long *)(x))
#define MCF_REG16(x) (*(volatile unsigned short *)(x))
#define MCF_REG08(x) (*(volatile unsigned char *)(x))
@@ -74,31 +79,11 @@
#define MCF_IRQ_PROFILER (64 + 33) /* Timer1 */
/*
- * Define the Cache register flags.
+ * UART module.
*/
-#define CACR_EC (1<<31)
-#define CACR_ESB (1<<29)
-#define CACR_DPI (1<<28)
-#define CACR_HLCK (1<<27)
-#define CACR_CINVA (1<<24)
-#define CACR_DNFB (1<<10)
-#define CACR_DCM_WTHRU (0<<8)
-#define CACR_DCM_WBACK (1<<8)
-#define CACR_DCM_OFF_PRE (2<<8)
-#define CACR_DCM_OFF_IMP (3<<8)
-#define CACR_DW (1<<5)
-
-#define ACR_BASE_POS 24
-#define ACR_MASK_POS 16
-#define ACR_ENABLE (1<<15)
-#define ACR_USER (0<<13)
-#define ACR_SUPER (1<<13)
-#define ACR_ANY (2<<13)
-#define ACR_CM_WTHRU (0<<5)
-#define ACR_CM_WBACK (1<<5)
-#define ACR_CM_OFF_PRE (2<<5)
-#define ACR_CM_OFF_IMP (3<<5)
-#define ACR_WPROTECT (1<<2)
+#define MCFUART_BASE1 0xFC060000 /* Base address of UART1 */
+#define MCFUART_BASE2 0xFC064000 /* Base address of UART2 */
+#define MCFUART_BASE3 0xFC068000 /* Base address of UART3 */
/*********************************************************************
*
diff --git a/arch/m68k/include/asm/m53xxacr.h b/arch/m68k/include/asm/m53xxacr.h
new file mode 100644
index 0000000..cd952b0
--- /dev/null
+++ b/arch/m68k/include/asm/m53xxacr.h
@@ -0,0 +1,101 @@
+/****************************************************************************/
+
+/*
+ * m53xxacr.h -- ColdFire version 3 core cache support
+ *
+ * (C) Copyright 2010, Greg Ungerer <gerg@snapgear.com>
+ */
+
+/****************************************************************************/
+#ifndef m53xxacr_h
+#define m53xxacr_h
+/****************************************************************************/
+
+/*
+ * All varients of the ColdFire using version 3 cores have a similar
+ * cache setup. They have a unified instruction and data cache, with
+ * configurable write-through or copy-back operation.
+ */
+
+/*
+ * Define the Cache Control register flags.
+ */
+#define CACR_EC 0x80000000 /* Enable cache */
+#define CACR_ESB 0x20000000 /* Enable store buffer */
+#define CACR_DPI 0x10000000 /* Disable invalidation by CPUSHL */
+#define CACR_HLCK 0x08000000 /* Half cache lock mode */
+#define CACR_CINVA 0x01000000 /* Invalidate cache */
+#define CACR_DNFB 0x00000400 /* Inhibited fill buffer */
+#define CACR_DCM_WT 0x00000000 /* Cacheable write-through */
+#define CACR_DCM_CB 0x00000100 /* Cacheable copy-back */
+#define CACR_DCM_PRE 0x00000200 /* Cache inhibited, precise */
+#define CACR_DCM_IMPRE 0x00000300 /* Cache inhibited, imprecise */
+#define CACR_WPROTECT 0x00000020 /* Write protect*/
+#define CACR_EUSP 0x00000010 /* Eanble separate user a7 */
+
+/*
+ * Define the Access Control register flags.
+ */
+#define ACR_BASE_POS 24 /* Address Base (upper 8 bits) */
+#define ACR_MASK_POS 16 /* Address Mask (next 8 bits) */
+#define ACR_ENABLE 0x00008000 /* Enable this ACR */
+#define ACR_USER 0x00000000 /* Allow only user accesses */
+#define ACR_SUPER 0x00002000 /* Allow supervisor access only */
+#define ACR_ANY 0x00004000 /* Allow any access type */
+#define ACR_CM_WT 0x00000000 /* Cacheable, write-through */
+#define ACR_CM_CB 0x00000020 /* Cacheable, copy-back */
+#define ACR_CM_PRE 0x00000040 /* Cache inhibited, precise */
+#define ACR_CM_IMPRE 0x00000060 /* Cache inhibited, imprecise */
+#define ACR_WPROTECT 0x00000004 /* Write protect region */
+
+/*
+ * Define the cache type and arrangement (needed for pushes).
+ */
+#if defined(CONFIG_M5307)
+#define CACHE_SIZE 0x2000 /* 8k of unified cache */
+#define ICACHE_SIZE CACHE_SIZE
+#define DCACHE_SIZE CACHE_SIZE
+#elif defined(CONFIG_M532x)
+#define CACHE_SIZE 0x4000 /* 32k of unified cache */
+#define ICACHE_SIZE CACHE_SIZE
+#define DCACHE_SIZE CACHE_SIZE
+#endif
+
+#define CACHE_LINE_SIZE 16 /* 16 byte line size */
+#define CACHE_WAYS 4 /* 4 ways - set associative */
+
+/*
+ * Set the cache controller settings we will use. This default in the
+ * CACR is cache inhibited, we use the ACR register to set cacheing
+ * enabled on the regions we want (eg RAM).
+ */
+#if defined(CONFIG_CACHE_COPYBACK)
+#define CACHE_TYPE ACR_CM_CB
+#define CACHE_PUSH
+#else
+#define CACHE_TYPE ACR_CM_WT
+#endif
+
+#ifdef CONFIG_COLDFIRE_SW_A7
+#define CACHE_MODE (CACR_EC + CACR_ESB + CACR_DCM_PRE)
+#else
+#define CACHE_MODE (CACR_EC + CACR_ESB + CACR_DCM_PRE + CACR_EUSP)
+#endif
+
+/*
+ * Unified cache means we will never need to flush for coherency of
+ * instruction fetch. We will need to flush to maintain memory/DMA
+ * coherency though in all cases. And for copyback caches we will need
+ * to push cached data as well.
+ */
+#define CACHE_INIT CACR_CINVA
+#define CACHE_INVALIDATE CACR_CINVA
+#define CACHE_INVALIDATED CACR_CINVA
+
+#define ACR0_MODE ((CONFIG_RAMBASE & 0xff000000) + \
+ (0x000f0000) + \
+ (ACR_ENABLE + ACR_ANY + CACHE_TYPE))
+#define ACR1_MODE 0
+
+/****************************************************************************/
+#endif /* m53xxsim_h */
diff --git a/arch/m68k/include/asm/m5407sim.h b/arch/m68k/include/asm/m5407sim.h
index c399abb..75f5c28 100644
--- a/arch/m68k/include/asm/m5407sim.h
+++ b/arch/m68k/include/asm/m5407sim.h
@@ -14,6 +14,11 @@
#define m5407sim_h
/****************************************************************************/
+#define CPU_NAME "COLDFIRE(m5407)"
+#define CPU_INSTR_PER_JIFFY 3
+
+#include <asm/m54xxacr.h>
+
/*
* Define the 5407 SIM register set addresses.
*/
@@ -73,6 +78,9 @@
#define MCFSIM_DACR1 0x110 /* DRAM 1 Addr and Ctrl (r/w) */
#define MCFSIM_DMR1 0x114 /* DRAM 1 Mask reg (r/w) */
+#define MCFUART_BASE1 0x1c0 /* Base address of UART1 */
+#define MCFUART_BASE2 0x200 /* Base address of UART2 */
+
#define MCFSIM_PADDR (MCF_MBAR + 0x244)
#define MCFSIM_PADAT (MCF_MBAR + 0x248)
@@ -117,39 +125,5 @@
#define MCF_IRQ_TIMER 30 /* Timer0, Level 6 */
#define MCF_IRQ_PROFILER 31 /* Timer1, Level 7 */
-/*
- * Define the Cache register flags.
- */
-#define CACR_DEC 0x80000000 /* Enable data cache */
-#define CACR_DWP 0x40000000 /* Data write protection */
-#define CACR_DESB 0x20000000 /* Enable data store buffer */
-#define CACR_DDPI 0x10000000 /* Disable CPUSHL */
-#define CACR_DHCLK 0x08000000 /* Half data cache lock mode */
-#define CACR_DDCM_WT 0x00000000 /* Write through cache*/
-#define CACR_DDCM_CP 0x02000000 /* Copyback cache */
-#define CACR_DDCM_P 0x04000000 /* No cache, precise */
-#define CACR_DDCM_IMP 0x06000000 /* No cache, imprecise */
-#define CACR_DCINVA 0x01000000 /* Invalidate data cache */
-#define CACR_BEC 0x00080000 /* Enable branch cache */
-#define CACR_BCINVA 0x00040000 /* Invalidate branch cache */
-#define CACR_IEC 0x00008000 /* Enable instruction cache */
-#define CACR_DNFB 0x00002000 /* Inhibited fill buffer */
-#define CACR_IDPI 0x00001000 /* Disable CPUSHL */
-#define CACR_IHLCK 0x00000800 /* Intruction cache half lock */
-#define CACR_IDCM 0x00000400 /* Intruction cache inhibit */
-#define CACR_ICINVA 0x00000100 /* Invalidate instr cache */
-
-#define ACR_BASE_POS 24 /* Address Base */
-#define ACR_MASK_POS 16 /* Address Mask */
-#define ACR_ENABLE 0x00008000 /* Enable address */
-#define ACR_USER 0x00000000 /* User mode access only */
-#define ACR_SUPER 0x00002000 /* Supervisor mode only */
-#define ACR_ANY 0x00004000 /* Match any access mode */
-#define ACR_CM_WT 0x00000000 /* Write through mode */
-#define ACR_CM_CP 0x00000020 /* Copyback mode */
-#define ACR_CM_OFF_PRE 0x00000040 /* No cache, precise */
-#define ACR_CM_OFF_IMP 0x00000060 /* No cache, imprecise */
-#define ACR_WPROTECT 0x00000004 /* Write protect */
-
/****************************************************************************/
#endif /* m5407sim_h */
diff --git a/arch/m68k/include/asm/m54xxacr.h b/arch/m68k/include/asm/m54xxacr.h
new file mode 100644
index 0000000..16a1835
--- /dev/null
+++ b/arch/m68k/include/asm/m54xxacr.h
@@ -0,0 +1,97 @@
+/*
+ * Bit definitions for the MCF54xx ACR and CACR registers.
+ */
+
+#ifndef m54xxacr_h
+#define m54xxacr_h
+
+/*
+ * Define the Cache register flags.
+ */
+#define CACR_DEC 0x80000000 /* Enable data cache */
+#define CACR_DWP 0x40000000 /* Data write protection */
+#define CACR_DESB 0x20000000 /* Enable data store buffer */
+#define CACR_DDPI 0x10000000 /* Disable invalidation by CPUSHL */
+#define CACR_DHCLK 0x08000000 /* Half data cache lock mode */
+#define CACR_DDCM_WT 0x00000000 /* Write through cache*/
+#define CACR_DDCM_CP 0x02000000 /* Copyback cache */
+#define CACR_DDCM_P 0x04000000 /* No cache, precise */
+#define CACR_DDCM_IMP 0x06000000 /* No cache, imprecise */
+#define CACR_DCINVA 0x01000000 /* Invalidate data cache */
+#define CACR_BEC 0x00080000 /* Enable branch cache */
+#define CACR_BCINVA 0x00040000 /* Invalidate branch cache */
+#define CACR_IEC 0x00008000 /* Enable instruction cache */
+#define CACR_DNFB 0x00002000 /* Inhibited fill buffer */
+#define CACR_IDPI 0x00001000 /* Disable CPUSHL */
+#define CACR_IHLCK 0x00000800 /* Intruction cache half lock */
+#define CACR_IDCM 0x00000400 /* Intruction cache inhibit */
+#define CACR_ICINVA 0x00000100 /* Invalidate instr cache */
+#define CACR_EUSP 0x00000020 /* Enable separate user a7 */
+
+#define ACR_BASE_POS 24 /* Address Base */
+#define ACR_MASK_POS 16 /* Address Mask */
+#define ACR_ENABLE 0x00008000 /* Enable address */
+#define ACR_USER 0x00000000 /* User mode access only */
+#define ACR_SUPER 0x00002000 /* Supervisor mode only */
+#define ACR_ANY 0x00004000 /* Match any access mode */
+#define ACR_CM_WT 0x00000000 /* Write through mode */
+#define ACR_CM_CP 0x00000020 /* Copyback mode */
+#define ACR_CM_OFF_PRE 0x00000040 /* No cache, precise */
+#define ACR_CM_OFF_IMP 0x00000060 /* No cache, imprecise */
+#define ACR_CM 0x00000060 /* Cache mode mask */
+#define ACR_WPROTECT 0x00000004 /* Write protect */
+
+#if defined(CONFIG_M5407)
+
+#define ICACHE_SIZE 0x4000 /* instruction - 16k */
+#define DCACHE_SIZE 0x2000 /* data - 8k */
+
+#elif defined(CONFIG_M54xx)
+
+#define ICACHE_SIZE 0x8000 /* instruction - 32k */
+#define DCACHE_SIZE 0x8000 /* data - 32k */
+
+#endif
+
+#define CACHE_LINE_SIZE 0x0010 /* 16 bytes */
+#define CACHE_WAYS 4 /* 4 ways */
+
+/*
+ * Version 4 cores have a true harvard style separate instruction
+ * and data cache. Enable data and instruction caches, also enable write
+ * buffers and branch accelerator.
+ */
+/* attention : enabling CACR_DESB requires a "nop" to flush the store buffer */
+/* use '+' instead of '|' for assembler's sake */
+
+ /* Enable data cache */
+ /* Enable data store buffer */
+ /* outside ACRs : No cache, precise */
+ /* Enable instruction+branch caches */
+#if defined(CONFIG_M5407)
+#define CACHE_MODE (CACR_DEC+CACR_DESB+CACR_DDCM_P+CACR_BEC+CACR_IEC)
+#else
+#define CACHE_MODE (CACR_DEC+CACR_DESB+CACR_DDCM_P+CACR_BEC+CACR_IEC+CACR_EUSP)
+#endif
+#if defined(CONFIG_CACHE_COPYBACK)
+#define DATA_CACHE_MODE (ACR_ENABLE+ACR_ANY+ACR_CM_CP)
+#else
+#define DATA_CACHE_MODE (ACR_ENABLE+ACR_ANY+ACR_CM_WT)
+#endif
+#define INSN_CACHE_MODE (ACR_ENABLE+ACR_ANY)
+
+#define CACHE_INIT (CACR_DCINVA+CACR_BCINVA+CACR_ICINVA)
+#define CACHE_INVALIDATE (CACHE_MODE+CACR_DCINVA+CACR_BCINVA+CACR_ICINVA)
+#define CACHE_INVALIDATEI (CACHE_MODE+CACR_BCINVA+CACR_ICINVA)
+#define CACHE_INVALIDATED (CACHE_MODE+CACR_DCINVA)
+#define ACR0_MODE (0x000f0000+DATA_CACHE_MODE)
+#define ACR1_MODE 0
+#define ACR2_MODE (0x000f0000+INSN_CACHE_MODE)
+#define ACR3_MODE 0
+
+#if ((DATA_CACHE_MODE & ACR_CM) == ACR_CM_CP)
+/* Copyback cache mode must push dirty cache lines first */
+#define CACHE_PUSH
+#endif
+
+#endif /* m54xxacr_h */
diff --git a/arch/m68k/include/asm/m548xgpt.h b/arch/m68k/include/asm/m54xxgpt.h
index 33b2eef..df75dd8 100644
--- a/arch/m68k/include/asm/m548xgpt.h
+++ b/arch/m68k/include/asm/m54xxgpt.h
@@ -1,13 +1,13 @@
/*
- * File: m548xgpt.h
- * Purpose: Register and bit definitions for the MCF548X
+ * File: m54xxgpt.h
+ * Purpose: Register and bit definitions for the MCF54XX
*
* Notes:
*
*/
-#ifndef m548xgpt_h
-#define m548xgpt_h
+#ifndef m54xxgpt_h
+#define m54xxgpt_h
/*********************************************************************
*
@@ -87,4 +87,4 @@
/********************************************************************/
-#endif /* m548xgpt_h */
+#endif /* m54xxgpt_h */
diff --git a/arch/m68k/include/asm/m548xsim.h b/arch/m68k/include/asm/m54xxsim.h
index 149135e..462ae53 100644
--- a/arch/m68k/include/asm/m548xsim.h
+++ b/arch/m68k/include/asm/m54xxsim.h
@@ -1,11 +1,16 @@
/*
- * m548xsim.h -- ColdFire 547x/548x System Integration Unit support.
+ * m54xxsim.h -- ColdFire 547x/548x System Integration Unit support.
*/
-#ifndef m548xsim_h
-#define m548xsim_h
+#ifndef m54xxsim_h
+#define m54xxsim_h
-#define MCFINT_VECBASE 64
+#define CPU_NAME "COLDFIRE(m54xx)"
+#define CPU_INSTR_PER_JIFFY 2
+
+#include <asm/m54xxacr.h>
+
+#define MCFINT_VECBASE 64
/*
* Interrupt Controller Registers
@@ -22,6 +27,14 @@
#define MCFINTC_ICR0 0x40 /* Base ICR register */
/*
+ * UART module.
+ */
+#define MCFUART_BASE1 0x8600 /* Base address of UART1 */
+#define MCFUART_BASE2 0x8700 /* Base address of UART2 */
+#define MCFUART_BASE3 0x8800 /* Base address of UART3 */
+#define MCFUART_BASE4 0x8900 /* Base address of UART4 */
+
+/*
* Define system peripheral IRQ usage.
*/
#define MCF_IRQ_TIMER (64 + 54) /* Slice Timer 0 */
@@ -52,4 +65,4 @@
#define MCF_PAR_PSC_RTS_RTS (0x30)
#define MCF_PAR_PSC_CANRX (0x40)
-#endif /* m548xsim_h */
+#endif /* m54xxsim_h */
diff --git a/arch/m68k/include/asm/mcfcache.h b/arch/m68k/include/asm/mcfcache.h
deleted file mode 100644
index f49dfc0..0000000
--- a/arch/m68k/include/asm/mcfcache.h
+++ /dev/null
@@ -1,150 +0,0 @@
-/****************************************************************************/
-
-/*
- * mcfcache.h -- ColdFire CPU cache support code
- *
- * (C) Copyright 2004, Greg Ungerer <gerg@snapgear.com>
- */
-
-/****************************************************************************/
-#ifndef __M68KNOMMU_MCFCACHE_H
-#define __M68KNOMMU_MCFCACHE_H
-/****************************************************************************/
-
-
-/*
- * The different ColdFire families have different cache arrangments.
- * Everything from a small instruction only cache, to configurable
- * data and/or instruction cache, to unified instruction/data, to
- * harvard style separate instruction and data caches.
- */
-
-#if defined(CONFIG_M5206) || defined(CONFIG_M5206e) || defined(CONFIG_M5272)
-/*
- * Simple version 2 core cache. These have instruction cache only,
- * we just need to invalidate it and enable it.
- */
-.macro CACHE_ENABLE
- movel #0x01000000,%d0 /* invalidate cache cmd */
- movec %d0,%CACR /* do invalidate cache */
- movel #0x80000100,%d0 /* setup cache mask */
- movec %d0,%CACR /* enable cache */
-.endm
-#endif /* CONFIG_M5206 || CONFIG_M5206e || CONFIG_M5272 */
-
-#if defined(CONFIG_M523x) || defined(CONFIG_M527x)
-/*
- * New version 2 cores have a configurable split cache arrangement.
- * For now I am just enabling instruction cache - but ultimately I
- * think a split instruction/data cache would be better.
- */
-.macro CACHE_ENABLE
- movel #0x01400000,%d0
- movec %d0,%CACR /* invalidate cache */
- nop
- movel #0x0000c000,%d0 /* set SDRAM cached only */
- movec %d0,%ACR0
- movel #0x00000000,%d0 /* no other regions cached */
- movec %d0,%ACR1
- movel #0x80400100,%d0 /* configure cache */
- movec %d0,%CACR /* enable cache */
- nop
-.endm
-#endif /* CONFIG_M523x || CONFIG_M527x */
-
-#if defined(CONFIG_M528x)
-.macro CACHE_ENABLE
- nop
- movel #0x01000000, %d0
- movec %d0, %CACR /* Invalidate cache */
- nop
- movel #0x0000c020, %d0 /* Set SDRAM cached only */
- movec %d0, %ACR0
- movel #0x00000000, %d0 /* No other regions cached */
- movec %d0, %ACR1
- movel #0x80000200, %d0 /* Setup cache mask */
- movec %d0, %CACR /* Enable cache */
- nop
-.endm
-#endif /* CONFIG_M528x */
-
-#if defined(CONFIG_M5249) || defined(CONFIG_M5307)
-/*
- * The version 3 core cache. Oddly enough the version 2 core 5249
- * has the same SDRAM and cache setup as the version 3 cores.
- * This is a single unified instruction/data cache.
- */
-.macro CACHE_ENABLE
- movel #0x01000000,%d0 /* invalidate whole cache */
- movec %d0,%CACR
- nop
-#if defined(DEBUGGER_COMPATIBLE_CACHE) || defined(CONFIG_SECUREEDGEMP3)
- movel #0x0000c000,%d0 /* set SDRAM cached (write-thru) */
-#else
- movel #0x0000c020,%d0 /* set SDRAM cached (copyback) */
-#endif
- movec %d0,%ACR0
- movel #0x00000000,%d0 /* no other regions cached */
- movec %d0,%ACR1
- movel #0xa0000200,%d0 /* enable cache */
- movec %d0,%CACR
- nop
-.endm
-#endif /* CONFIG_M5249 || CONFIG_M5307 */
-
-#if defined(CONFIG_M532x)
-.macro CACHE_ENABLE
- movel #0x01000000,%d0 /* invalidate cache cmd */
- movec %d0,%CACR /* do invalidate cache */
- nop
- movel #0x4001C000,%d0 /* set SDRAM cached (write-thru) */
- movec %d0,%ACR0
- movel #0x00000000,%d0 /* no other regions cached */
- movec %d0,%ACR1
- movel #0x80000200,%d0 /* setup cache mask */
- movec %d0,%CACR /* enable cache */
- nop
-.endm
-#endif /* CONFIG_M532x */
-
-#if defined(CONFIG_M5407) || defined(CONFIG_M548x)
-/*
- * Version 4 cores have a true harvard style separate instruction
- * and data cache. Invalidate and enable cache, also enable write
- * buffers and branch accelerator.
- */
-.macro CACHE_ENABLE
- movel #0x01040100,%d0 /* invalidate whole cache */
- movec %d0,%CACR
- nop
- movel #0x000fc000,%d0 /* set SDRAM cached only */
- movec %d0, %ACR0
- movel #0x00000000,%d0 /* no other regions cached */
- movec %d0, %ACR1
- movel #0x000fc000,%d0 /* set SDRAM cached only */
- movec %d0, %ACR2
- movel #0x00000000,%d0 /* no other regions cached */
- movec %d0, %ACR3
- movel #0xb6088400,%d0 /* enable caches */
- movec %d0,%CACR
- nop
-.endm
-#endif /* CONFIG_M5407 */
-
-#if defined(CONFIG_M520x)
-.macro CACHE_ENABLE
- move.l #0x01000000,%d0 /* invalidate whole cache */
- movec %d0,%CACR
- nop
- move.l #0x0000c000,%d0 /* set SDRAM cached (write-thru) */
- movec %d0,%ACR0
- move.l #0x00000000,%d0 /* no other regions cached */
- movec %d0,%ACR1
- move.l #0x80400000,%d0 /* enable 8K instruction cache */
- movec %d0,%CACR
- nop
-.endm
-#endif /* CONFIG_M520x */
-
-/****************************************************************************/
-#endif /* __M68KNOMMU_MCFCACHE_H */
diff --git a/arch/m68k/include/asm/mcfsim.h b/arch/m68k/include/asm/mcfsim.h
index 6901fd6..ebd0304 100644
--- a/arch/m68k/include/asm/mcfsim.h
+++ b/arch/m68k/include/asm/mcfsim.h
@@ -41,8 +41,8 @@
#elif defined(CONFIG_M5407)
#include <asm/m5407sim.h>
#include <asm/mcfintc.h>
-#elif defined(CONFIG_M548x)
-#include <asm/m548xsim.h>
+#elif defined(CONFIG_M54xx)
+#include <asm/m54xxsim.h>
#endif
/****************************************************************************/
diff --git a/arch/m68k/include/asm/mcfuart.h b/arch/m68k/include/asm/mcfuart.h
index db72e2b..2abedff 100644
--- a/arch/m68k/include/asm/mcfuart.h
+++ b/arch/m68k/include/asm/mcfuart.h
@@ -12,49 +12,6 @@
#define mcfuart_h
/****************************************************************************/
-/*
- * Define the base address of the UARTS within the MBAR address
- * space.
- */
-#if defined(CONFIG_M5272)
-#define MCFUART_BASE1 0x100 /* Base address of UART1 */
-#define MCFUART_BASE2 0x140 /* Base address of UART2 */
-#elif defined(CONFIG_M5206) || defined(CONFIG_M5206e)
-#if defined(CONFIG_NETtel)
-#define MCFUART_BASE1 0x180 /* Base address of UART1 */
-#define MCFUART_BASE2 0x140 /* Base address of UART2 */
-#else
-#define MCFUART_BASE1 0x140 /* Base address of UART1 */
-#define MCFUART_BASE2 0x180 /* Base address of UART2 */
-#endif
-#elif defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x)
-#define MCFUART_BASE1 0x200 /* Base address of UART1 */
-#define MCFUART_BASE2 0x240 /* Base address of UART2 */
-#define MCFUART_BASE3 0x280 /* Base address of UART3 */
-#elif defined(CONFIG_M5249) || defined(CONFIG_M5307) || defined(CONFIG_M5407)
-#if defined(CONFIG_NETtel) || defined(CONFIG_SECUREEDGEMP3)
-#define MCFUART_BASE1 0x200 /* Base address of UART1 */
-#define MCFUART_BASE2 0x1c0 /* Base address of UART2 */
-#else
-#define MCFUART_BASE1 0x1c0 /* Base address of UART1 */
-#define MCFUART_BASE2 0x200 /* Base address of UART2 */
-#endif
-#elif defined(CONFIG_M520x)
-#define MCFUART_BASE1 0x60000 /* Base address of UART1 */
-#define MCFUART_BASE2 0x64000 /* Base address of UART2 */
-#define MCFUART_BASE3 0x68000 /* Base address of UART2 */
-#elif defined(CONFIG_M532x)
-#define MCFUART_BASE1 0xfc060000 /* Base address of UART1 */
-#define MCFUART_BASE2 0xfc064000 /* Base address of UART2 */
-#define MCFUART_BASE3 0xfc068000 /* Base address of UART3 */
-#elif defined(CONFIG_M548x)
-#define MCFUART_BASE1 0x8600 /* on M548x */
-#define MCFUART_BASE2 0x8700 /* on M548x */
-#define MCFUART_BASE3 0x8800 /* on M548x */
-#define MCFUART_BASE4 0x8900 /* on M548x */
-#endif
-
-
#include <linux/serial_core.h>
#include <linux/platform_device.h>
@@ -217,7 +174,7 @@ struct mcf_platform_uart {
#define MCFUART_URF_RXS 0xc0 /* Receiver status */
#endif
-#if defined(CONFIG_M548x)
+#if defined(CONFIG_M54xx)
#define MCFUART_TXFIFOSIZE 512
#elif defined(CONFIG_M5272)
#define MCFUART_TXFIFOSIZE 25
diff --git a/arch/m68k/include/asm/processor.h b/arch/m68k/include/asm/processor.h
index 7a6a759..278c69b 100644
--- a/arch/m68k/include/asm/processor.h
+++ b/arch/m68k/include/asm/processor.h
@@ -20,23 +20,26 @@
static inline unsigned long rdusp(void)
{
-#ifdef CONFIG_COLDFIRE
+#ifdef CONFIG_COLDFIRE_SW_A7
extern unsigned int sw_usp;
return sw_usp;
#else
- unsigned long usp;
- __asm__ __volatile__("move %/usp,%0" : "=a" (usp));
+ register unsigned long usp __asm__("a0");
+ /* move %usp,%a0 */
+ __asm__ __volatile__(".word 0x4e68" : "=a" (usp));
return usp;
#endif
}
static inline void wrusp(unsigned long usp)
{
-#ifdef CONFIG_COLDFIRE
+#ifdef CONFIG_COLDFIRE_SW_A7
extern unsigned int sw_usp;
sw_usp = usp;
#else
- __asm__ __volatile__("move %0,%/usp" : : "a" (usp));
+ register unsigned long a0 __asm__("a0") = usp;
+ /* move %a0,%usp */
+ __asm__ __volatile__(".word 0x4e60" : : "a" (a0) );
#endif
}
diff --git a/arch/m68knommu/Kconfig b/arch/m68knommu/Kconfig
index fa9f746..8b9daca 100644
--- a/arch/m68knommu/Kconfig
+++ b/arch/m68knommu/Kconfig
@@ -2,6 +2,7 @@ config M68K
bool
default y
select HAVE_IDE
+ select HAVE_GENERIC_HARDIRQS
config MMU
bool
@@ -48,14 +49,6 @@ config GENERIC_HWEIGHT
bool
default y
-config GENERIC_HARDIRQS
- bool
- default y
-
-config GENERIC_HARDIRQS_NO__DO_IRQ
- bool
- default y
-
config GENERIC_CALIBRATE_DELAY
bool
default y
@@ -75,6 +68,16 @@ config GENERIC_CLOCKEVENTS
config NO_IOPORT
def_bool y
+config COLDFIRE_SW_A7
+ bool
+ default n
+
+config HAVE_CACHE_SPLIT
+ bool
+
+config HAVE_CACHE_CB
+ bool
+
source "init/Kconfig"
source "kernel/Kconfig.freezer"
@@ -107,69 +110,90 @@ config M68360
config M5206
bool "MCF5206"
+ select COLDFIRE_SW_A7
help
Motorola ColdFire 5206 processor support.
config M5206e
bool "MCF5206e"
+ select COLDFIRE_SW_A7
help
Motorola ColdFire 5206e processor support.
config M520x
bool "MCF520x"
select GENERIC_CLOCKEVENTS
+ select HAVE_CACHE_SPLIT
help
Freescale Coldfire 5207/5208 processor support.
config M523x
bool "MCF523x"
select GENERIC_CLOCKEVENTS
+ select HAVE_CACHE_SPLIT
help
Freescale Coldfire 5230/1/2/4/5 processor support
config M5249
bool "MCF5249"
+ select COLDFIRE_SW_A7
help
Motorola ColdFire 5249 processor support.
config M5271
bool "MCF5271"
+ select HAVE_CACHE_SPLIT
help
Freescale (Motorola) ColdFire 5270/5271 processor support.
config M5272
bool "MCF5272"
+ select COLDFIRE_SW_A7
help
Motorola ColdFire 5272 processor support.
config M5275
bool "MCF5275"
+ select HAVE_CACHE_SPLIT
help
Freescale (Motorola) ColdFire 5274/5275 processor support.
config M528x
bool "MCF528x"
select GENERIC_CLOCKEVENTS
+ select HAVE_CACHE_SPLIT
help
Motorola ColdFire 5280/5282 processor support.
config M5307
bool "MCF5307"
+ select COLDFIRE_SW_A7
+ select HAVE_CACHE_CB
help
Motorola ColdFire 5307 processor support.
config M532x
bool "MCF532x"
+ select HAVE_CACHE_CB
help
Freescale (Motorola) ColdFire 532x processor support.
config M5407
bool "MCF5407"
+ select COLDFIRE_SW_A7
+ select HAVE_CACHE_CB
help
Motorola ColdFire 5407 processor support.
+config M547x
+ bool "MCF547x"
+ select HAVE_CACHE_CB
+ help
+ Freescale ColdFire 5470/5471/5472/5473/5474/5475 processor support.
+
config M548x
bool "MCF548x"
+ select HAVE_CACHE_CB
help
Freescale ColdFire 5480/5481/5482/5483/5484/5485 processor support.
@@ -181,9 +205,14 @@ config M527x
select GENERIC_CLOCKEVENTS
default y
+config M54xx
+ bool
+ depends on (M548x || M547x)
+ default y
+
config COLDFIRE
bool
- depends on (M5206 || M5206e || M520x || M523x || M5249 || M527x || M5272 || M528x || M5307 || M532x || M5407 || M548x)
+ depends on (M5206 || M5206e || M520x || M523x || M5249 || M527x || M5272 || M528x || M5307 || M532x || M5407 || M54xx)
select GENERIC_GPIO
select ARCH_REQUIRE_GPIOLIB
default y
@@ -230,6 +259,46 @@ config OLDMASK
Build support for the older revision ColdFire 5307 silicon.
Specifically this is the 1H55J mask revision.
+if HAVE_CACHE_SPLIT
+choice
+ prompt "Split Cache Configuration"
+ default CACHE_I
+
+config CACHE_I
+ bool "Instruction"
+ help
+ Use all of the ColdFire CPU cache memory as an instruction cache.
+
+config CACHE_D
+ bool "Data"
+ help
+ Use all of the ColdFire CPU cache memory as a data cache.
+
+config CACHE_BOTH
+ bool "Both"
+ help
+ Split the ColdFire CPU cache, and use half as an instruction cache
+ and half as a data cache.
+endchoice
+endif
+
+if HAVE_CACHE_CB
+choice
+ prompt "Data cache mode"
+ default CACHE_WRITETHRU
+
+config CACHE_WRITETHRU
+ bool "Write-through"
+ help
+ The ColdFire CPU cache is set into Write-through mode.
+
+config CACHE_COPYBACK
+ bool "Copy-back"
+ help
+ The ColdFire CPU cache is set into Copy-back mode.
+endchoice
+endif
+
comment "Platform"
config PILOT3
@@ -245,16 +314,16 @@ config XCOPILOT_BUGS
Support the bugs of Xcopilot.
config UC5272
- bool 'Arcturus Networks uC5272 dimm board support'
- depends on M5272
- help
- Support for the Arcturus Networks uC5272 dimm board.
+ bool 'Arcturus Networks uC5272 dimm board support'
+ depends on M5272
+ help
+ Support for the Arcturus Networks uC5272 dimm board.
config UC5282
- bool "Arcturus Networks uC5282 board support"
- depends on M528x
- help
- Support for the Arcturus Networks uC5282 dimm board.
+ bool "Arcturus Networks uC5282 board support"
+ depends on M528x
+ help
+ Support for the Arcturus Networks uC5282 dimm board.
config UCSIMM
bool "uCsimm module support"
@@ -279,7 +348,7 @@ config DIRECT_IO_ACCESS
depends on (UCSIMM || UCDIMM || DRAGEN2)
help
Disable the CPU internal registers protection in user mode,
- to allow a user application to read/write them.
+ to allow a user application to read/write them.
config INIT_LCD
bool "Initialize LCD"
@@ -517,7 +586,7 @@ config EMAC_INC
depends on (SOM5282EM)
config SNEHA
- bool
+ bool
default y
depends on CPU16B
diff --git a/arch/m68knommu/Makefile b/arch/m68knommu/Makefile
index 026ef16..589613f 100644
--- a/arch/m68knommu/Makefile
+++ b/arch/m68knommu/Makefile
@@ -25,7 +25,7 @@ platform-$(CONFIG_M528x) := 528x
platform-$(CONFIG_M5307) := 5307
platform-$(CONFIG_M532x) := 532x
platform-$(CONFIG_M5407) := 5407
-platform-$(CONFIG_M548x) := 548x
+platform-$(CONFIG_M54xx) := 54xx
PLATFORM := $(platform-y)
board-$(CONFIG_PILOT) := pilot
@@ -74,7 +74,7 @@ cpuclass-$(CONFIG_M528x) := coldfire
cpuclass-$(CONFIG_M5307) := coldfire
cpuclass-$(CONFIG_M532x) := coldfire
cpuclass-$(CONFIG_M5407) := coldfire
-cpuclass-$(CONFIG_M548x) := coldfire
+cpuclass-$(CONFIG_M54xx) := coldfire
cpuclass-$(CONFIG_M68328) := 68328
cpuclass-$(CONFIG_M68EZ328) := 68328
cpuclass-$(CONFIG_M68VZ328) := 68328
@@ -91,18 +91,18 @@ export PLATFORM BOARD MODEL CPUCLASS
# Some CFLAG additions based on specific CPU type.
#
cflags-$(CONFIG_M5206) := $(call cc-option,-mcpu=5206,-m5200)
-cflags-$(CONFIG_M5206e) := $(call cc-option,-m5206e,-m5200)
+cflags-$(CONFIG_M5206e) := $(call cc-option,-mcpu=5206e,-m5200)
cflags-$(CONFIG_M520x) := $(call cc-option,-mcpu=5208,-m5200)
cflags-$(CONFIG_M523x) := $(call cc-option,-mcpu=523x,-m5307)
cflags-$(CONFIG_M5249) := $(call cc-option,-mcpu=5249,-m5200)
cflags-$(CONFIG_M5271) := $(call cc-option,-mcpu=5271,-m5307)
cflags-$(CONFIG_M5272) := $(call cc-option,-mcpu=5272,-m5307)
cflags-$(CONFIG_M5275) := $(call cc-option,-mcpu=5275,-m5307)
-cflags-$(CONFIG_M528x) := $(call cc-option,-m528x,-m5307)
-cflags-$(CONFIG_M5307) := $(call cc-option,-m5307,-m5200)
+cflags-$(CONFIG_M528x) := $(call cc-option,-mcpu=528x,-m5307)
+cflags-$(CONFIG_M5307) := $(call cc-option,-mcpu=5307,-m5200)
cflags-$(CONFIG_M532x) := $(call cc-option,-mcpu=532x,-m5307)
-cflags-$(CONFIG_M5407) := $(call cc-option,-m5407,-m5200)
-cflags-$(CONFIG_M548x) := $(call cc-option,-m5407,-m5200)
+cflags-$(CONFIG_M5407) := $(call cc-option,-mcpu=5407,-m5200)
+cflags-$(CONFIG_M54xx) := $(call cc-option,-mcpu=5475,-m5200)
cflags-$(CONFIG_M68328) := -m68000
cflags-$(CONFIG_M68EZ328) := -m68000
cflags-$(CONFIG_M68VZ328) := -m68000
diff --git a/arch/m68knommu/configs/m5208evb_defconfig b/arch/m68knommu/configs/m5208evb_defconfig
index 6ac2981..2f5655c 100644
--- a/arch/m68knommu/configs/m5208evb_defconfig
+++ b/arch/m68knommu/configs/m5208evb_defconfig
@@ -1,7 +1,7 @@
CONFIG_EXPERIMENTAL=y
CONFIG_LOG_BUF_SHIFT=14
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_KALLSYMS is not set
# CONFIG_HOTPLUG is not set
# CONFIG_FUTEX is not set
diff --git a/arch/m68knommu/configs/m5249evb_defconfig b/arch/m68knommu/configs/m5249evb_defconfig
index 14934ff..16df72b 100644
--- a/arch/m68knommu/configs/m5249evb_defconfig
+++ b/arch/m68knommu/configs/m5249evb_defconfig
@@ -1,7 +1,7 @@
CONFIG_EXPERIMENTAL=y
CONFIG_LOG_BUF_SHIFT=14
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_KALLSYMS is not set
# CONFIG_HOTPLUG is not set
# CONFIG_FUTEX is not set
diff --git a/arch/m68knommu/configs/m5272c3_defconfig b/arch/m68knommu/configs/m5272c3_defconfig
index 5985a3b..4e6ea50 100644
--- a/arch/m68knommu/configs/m5272c3_defconfig
+++ b/arch/m68knommu/configs/m5272c3_defconfig
@@ -1,7 +1,7 @@
CONFIG_EXPERIMENTAL=y
CONFIG_LOG_BUF_SHIFT=14
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_KALLSYMS is not set
# CONFIG_HOTPLUG is not set
# CONFIG_FUTEX is not set
diff --git a/arch/m68knommu/configs/m5275evb_defconfig b/arch/m68knommu/configs/m5275evb_defconfig
index 5a7857e..f3dd741 100644
--- a/arch/m68knommu/configs/m5275evb_defconfig
+++ b/arch/m68knommu/configs/m5275evb_defconfig
@@ -1,7 +1,7 @@
CONFIG_EXPERIMENTAL=y
CONFIG_LOG_BUF_SHIFT=14
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_KALLSYMS is not set
# CONFIG_HOTPLUG is not set
# CONFIG_FUTEX is not set
diff --git a/arch/m68knommu/configs/m5307c3_defconfig b/arch/m68knommu/configs/m5307c3_defconfig
index e810201..bce0a20 100644
--- a/arch/m68knommu/configs/m5307c3_defconfig
+++ b/arch/m68knommu/configs/m5307c3_defconfig
@@ -1,7 +1,7 @@
CONFIG_EXPERIMENTAL=y
CONFIG_LOG_BUF_SHIFT=14
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_KALLSYMS is not set
# CONFIG_HOTPLUG is not set
# CONFIG_FUTEX is not set
diff --git a/arch/m68knommu/configs/m5407c3_defconfig b/arch/m68knommu/configs/m5407c3_defconfig
index 5c124a7..618cc32 100644
--- a/arch/m68knommu/configs/m5407c3_defconfig
+++ b/arch/m68knommu/configs/m5407c3_defconfig
@@ -1,7 +1,7 @@
CONFIG_EXPERIMENTAL=y
CONFIG_LOG_BUF_SHIFT=14
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_KALLSYMS is not set
# CONFIG_HOTPLUG is not set
# CONFIG_FUTEX is not set
diff --git a/arch/m68knommu/defconfig b/arch/m68knommu/defconfig
index 6ac2981..2f5655c 100644
--- a/arch/m68knommu/defconfig
+++ b/arch/m68knommu/defconfig
@@ -1,7 +1,7 @@
CONFIG_EXPERIMENTAL=y
CONFIG_LOG_BUF_SHIFT=14
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_KALLSYMS is not set
# CONFIG_HOTPLUG is not set
# CONFIG_FUTEX is not set
diff --git a/arch/m68knommu/kernel/setup.c b/arch/m68knommu/kernel/setup.c
index c684adf..16b2de7 100644
--- a/arch/m68knommu/kernel/setup.c
+++ b/arch/m68knommu/kernel/setup.c
@@ -55,55 +55,29 @@ void (*mach_halt)(void);
void (*mach_power_off)(void);
#ifdef CONFIG_M68328
- #define CPU "MC68328"
+#define CPU_NAME "MC68328"
#endif
#ifdef CONFIG_M68EZ328
- #define CPU "MC68EZ328"
+#define CPU_NAME "MC68EZ328"
#endif
#ifdef CONFIG_M68VZ328
- #define CPU "MC68VZ328"
+#define CPU_NAME "MC68VZ328"
#endif
#ifdef CONFIG_M68360
- #define CPU "MC68360"
+#define CPU_NAME "MC68360"
#endif
-#if defined(CONFIG_M5206)
- #define CPU "COLDFIRE(m5206)"
+#ifndef CPU_NAME
+#define CPU_NAME "UNKNOWN"
#endif
-#if defined(CONFIG_M5206e)
- #define CPU "COLDFIRE(m5206e)"
-#endif
-#if defined(CONFIG_M520x)
- #define CPU "COLDFIRE(m520x)"
-#endif
-#if defined(CONFIG_M523x)
- #define CPU "COLDFIRE(m523x)"
-#endif
-#if defined(CONFIG_M5249)
- #define CPU "COLDFIRE(m5249)"
-#endif
-#if defined(CONFIG_M5271)
- #define CPU "COLDFIRE(m5270/5271)"
-#endif
-#if defined(CONFIG_M5272)
- #define CPU "COLDFIRE(m5272)"
-#endif
-#if defined(CONFIG_M5275)
- #define CPU "COLDFIRE(m5274/5275)"
-#endif
-#if defined(CONFIG_M528x)
- #define CPU "COLDFIRE(m5280/5282)"
-#endif
-#if defined(CONFIG_M5307)
- #define CPU "COLDFIRE(m5307)"
-#endif
-#if defined(CONFIG_M532x)
- #define CPU "COLDFIRE(m532x)"
-#endif
-#if defined(CONFIG_M5407)
- #define CPU "COLDFIRE(m5407)"
-#endif
-#ifndef CPU
- #define CPU "UNKNOWN"
+
+/*
+ * Different cores have different instruction execution timings.
+ * The old/traditional 68000 cores are basically all the same, at 16.
+ * The ColdFire cores vary a little, their values are defined in their
+ * headers. We default to the standard 68000 value here.
+ */
+#ifndef CPU_INSTR_PER_JIFFY
+#define CPU_INSTR_PER_JIFFY 16
#endif
extern int _stext, _etext, _sdata, _edata, _sbss, _ebss, _end;
@@ -208,7 +182,7 @@ void __init setup_arch(char **cmdline_p)
command_line[sizeof(command_line) - 1] = 0;
#endif /* CONFIG_UBOOT */
- printk(KERN_INFO "\x0F\r\n\nuClinux/" CPU "\n");
+ printk(KERN_INFO "\x0F\r\n\nuClinux/" CPU_NAME "\n");
#ifdef CONFIG_UCDIMM
printk(KERN_INFO "uCdimm by Lineo, Inc. <www.lineo.com>\n");
@@ -257,11 +231,6 @@ void __init setup_arch(char **cmdline_p)
memcpy(boot_command_line, command_line, COMMAND_LINE_SIZE);
boot_command_line[COMMAND_LINE_SIZE-1] = 0;
-#ifdef DEBUG
- if (strlen(*cmdline_p))
- printk(KERN_DEBUG "Command line: '%s'\n", *cmdline_p);
-#endif
-
#if defined(CONFIG_FRAMEBUFFER_CONSOLE) && defined(CONFIG_DUMMY_CONSOLE)
conswitchp = &dummy_con;
#endif
@@ -303,15 +272,10 @@ static int show_cpuinfo(struct seq_file *m, void *v)
char *cpu, *mmu, *fpu;
u_long clockfreq;
- cpu = CPU;
+ cpu = CPU_NAME;
mmu = "none";
fpu = "none";
-
-#ifdef CONFIG_COLDFIRE
- clockfreq = (loops_per_jiffy * HZ) * 3;
-#else
- clockfreq = (loops_per_jiffy * HZ) * 16;
-#endif
+ clockfreq = (loops_per_jiffy * HZ) * CPU_INSTR_PER_JIFFY;
seq_printf(m, "CPU:\t\t%s\n"
"MMU:\t\t%s\n"
diff --git a/arch/m68knommu/mm/Makefile b/arch/m68knommu/mm/Makefile
index fc91f25..b54ab6b 100644
--- a/arch/m68knommu/mm/Makefile
+++ b/arch/m68knommu/mm/Makefile
@@ -2,4 +2,4 @@
# Makefile for the linux m68knommu specific parts of the memory manager.
#
-obj-y += init.o fault.o memory.o kmap.o
+obj-y += init.o kmap.o
diff --git a/arch/m68knommu/mm/fault.c b/arch/m68knommu/mm/fault.c
deleted file mode 100644
index bc05cf7..0000000
--- a/arch/m68knommu/mm/fault.c
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * linux/arch/m68knommu/mm/fault.c
- *
- * Copyright (C) 1998 D. Jeff Dionne <jeff@lineo.ca>,
- * Copyright (C) 2000 Lineo, Inc. (www.lineo.com)
- *
- * Based on:
- *
- * linux/arch/m68k/mm/fault.c
- *
- * Copyright (C) 1995 Hamish Macdonald
- */
-
-#include <linux/mman.h>
-#include <linux/mm.h>
-#include <linux/kernel.h>
-#include <linux/ptrace.h>
-
-#include <asm/system.h>
-#include <asm/pgtable.h>
-
-extern void die_if_kernel(char *, struct pt_regs *, long);
-
-/*
- * This routine handles page faults. It determines the problem, and
- * then passes it off to one of the appropriate routines.
- *
- * error_code:
- * bit 0 == 0 means no page found, 1 means protection fault
- * bit 1 == 0 means read, 1 means write
- *
- * If this routine detects a bad access, it returns 1, otherwise it
- * returns 0.
- */
-asmlinkage int do_page_fault(struct pt_regs *regs, unsigned long address,
- unsigned long error_code)
-{
-#ifdef DEBUG
- printk(KERN_DEBUG "regs->sr=%#x, regs->pc=%#lx, address=%#lx, %ld\n",
- regs->sr, regs->pc, address, error_code);
-#endif
-
- /*
- * Oops. The kernel tried to access some bad page. We'll have to
- * terminate things with extreme prejudice.
- */
- if ((unsigned long) address < PAGE_SIZE)
- printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference");
- else
- printk(KERN_ALERT "Unable to handle kernel access");
- printk(KERN_ALERT " at virtual address %08lx\n", address);
- die_if_kernel("Oops", regs, error_code);
- do_exit(SIGKILL);
-
- return 1;
-}
-
diff --git a/arch/m68knommu/mm/kmap.c b/arch/m68knommu/mm/kmap.c
index 902c1df..ece8d5a 100644
--- a/arch/m68knommu/mm/kmap.c
+++ b/arch/m68knommu/mm/kmap.c
@@ -36,15 +36,6 @@ void iounmap(void *addr)
}
/*
- * __iounmap unmaps nearly everything, so be careful
- * it doesn't free currently pointer/page tables anymore but it
- * wans't used anyway and might be added later.
- */
-void __iounmap(void *addr, unsigned long size)
-{
-}
-
-/*
* Set new cache mode for some kernel address space.
* The caller must push data for that range itself, if such data may already
* be in the cache.
diff --git a/arch/m68knommu/mm/memory.c b/arch/m68knommu/mm/memory.c
deleted file mode 100644
index 8f7949e..0000000
--- a/arch/m68knommu/mm/memory.c
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * linux/arch/m68knommu/mm/memory.c
- *
- * Copyright (C) 1998 Kenneth Albanowski <kjahds@kjahds.com>,
- * Copyright (C) 1999-2002, Greg Ungerer (gerg@snapgear.com)
- *
- * Based on:
- *
- * linux/arch/m68k/mm/memory.c
- *
- * Copyright (C) 1995 Hamish Macdonald
- */
-
-#include <linux/mm.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/types.h>
-
-#include <asm/segment.h>
-#include <asm/page.h>
-#include <asm/pgtable.h>
-#include <asm/system.h>
-
-/*
- * Map some physical address range into the kernel address space.
- */
-
-unsigned long kernel_map(unsigned long paddr, unsigned long size,
- int nocacheflag, unsigned long *memavailp )
-{
- return paddr;
-}
-
diff --git a/arch/m68knommu/platform/548x/Makefile b/arch/m68knommu/platform/54xx/Makefile
index e6035e7..e6035e7 100644
--- a/arch/m68knommu/platform/548x/Makefile
+++ b/arch/m68knommu/platform/54xx/Makefile
diff --git a/arch/m68knommu/platform/548x/config.c b/arch/m68knommu/platform/54xx/config.c
index 9888846..7813098 100644
--- a/arch/m68knommu/platform/548x/config.c
+++ b/arch/m68knommu/platform/54xx/config.c
@@ -1,7 +1,7 @@
/***************************************************************************/
/*
- * linux/arch/m68knommu/platform/548x/config.c
+ * linux/arch/m68knommu/platform/54xx/config.c
*
* Copyright (C) 2010, Philippe De Muyter <phdm@macqel.be>
*/
@@ -15,13 +15,13 @@
#include <linux/io.h>
#include <asm/machdep.h>
#include <asm/coldfire.h>
-#include <asm/m548xsim.h>
+#include <asm/m54xxsim.h>
#include <asm/mcfuart.h>
-#include <asm/m548xgpt.h>
+#include <asm/m54xxgpt.h>
/***************************************************************************/
-static struct mcf_platform_uart m548x_uart_platform[] = {
+static struct mcf_platform_uart m54xx_uart_platform[] = {
{
.mapbase = MCF_MBAR + MCFUART_BASE1,
.irq = 64 + 35,
@@ -40,20 +40,20 @@ static struct mcf_platform_uart m548x_uart_platform[] = {
},
};
-static struct platform_device m548x_uart = {
+static struct platform_device m54xx_uart = {
.name = "mcfuart",
.id = 0,
- .dev.platform_data = m548x_uart_platform,
+ .dev.platform_data = m54xx_uart_platform,
};
-static struct platform_device *m548x_devices[] __initdata = {
- &m548x_uart,
+static struct platform_device *m54xx_devices[] __initdata = {
+ &m54xx_uart,
};
/***************************************************************************/
-static void __init m548x_uart_init_line(int line, int irq)
+static void __init m54xx_uart_init_line(int line, int irq)
{
int rts_cts;
@@ -72,18 +72,18 @@ static void __init m548x_uart_init_line(int line, int irq)
MCF_MBAR + MCF_PAR_PSC(line));
}
-static void __init m548x_uarts_init(void)
+static void __init m54xx_uarts_init(void)
{
- const int nrlines = ARRAY_SIZE(m548x_uart_platform);
+ const int nrlines = ARRAY_SIZE(m54xx_uart_platform);
int line;
for (line = 0; (line < nrlines); line++)
- m548x_uart_init_line(line, m548x_uart_platform[line].irq);
+ m54xx_uart_init_line(line, m54xx_uart_platform[line].irq);
}
/***************************************************************************/
-static void mcf548x_reset(void)
+static void mcf54xx_reset(void)
{
/* disable interrupts and enable the watchdog */
asm("movew #0x2700, %sr\n");
@@ -97,8 +97,8 @@ static void mcf548x_reset(void)
void __init config_BSP(char *commandp, int size)
{
- mach_reset = mcf548x_reset;
- m548x_uarts_init();
+ mach_reset = mcf54xx_reset;
+ m54xx_uarts_init();
}
/***************************************************************************/
@@ -106,7 +106,7 @@ void __init config_BSP(char *commandp, int size)
static int __init init_BSP(void)
{
- platform_add_devices(m548x_devices, ARRAY_SIZE(m548x_devices));
+ platform_add_devices(m54xx_devices, ARRAY_SIZE(m54xx_devices));
return 0;
}
diff --git a/arch/m68knommu/platform/68328/ints.c b/arch/m68knommu/platform/68328/ints.c
index 8658528..2a3af19 100644
--- a/arch/m68knommu/platform/68328/ints.c
+++ b/arch/m68knommu/platform/68328/ints.c
@@ -179,8 +179,8 @@ void __init init_IRQ(void)
IMR = ~0;
for (i = 0; (i < NR_IRQS); i++) {
- set_irq_chip(irq, &intc_irq_chip);
- set_irq_handler(irq, handle_level_irq);
+ set_irq_chip(i, &intc_irq_chip);
+ set_irq_handler(i, handle_level_irq);
}
}
diff --git a/arch/m68knommu/platform/coldfire/Makefile b/arch/m68knommu/platform/coldfire/Makefile
index 45f501f..a8967ba 100644
--- a/arch/m68knommu/platform/coldfire/Makefile
+++ b/arch/m68knommu/platform/coldfire/Makefile
@@ -14,7 +14,7 @@
asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1
-obj-$(CONFIG_COLDFIRE) += clk.o dma.o entry.o vectors.o
+obj-$(CONFIG_COLDFIRE) += cache.o clk.o dma.o entry.o vectors.o
obj-$(CONFIG_M5206) += timers.o intc.o
obj-$(CONFIG_M5206e) += timers.o intc.o
obj-$(CONFIG_M520x) += pit.o intc-simr.o
@@ -26,7 +26,7 @@ obj-$(CONFIG_M528x) += pit.o intc-2.o
obj-$(CONFIG_M5307) += timers.o intc.o
obj-$(CONFIG_M532x) += timers.o intc-simr.o
obj-$(CONFIG_M5407) += timers.o intc.o
-obj-$(CONFIG_M548x) += sltimers.o intc-2.o
+obj-$(CONFIG_M54xx) += sltimers.o intc-2.o
obj-y += pinmux.o gpio.o
extra-y := head.o
diff --git a/arch/m68knommu/platform/coldfire/cache.c b/arch/m68knommu/platform/coldfire/cache.c
new file mode 100644
index 0000000..235d3c4
--- /dev/null
+++ b/arch/m68knommu/platform/coldfire/cache.c
@@ -0,0 +1,48 @@
+/***************************************************************************/
+
+/*
+ * cache.c -- general ColdFire Cache maintainence code
+ *
+ * Copyright (C) 2010, Greg Ungerer (gerg@snapgear.com)
+ */
+
+/***************************************************************************/
+
+#include <linux/kernel.h>
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+
+/***************************************************************************/
+#ifdef CACHE_PUSH
+/***************************************************************************/
+
+/*
+ * Use cpushl to push all dirty cache lines back to memory.
+ * Older versions of GAS don't seem to know how to generate the
+ * ColdFire cpushl instruction... Oh well, bit stuff it for now.
+ */
+
+void mcf_cache_push(void)
+{
+ __asm__ __volatile__ (
+ "clrl %%d0\n\t"
+ "1:\n\t"
+ "movel %%d0,%%a0\n\t"
+ "2:\n\t"
+ ".word 0xf468\n\t"
+ "addl %0,%%a0\n\t"
+ "cmpl %1,%%a0\n\t"
+ "blt 2b\n\t"
+ "addql #1,%%d0\n\t"
+ "cmpil %2,%%d0\n\t"
+ "bne 1b\n\t"
+ : /* No output */
+ : "i" (CACHE_LINE_SIZE),
+ "i" (DCACHE_SIZE / CACHE_WAYS),
+ "i" (CACHE_WAYS)
+ : "d0", "a0" );
+}
+
+/***************************************************************************/
+#endif /* CACHE_PUSH */
+/***************************************************************************/
diff --git a/arch/m68knommu/platform/coldfire/entry.S b/arch/m68knommu/platform/coldfire/entry.S
index e1debc8..4ddfc3da 100644
--- a/arch/m68knommu/platform/coldfire/entry.S
+++ b/arch/m68knommu/platform/coldfire/entry.S
@@ -36,13 +36,16 @@
#include <asm/asm-offsets.h>
#include <asm/entry.h>
+#ifdef CONFIG_COLDFIRE_SW_A7
+/*
+ * Define software copies of the supervisor and user stack pointers.
+ */
.bss
-
sw_ksp:
.long 0
-
sw_usp:
.long 0
+#endif /* CONFIG_COLDFIRE_SW_A7 */
.text
@@ -51,7 +54,6 @@ sw_usp:
.globl ret_from_exception
.globl ret_from_signal
.globl sys_call_table
-.globl ret_from_interrupt
.globl inthandler
.globl fasthandler
@@ -140,20 +142,7 @@ Luser_return:
jne Lwork_to_do /* still work to do */
Lreturn:
- move #0x2700,%sr /* disable intrs */
- movel sw_usp,%a0 /* get usp */
- movel %sp@(PT_OFF_PC),%a0@- /* copy exception program counter */
- movel %sp@(PT_OFF_FORMATVEC),%a0@- /* copy exception format/vector/sr */
- moveml %sp@,%d1-%d5/%a0-%a2
- lea %sp@(32),%sp /* space for 8 regs */
- movel %sp@+,%d0
- addql #4,%sp /* orig d0 */
- addl %sp@+,%sp /* stk adj */
- addql #8,%sp /* remove exception */
- movel %sp,sw_ksp /* save ksp */
- subql #8,sw_usp /* set exception */
- movel sw_usp,%sp /* restore usp */
- rte
+ RESTORE_USER
Lwork_to_do:
movel %a0@(TI_FLAGS),%d1 /* get thread_info->flags */
@@ -191,31 +180,7 @@ ENTRY(inthandler)
jbsr do_IRQ /* call high level irq handler */
lea %sp@(8),%sp /* pop args off stack */
- bra ret_from_interrupt /* this was fallthrough */
-
-/*
- * This is the fast interrupt handler (for certain hardware interrupt
- * sources). Unlike the normal interrupt handler it just uses the
- * current stack (doesn't care if it is user or kernel). It also
- * doesn't bother doing the bottom half handlers.
- */
-ENTRY(fasthandler)
- SAVE_LOCAL
-
- movew %sp@(PT_OFF_FORMATVEC),%d0
- andl #0x03fc,%d0 /* mask out vector only */
-
- movel %sp,%sp@- /* push regs arg */
- lsrl #2,%d0 /* calculate real vector # */
- movel %d0,%sp@- /* push vector number */
- jbsr do_IRQ /* call high level irq handler */
- lea %sp@(8),%sp /* pop args off stack */
-
- RESTORE_LOCAL
-
-ENTRY(ret_from_interrupt)
- /* the fasthandler is confusing me, haven't seen any user */
- jmp ret_from_exception
+ bra ret_from_exception
/*
* Beware - when entering resume, prev (the current task) is
@@ -226,9 +191,8 @@ ENTRY(ret_from_interrupt)
*/
ENTRY(resume)
movel %a0, %d1 /* get prev thread in d1 */
-
- movel sw_usp,%d0 /* save usp */
- movel %d0,%a0@(TASK_THREAD+THREAD_USP)
+ RDUSP
+ movel %a2,%a0@(TASK_THREAD+THREAD_USP)
SAVE_SWITCH_STACK
movel %sp,%a0@(TASK_THREAD+THREAD_KSP) /* save kernel stack pointer */
@@ -236,5 +200,5 @@ ENTRY(resume)
RESTORE_SWITCH_STACK
movel %a1@(TASK_THREAD+THREAD_USP),%a0 /* restore thread user stack */
- movel %a0, sw_usp
+ WRUSP
rts
diff --git a/arch/m68knommu/platform/coldfire/head.S b/arch/m68knommu/platform/coldfire/head.S
index 0b2d7c7..d597790 100644
--- a/arch/m68knommu/platform/coldfire/head.S
+++ b/arch/m68knommu/platform/coldfire/head.S
@@ -3,7 +3,7 @@
/*
* head.S -- common startup code for ColdFire CPUs.
*
- * (C) Copyright 1999-2006, Greg Ungerer <gerg@snapgear.com>.
+ * (C) Copyright 1999-2010, Greg Ungerer <gerg@snapgear.com>.
*/
/*****************************************************************************/
@@ -13,7 +13,6 @@
#include <linux/init.h>
#include <asm/asm-offsets.h>
#include <asm/coldfire.h>
-#include <asm/mcfcache.h>
#include <asm/mcfsim.h>
#include <asm/thread_info.h>
@@ -173,10 +172,27 @@ _start:
/*
* Now that we know what the memory is, lets enable cache
- * and get things moving. This is Coldfire CPU specific.
+ * and get things moving. This is Coldfire CPU specific. Not
+ * all version cores have identical cache register setup. But
+ * it is very similar. Define the exact settings in the headers
+ * then the code here is the same for all.
*/
- CACHE_ENABLE /* enable CPU cache */
-
+ movel #CACHE_INIT,%d0 /* invalidate whole cache */
+ movec %d0,%CACR
+ nop
+ movel #ACR0_MODE,%d0 /* set RAM region for caching */
+ movec %d0,%ACR0
+ movel #ACR1_MODE,%d0 /* anything else to cache? */
+ movec %d0,%ACR1
+#ifdef ACR2_MODE
+ movel #ACR2_MODE,%d0
+ movec %d0,%ACR2
+ movel #ACR3_MODE,%d0
+ movec %d0,%ACR3
+#endif
+ movel #CACHE_MODE,%d0 /* enable cache */
+ movec %d0,%CACR
+ nop
#ifdef CONFIG_ROMFS_FS
/*
diff --git a/arch/microblaze/Kconfig b/arch/microblaze/Kconfig
index 5f5018a..3168003 100644
--- a/arch/microblaze/Kconfig
+++ b/arch/microblaze/Kconfig
@@ -15,6 +15,8 @@ config MICROBLAZE
select TRACING_SUPPORT
select OF
select OF_EARLY_FLATTREE
+ select HAVE_GENERIC_HARDIRQS
+ select GENERIC_IRQ_PROBE
config SWAP
def_bool n
@@ -37,12 +39,6 @@ config GENERIC_FIND_NEXT_BIT
config GENERIC_HWEIGHT
def_bool y
-config GENERIC_HARDIRQS
- def_bool y
-
-config GENERIC_IRQ_PROBE
- def_bool y
-
config GENERIC_CALIBRATE_DELAY
def_bool y
@@ -52,9 +48,6 @@ config GENERIC_TIME_VSYSCALL
config GENERIC_CLOCKEVENTS
def_bool y
-config GENERIC_HARDIRQS_NO__DO_IRQ
- def_bool y
-
config GENERIC_GPIO
def_bool y
diff --git a/arch/microblaze/configs/mmu_defconfig b/arch/microblaze/configs/mmu_defconfig
index ab8fbe7..b3f5eec 100644
--- a/arch/microblaze/configs/mmu_defconfig
+++ b/arch/microblaze/configs/mmu_defconfig
@@ -7,7 +7,7 @@ CONFIG_BLK_DEV_INITRD=y
CONFIG_INITRAMFS_SOURCE="rootfs.cpio"
CONFIG_INITRAMFS_COMPRESSION_GZIP=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
CONFIG_KALLSYMS_ALL=y
CONFIG_KALLSYMS_EXTRA_PASS=y
# CONFIG_HOTPLUG is not set
diff --git a/arch/microblaze/configs/nommu_defconfig b/arch/microblaze/configs/nommu_defconfig
index ebc143c..0249e4b 100644
--- a/arch/microblaze/configs/nommu_defconfig
+++ b/arch/microblaze/configs/nommu_defconfig
@@ -6,7 +6,7 @@ CONFIG_BSD_PROCESS_ACCT_V3=y
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
CONFIG_KALLSYMS_ALL=y
CONFIG_KALLSYMS_EXTRA_PASS=y
# CONFIG_HOTPLUG is not set
diff --git a/arch/microblaze/include/asm/pgtable.h b/arch/microblaze/include/asm/pgtable.h
index cae268c2..b23f680 100644
--- a/arch/microblaze/include/asm/pgtable.h
+++ b/arch/microblaze/include/asm/pgtable.h
@@ -444,8 +444,9 @@ static inline void set_pte_at(struct mm_struct *mm, unsigned long addr,
*ptep = pte;
}
-static inline int ptep_test_and_clear_young(struct mm_struct *mm,
- unsigned long addr, pte_t *ptep)
+#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG
+static inline int ptep_test_and_clear_young(struct vm_area_struct *vma,
+ unsigned long address, pte_t *ptep)
{
return (pte_update(ptep, _PAGE_ACCESSED, 0) & _PAGE_ACCESSED) != 0;
}
@@ -457,6 +458,7 @@ static inline int ptep_test_and_clear_dirty(struct mm_struct *mm,
(_PAGE_DIRTY | _PAGE_HWWRITE), 0) & _PAGE_DIRTY) != 0;
}
+#define __HAVE_ARCH_PTEP_GET_AND_CLEAR
static inline pte_t ptep_get_and_clear(struct mm_struct *mm,
unsigned long addr, pte_t *ptep)
{
diff --git a/arch/microblaze/include/asm/tlb.h b/arch/microblaze/include/asm/tlb.h
index e8abd4a..8aa9781 100644
--- a/arch/microblaze/include/asm/tlb.h
+++ b/arch/microblaze/include/asm/tlb.h
@@ -13,6 +13,7 @@
#define tlb_flush(tlb) flush_tlb_mm((tlb)->mm)
+#include <linux/pagemap.h>
#include <asm-generic/tlb.h>
#ifdef CONFIG_MMU
diff --git a/arch/microblaze/kernel/prom.c b/arch/microblaze/kernel/prom.c
index c881393..bceaa55 100644
--- a/arch/microblaze/kernel/prom.c
+++ b/arch/microblaze/kernel/prom.c
@@ -47,9 +47,9 @@ void __init early_init_dt_add_memory_arch(u64 base, u64 size)
memblock_add(base, size);
}
-u64 __init early_init_dt_alloc_memory_arch(u64 size, u64 align)
+void * __init early_init_dt_alloc_memory_arch(u64 size, u64 align)
{
- return memblock_alloc(size, align);
+ return __va(memblock_alloc(size, align));
}
#ifdef CONFIG_EARLY_PRINTK
diff --git a/arch/mips/Kbuild.platforms b/arch/mips/Kbuild.platforms
index 78439b8..7ff9b54 100644
--- a/arch/mips/Kbuild.platforms
+++ b/arch/mips/Kbuild.platforms
@@ -2,6 +2,7 @@
platforms += alchemy
platforms += ar7
+platforms += ath79
platforms += bcm47xx
platforms += bcm63xx
platforms += cavium-octeon
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index f489ec3..f5ecc05 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -21,6 +21,7 @@ config MIPS
select HAVE_DMA_API_DEBUG
select HAVE_GENERIC_HARDIRQS
select GENERIC_IRQ_PROBE
+ select HAVE_ARCH_JUMP_LABEL
menu "Machine selection"
@@ -65,6 +66,22 @@ config AR7
Support for the Texas Instruments AR7 System-on-a-Chip
family: TNETD7100, 7200 and 7300.
+config ATH79
+ bool "Atheros AR71XX/AR724X/AR913X based boards"
+ select ARCH_REQUIRE_GPIOLIB
+ select BOOT_RAW
+ select CEVT_R4K
+ select CSRC_R4K
+ select DMA_NONCOHERENT
+ select IRQ_CPU
+ select MIPS_MACHINE
+ select SYS_HAS_CPU_MIPS32_R2
+ select SYS_HAS_EARLY_PRINTK
+ select SYS_SUPPORTS_32BIT_KERNEL
+ select SYS_SUPPORTS_BIG_ENDIAN
+ help
+ Support for the Atheros AR71XX/AR724X/AR913X SoCs.
+
config BCM47XX
bool "Broadcom BCM47XX based boards"
select CEVT_R4K
@@ -717,6 +734,7 @@ config CAVIUM_OCTEON_REFERENCE_BOARD
endchoice
source "arch/mips/alchemy/Kconfig"
+source "arch/mips/ath79/Kconfig"
source "arch/mips/bcm63xx/Kconfig"
source "arch/mips/jazz/Kconfig"
source "arch/mips/jz4740/Kconfig"
@@ -775,9 +793,6 @@ config SCHED_OMIT_FRAME_POINTER
bool
default y
-config GENERIC_HARDIRQS_NO__DO_IRQ
- def_bool y
-
#
# Select some configuration options automatically based on user selections.
#
@@ -883,6 +898,9 @@ config MIPS_DISABLE_OBSOLETE_IDE
config SYNC_R4K
bool
+config MIPS_MACHINE
+ def_bool n
+
config NO_IOPORT
def_bool n
@@ -2400,4 +2418,20 @@ source "security/Kconfig"
source "crypto/Kconfig"
+menuconfig VIRTUALIZATION
+ bool "Virtualization"
+ default n
+ ---help---
+ Say Y here to get to see options for using your Linux host to run other
+ operating systems inside virtual machines (guests).
+ This option alone does not add any kernel code.
+
+ If you say N, all options in this submenu will be skipped and disabled.
+
+if VIRTUALIZATION
+
+source drivers/virtio/Kconfig
+
+endif # VIRTUALIZATION
+
source "lib/Kconfig"
diff --git a/arch/mips/Kconfig.debug b/arch/mips/Kconfig.debug
index f437cd1..5358f90 100644
--- a/arch/mips/Kconfig.debug
+++ b/arch/mips/Kconfig.debug
@@ -7,7 +7,7 @@ config TRACE_IRQFLAGS_SUPPORT
source "lib/Kconfig.debug"
config EARLY_PRINTK
- bool "Early printk" if EMBEDDED
+ bool "Early printk" if EXPERT
depends on SYS_HAS_EARLY_PRINTK
default y
help
diff --git a/arch/mips/ath79/Kconfig b/arch/mips/ath79/Kconfig
new file mode 100644
index 0000000..b058282
--- /dev/null
+++ b/arch/mips/ath79/Kconfig
@@ -0,0 +1,50 @@
+if ATH79
+
+menu "Atheros AR71XX/AR724X/AR913X machine selection"
+
+config ATH79_MACH_AP81
+ bool "Atheros AP81 reference board"
+ select SOC_AR913X
+ select ATH79_DEV_AR913X_WMAC
+ select ATH79_DEV_GPIO_BUTTONS
+ select ATH79_DEV_LEDS_GPIO
+ select ATH79_DEV_SPI
+ help
+ Say 'Y' here if you want your kernel to support the
+ Atheros AP81 reference board.
+
+config ATH79_MACH_PB44
+ bool "Atheros PB44 reference board"
+ select SOC_AR71XX
+ select ATH79_DEV_GPIO_BUTTONS
+ select ATH79_DEV_LEDS_GPIO
+ select ATH79_DEV_SPI
+ help
+ Say 'Y' here if you want your kernel to support the
+ Atheros PB44 reference board.
+
+endmenu
+
+config SOC_AR71XX
+ def_bool n
+
+config SOC_AR724X
+ def_bool n
+
+config SOC_AR913X
+ def_bool n
+
+config ATH79_DEV_AR913X_WMAC
+ depends on SOC_AR913X
+ def_bool n
+
+config ATH79_DEV_GPIO_BUTTONS
+ def_bool n
+
+config ATH79_DEV_LEDS_GPIO
+ def_bool n
+
+config ATH79_DEV_SPI
+ def_bool n
+
+endif
diff --git a/arch/mips/ath79/Makefile b/arch/mips/ath79/Makefile
new file mode 100644
index 0000000..c33d465
--- /dev/null
+++ b/arch/mips/ath79/Makefile
@@ -0,0 +1,28 @@
+#
+# Makefile for the Atheros AR71XX/AR724X/AR913X specific parts of the kernel
+#
+# Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org>
+# Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
+#
+# 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.
+
+obj-y := prom.o setup.o irq.o common.o clock.o gpio.o
+
+obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
+
+#
+# Devices
+#
+obj-y += dev-common.o
+obj-$(CONFIG_ATH79_DEV_AR913X_WMAC) += dev-ar913x-wmac.o
+obj-$(CONFIG_ATH79_DEV_GPIO_BUTTONS) += dev-gpio-buttons.o
+obj-$(CONFIG_ATH79_DEV_LEDS_GPIO) += dev-leds-gpio.o
+obj-$(CONFIG_ATH79_DEV_SPI) += dev-spi.o
+
+#
+# Machines
+#
+obj-$(CONFIG_ATH79_MACH_AP81) += mach-ap81.o
+obj-$(CONFIG_ATH79_MACH_PB44) += mach-pb44.o
diff --git a/arch/mips/ath79/Platform b/arch/mips/ath79/Platform
new file mode 100644
index 0000000..2bd6636
--- /dev/null
+++ b/arch/mips/ath79/Platform
@@ -0,0 +1,7 @@
+#
+# Atheros AR71xx/AR724x/AR913x
+#
+
+platform-$(CONFIG_ATH79) += ath79/
+cflags-$(CONFIG_ATH79) += -I$(srctree)/arch/mips/include/asm/mach-ath79
+load-$(CONFIG_ATH79) = 0xffffffff80060000
diff --git a/arch/mips/ath79/clock.c b/arch/mips/ath79/clock.c
new file mode 100644
index 0000000..680bde9
--- /dev/null
+++ b/arch/mips/ath79/clock.c
@@ -0,0 +1,183 @@
+/*
+ * Atheros AR71XX/AR724X/AR913X common routines
+ *
+ * Copyright (C) 2011 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * 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/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+
+#include <asm/mach-ath79/ath79.h>
+#include <asm/mach-ath79/ar71xx_regs.h>
+#include "common.h"
+
+#define AR71XX_BASE_FREQ 40000000
+#define AR724X_BASE_FREQ 5000000
+#define AR913X_BASE_FREQ 5000000
+
+struct clk {
+ unsigned long rate;
+};
+
+static struct clk ath79_ref_clk;
+static struct clk ath79_cpu_clk;
+static struct clk ath79_ddr_clk;
+static struct clk ath79_ahb_clk;
+static struct clk ath79_wdt_clk;
+static struct clk ath79_uart_clk;
+
+static void __init ar71xx_clocks_init(void)
+{
+ u32 pll;
+ u32 freq;
+ u32 div;
+
+ ath79_ref_clk.rate = AR71XX_BASE_FREQ;
+
+ pll = ath79_pll_rr(AR71XX_PLL_REG_CPU_CONFIG);
+
+ div = ((pll >> AR71XX_PLL_DIV_SHIFT) & AR71XX_PLL_DIV_MASK) + 1;
+ freq = div * ath79_ref_clk.rate;
+
+ div = ((pll >> AR71XX_CPU_DIV_SHIFT) & AR71XX_CPU_DIV_MASK) + 1;
+ ath79_cpu_clk.rate = freq / div;
+
+ div = ((pll >> AR71XX_DDR_DIV_SHIFT) & AR71XX_DDR_DIV_MASK) + 1;
+ ath79_ddr_clk.rate = freq / div;
+
+ div = (((pll >> AR71XX_AHB_DIV_SHIFT) & AR71XX_AHB_DIV_MASK) + 1) * 2;
+ ath79_ahb_clk.rate = ath79_cpu_clk.rate / div;
+
+ ath79_wdt_clk.rate = ath79_ahb_clk.rate;
+ ath79_uart_clk.rate = ath79_ahb_clk.rate;
+}
+
+static void __init ar724x_clocks_init(void)
+{
+ u32 pll;
+ u32 freq;
+ u32 div;
+
+ ath79_ref_clk.rate = AR724X_BASE_FREQ;
+ pll = ath79_pll_rr(AR724X_PLL_REG_CPU_CONFIG);
+
+ div = ((pll >> AR724X_PLL_DIV_SHIFT) & AR724X_PLL_DIV_MASK);
+ freq = div * ath79_ref_clk.rate;
+
+ div = ((pll >> AR724X_PLL_REF_DIV_SHIFT) & AR724X_PLL_REF_DIV_MASK);
+ freq *= div;
+
+ ath79_cpu_clk.rate = freq;
+
+ div = ((pll >> AR724X_DDR_DIV_SHIFT) & AR724X_DDR_DIV_MASK) + 1;
+ ath79_ddr_clk.rate = freq / div;
+
+ div = (((pll >> AR724X_AHB_DIV_SHIFT) & AR724X_AHB_DIV_MASK) + 1) * 2;
+ ath79_ahb_clk.rate = ath79_cpu_clk.rate / div;
+
+ ath79_wdt_clk.rate = ath79_ahb_clk.rate;
+ ath79_uart_clk.rate = ath79_ahb_clk.rate;
+}
+
+static void __init ar913x_clocks_init(void)
+{
+ u32 pll;
+ u32 freq;
+ u32 div;
+
+ ath79_ref_clk.rate = AR913X_BASE_FREQ;
+ pll = ath79_pll_rr(AR913X_PLL_REG_CPU_CONFIG);
+
+ div = ((pll >> AR913X_PLL_DIV_SHIFT) & AR913X_PLL_DIV_MASK);
+ freq = div * ath79_ref_clk.rate;
+
+ ath79_cpu_clk.rate = freq;
+
+ div = ((pll >> AR913X_DDR_DIV_SHIFT) & AR913X_DDR_DIV_MASK) + 1;
+ ath79_ddr_clk.rate = freq / div;
+
+ div = (((pll >> AR913X_AHB_DIV_SHIFT) & AR913X_AHB_DIV_MASK) + 1) * 2;
+ ath79_ahb_clk.rate = ath79_cpu_clk.rate / div;
+
+ ath79_wdt_clk.rate = ath79_ahb_clk.rate;
+ ath79_uart_clk.rate = ath79_ahb_clk.rate;
+}
+
+void __init ath79_clocks_init(void)
+{
+ if (soc_is_ar71xx())
+ ar71xx_clocks_init();
+ else if (soc_is_ar724x())
+ ar724x_clocks_init();
+ else if (soc_is_ar913x())
+ ar913x_clocks_init();
+ else
+ BUG();
+
+ pr_info("Clocks: CPU:%lu.%03luMHz, DDR:%lu.%03luMHz, AHB:%lu.%03luMHz, "
+ "Ref:%lu.%03luMHz",
+ ath79_cpu_clk.rate / 1000000,
+ (ath79_cpu_clk.rate / 1000) % 1000,
+ ath79_ddr_clk.rate / 1000000,
+ (ath79_ddr_clk.rate / 1000) % 1000,
+ ath79_ahb_clk.rate / 1000000,
+ (ath79_ahb_clk.rate / 1000) % 1000,
+ ath79_ref_clk.rate / 1000000,
+ (ath79_ref_clk.rate / 1000) % 1000);
+}
+
+/*
+ * Linux clock API
+ */
+struct clk *clk_get(struct device *dev, const char *id)
+{
+ if (!strcmp(id, "ref"))
+ return &ath79_ref_clk;
+
+ if (!strcmp(id, "cpu"))
+ return &ath79_cpu_clk;
+
+ if (!strcmp(id, "ddr"))
+ return &ath79_ddr_clk;
+
+ if (!strcmp(id, "ahb"))
+ return &ath79_ahb_clk;
+
+ if (!strcmp(id, "wdt"))
+ return &ath79_wdt_clk;
+
+ if (!strcmp(id, "uart"))
+ return &ath79_uart_clk;
+
+ return ERR_PTR(-ENOENT);
+}
+EXPORT_SYMBOL(clk_get);
+
+int clk_enable(struct clk *clk)
+{
+ return 0;
+}
+EXPORT_SYMBOL(clk_enable);
+
+void clk_disable(struct clk *clk)
+{
+}
+EXPORT_SYMBOL(clk_disable);
+
+unsigned long clk_get_rate(struct clk *clk)
+{
+ return clk->rate;
+}
+EXPORT_SYMBOL(clk_get_rate);
+
+void clk_put(struct clk *clk)
+{
+}
+EXPORT_SYMBOL(clk_put);
diff --git a/arch/mips/ath79/common.c b/arch/mips/ath79/common.c
new file mode 100644
index 0000000..58f60e7
--- /dev/null
+++ b/arch/mips/ath79/common.c
@@ -0,0 +1,97 @@
+/*
+ * Atheros AR71XX/AR724X/AR913X common routines
+ *
+ * Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org>
+ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
+ *
+ * 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/module.h>
+#include <linux/types.h>
+#include <linux/spinlock.h>
+
+#include <asm/mach-ath79/ath79.h>
+#include <asm/mach-ath79/ar71xx_regs.h>
+#include "common.h"
+
+static DEFINE_SPINLOCK(ath79_device_reset_lock);
+
+u32 ath79_cpu_freq;
+EXPORT_SYMBOL_GPL(ath79_cpu_freq);
+
+u32 ath79_ahb_freq;
+EXPORT_SYMBOL_GPL(ath79_ahb_freq);
+
+u32 ath79_ddr_freq;
+EXPORT_SYMBOL_GPL(ath79_ddr_freq);
+
+enum ath79_soc_type ath79_soc;
+
+void __iomem *ath79_pll_base;
+void __iomem *ath79_reset_base;
+EXPORT_SYMBOL_GPL(ath79_reset_base);
+void __iomem *ath79_ddr_base;
+
+void ath79_ddr_wb_flush(u32 reg)
+{
+ void __iomem *flush_reg = ath79_ddr_base + reg;
+
+ /* Flush the DDR write buffer. */
+ __raw_writel(0x1, flush_reg);
+ while (__raw_readl(flush_reg) & 0x1)
+ ;
+
+ /* It must be run twice. */
+ __raw_writel(0x1, flush_reg);
+ while (__raw_readl(flush_reg) & 0x1)
+ ;
+}
+EXPORT_SYMBOL_GPL(ath79_ddr_wb_flush);
+
+void ath79_device_reset_set(u32 mask)
+{
+ unsigned long flags;
+ u32 reg;
+ u32 t;
+
+ if (soc_is_ar71xx())
+ reg = AR71XX_RESET_REG_RESET_MODULE;
+ else if (soc_is_ar724x())
+ reg = AR724X_RESET_REG_RESET_MODULE;
+ else if (soc_is_ar913x())
+ reg = AR913X_RESET_REG_RESET_MODULE;
+ else
+ BUG();
+
+ spin_lock_irqsave(&ath79_device_reset_lock, flags);
+ t = ath79_reset_rr(reg);
+ ath79_reset_wr(reg, t | mask);
+ spin_unlock_irqrestore(&ath79_device_reset_lock, flags);
+}
+EXPORT_SYMBOL_GPL(ath79_device_reset_set);
+
+void ath79_device_reset_clear(u32 mask)
+{
+ unsigned long flags;
+ u32 reg;
+ u32 t;
+
+ if (soc_is_ar71xx())
+ reg = AR71XX_RESET_REG_RESET_MODULE;
+ else if (soc_is_ar724x())
+ reg = AR724X_RESET_REG_RESET_MODULE;
+ else if (soc_is_ar913x())
+ reg = AR913X_RESET_REG_RESET_MODULE;
+ else
+ BUG();
+
+ spin_lock_irqsave(&ath79_device_reset_lock, flags);
+ t = ath79_reset_rr(reg);
+ ath79_reset_wr(reg, t & ~mask);
+ spin_unlock_irqrestore(&ath79_device_reset_lock, flags);
+}
+EXPORT_SYMBOL_GPL(ath79_device_reset_clear);
diff --git a/arch/mips/ath79/common.h b/arch/mips/ath79/common.h
new file mode 100644
index 0000000..561906c
--- /dev/null
+++ b/arch/mips/ath79/common.h
@@ -0,0 +1,31 @@
+/*
+ * Atheros AR71XX/AR724X/AR913X common definitions
+ *
+ * Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org>
+ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
+ *
+ * Parts of this file are based on Atheros' 2.6.15 BSP
+ *
+ * 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 __ATH79_COMMON_H
+#define __ATH79_COMMON_H
+
+#include <linux/types.h>
+#include <linux/init.h>
+
+#define ATH79_MEM_SIZE_MIN (2 * 1024 * 1024)
+#define ATH79_MEM_SIZE_MAX (128 * 1024 * 1024)
+
+void ath79_clocks_init(void);
+void ath79_ddr_wb_flush(unsigned int reg);
+
+void ath79_gpio_function_enable(u32 mask);
+void ath79_gpio_function_disable(u32 mask);
+void ath79_gpio_function_setup(u32 set, u32 clear);
+void ath79_gpio_init(void);
+
+#endif /* __ATH79_COMMON_H */
diff --git a/arch/mips/ath79/dev-ar913x-wmac.c b/arch/mips/ath79/dev-ar913x-wmac.c
new file mode 100644
index 0000000..48f425a
--- /dev/null
+++ b/arch/mips/ath79/dev-ar913x-wmac.c
@@ -0,0 +1,60 @@
+/*
+ * Atheros AR913X SoC built-in WMAC device support
+ *
+ * Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org>
+ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
+ *
+ * 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/delay.h>
+#include <linux/irq.h>
+#include <linux/platform_device.h>
+#include <linux/ath9k_platform.h>
+
+#include <asm/mach-ath79/ath79.h>
+#include <asm/mach-ath79/ar71xx_regs.h>
+#include "dev-ar913x-wmac.h"
+
+static struct ath9k_platform_data ar913x_wmac_data;
+
+static struct resource ar913x_wmac_resources[] = {
+ {
+ .start = AR913X_WMAC_BASE,
+ .end = AR913X_WMAC_BASE + AR913X_WMAC_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+ }, {
+ .start = ATH79_CPU_IRQ_IP2,
+ .end = ATH79_CPU_IRQ_IP2,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device ar913x_wmac_device = {
+ .name = "ath9k",
+ .id = -1,
+ .resource = ar913x_wmac_resources,
+ .num_resources = ARRAY_SIZE(ar913x_wmac_resources),
+ .dev = {
+ .platform_data = &ar913x_wmac_data,
+ },
+};
+
+void __init ath79_register_ar913x_wmac(u8 *cal_data)
+{
+ if (cal_data)
+ memcpy(ar913x_wmac_data.eeprom_data, cal_data,
+ sizeof(ar913x_wmac_data.eeprom_data));
+
+ /* reset the WMAC */
+ ath79_device_reset_set(AR913X_RESET_AMBA2WMAC);
+ mdelay(10);
+
+ ath79_device_reset_clear(AR913X_RESET_AMBA2WMAC);
+ mdelay(10);
+
+ platform_device_register(&ar913x_wmac_device);
+}
diff --git a/arch/mips/ath79/dev-ar913x-wmac.h b/arch/mips/ath79/dev-ar913x-wmac.h
new file mode 100644
index 0000000..579d562
--- /dev/null
+++ b/arch/mips/ath79/dev-ar913x-wmac.h
@@ -0,0 +1,17 @@
+/*
+ * Atheros AR913X SoC built-in WMAC device support
+ *
+ * Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org>
+ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
+ *
+ * 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 _ATH79_DEV_AR913X_WMAC_H
+#define _ATH79_DEV_AR913X_WMAC_H
+
+void ath79_register_ar913x_wmac(u8 *cal_data);
+
+#endif /* _ATH79_DEV_AR913X_WMAC_H */
diff --git a/arch/mips/ath79/dev-common.c b/arch/mips/ath79/dev-common.c
new file mode 100644
index 0000000..3b82e32
--- /dev/null
+++ b/arch/mips/ath79/dev-common.c
@@ -0,0 +1,77 @@
+/*
+ * Atheros AR71XX/AR724X/AR913X common devices
+ *
+ * Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org>
+ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
+ *
+ * Parts of this file are based on Atheros' 2.6.15 BSP
+ *
+ * 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/init.h>
+#include <linux/platform_device.h>
+#include <linux/serial_8250.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+
+#include <asm/mach-ath79/ath79.h>
+#include <asm/mach-ath79/ar71xx_regs.h>
+#include "common.h"
+#include "dev-common.h"
+
+static struct resource ath79_uart_resources[] = {
+ {
+ .start = AR71XX_UART_BASE,
+ .end = AR71XX_UART_BASE + AR71XX_UART_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+#define AR71XX_UART_FLAGS (UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_IOREMAP)
+static struct plat_serial8250_port ath79_uart_data[] = {
+ {
+ .mapbase = AR71XX_UART_BASE,
+ .irq = ATH79_MISC_IRQ_UART,
+ .flags = AR71XX_UART_FLAGS,
+ .iotype = UPIO_MEM32,
+ .regshift = 2,
+ }, {
+ /* terminating entry */
+ }
+};
+
+static struct platform_device ath79_uart_device = {
+ .name = "serial8250",
+ .id = PLAT8250_DEV_PLATFORM,
+ .resource = ath79_uart_resources,
+ .num_resources = ARRAY_SIZE(ath79_uart_resources),
+ .dev = {
+ .platform_data = ath79_uart_data
+ },
+};
+
+void __init ath79_register_uart(void)
+{
+ struct clk *clk;
+
+ clk = clk_get(NULL, "uart");
+ if (IS_ERR(clk))
+ panic("unable to get UART clock, err=%ld", PTR_ERR(clk));
+
+ ath79_uart_data[0].uartclk = clk_get_rate(clk);
+ platform_device_register(&ath79_uart_device);
+}
+
+static struct platform_device ath79_wdt_device = {
+ .name = "ath79-wdt",
+ .id = -1,
+};
+
+void __init ath79_register_wdt(void)
+{
+ platform_device_register(&ath79_wdt_device);
+}
diff --git a/arch/mips/ath79/dev-common.h b/arch/mips/ath79/dev-common.h
new file mode 100644
index 0000000..0f514e1
--- /dev/null
+++ b/arch/mips/ath79/dev-common.h
@@ -0,0 +1,18 @@
+/*
+ * Atheros AR71XX/AR724X/AR913X common devices
+ *
+ * Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org>
+ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
+ *
+ * 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 _ATH79_DEV_COMMON_H
+#define _ATH79_DEV_COMMON_H
+
+void ath79_register_uart(void);
+void ath79_register_wdt(void);
+
+#endif /* _ATH79_DEV_COMMON_H */
diff --git a/arch/mips/ath79/dev-gpio-buttons.c b/arch/mips/ath79/dev-gpio-buttons.c
new file mode 100644
index 0000000..4b0168a
--- /dev/null
+++ b/arch/mips/ath79/dev-gpio-buttons.c
@@ -0,0 +1,58 @@
+/*
+ * Atheros AR71XX/AR724X/AR913X GPIO button support
+ *
+ * Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org>
+ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
+ *
+ * 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/slab.h"
+#include <linux/platform_device.h>
+
+#include "dev-gpio-buttons.h"
+
+void __init ath79_register_gpio_keys_polled(int id,
+ unsigned poll_interval,
+ unsigned nbuttons,
+ struct gpio_keys_button *buttons)
+{
+ struct platform_device *pdev;
+ struct gpio_keys_platform_data pdata;
+ struct gpio_keys_button *p;
+ int err;
+
+ p = kmalloc(nbuttons * sizeof(*p), GFP_KERNEL);
+ if (!p)
+ return;
+
+ memcpy(p, buttons, nbuttons * sizeof(*p));
+
+ pdev = platform_device_alloc("gpio-keys-polled", id);
+ if (!pdev)
+ goto err_free_buttons;
+
+ memset(&pdata, 0, sizeof(pdata));
+ pdata.poll_interval = poll_interval;
+ pdata.nbuttons = nbuttons;
+ pdata.buttons = p;
+
+ err = platform_device_add_data(pdev, &pdata, sizeof(pdata));
+ if (err)
+ goto err_put_pdev;
+
+ err = platform_device_add(pdev);
+ if (err)
+ goto err_put_pdev;
+
+ return;
+
+err_put_pdev:
+ platform_device_put(pdev);
+
+err_free_buttons:
+ kfree(p);
+}
diff --git a/arch/mips/ath79/dev-gpio-buttons.h b/arch/mips/ath79/dev-gpio-buttons.h
new file mode 100644
index 0000000..481847a
--- /dev/null
+++ b/arch/mips/ath79/dev-gpio-buttons.h
@@ -0,0 +1,23 @@
+/*
+ * Atheros AR71XX/AR724X/AR913X GPIO button support
+ *
+ * Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org>
+ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
+ *
+ * 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 _ATH79_DEV_GPIO_BUTTONS_H
+#define _ATH79_DEV_GPIO_BUTTONS_H
+
+#include <linux/input.h>
+#include <linux/gpio_keys.h>
+
+void ath79_register_gpio_keys_polled(int id,
+ unsigned poll_interval,
+ unsigned nbuttons,
+ struct gpio_keys_button *buttons);
+
+#endif /* _ATH79_DEV_GPIO_BUTTONS_H */
diff --git a/arch/mips/ath79/dev-leds-gpio.c b/arch/mips/ath79/dev-leds-gpio.c
new file mode 100644
index 0000000..cdade68
--- /dev/null
+++ b/arch/mips/ath79/dev-leds-gpio.c
@@ -0,0 +1,56 @@
+/*
+ * Atheros AR71XX/AR724X/AR913X common GPIO LEDs support
+ *
+ * Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org>
+ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
+ *
+ * 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/slab.h>
+#include <linux/platform_device.h>
+
+#include "dev-leds-gpio.h"
+
+void __init ath79_register_leds_gpio(int id,
+ unsigned num_leds,
+ struct gpio_led *leds)
+{
+ struct platform_device *pdev;
+ struct gpio_led_platform_data pdata;
+ struct gpio_led *p;
+ int err;
+
+ p = kmalloc(num_leds * sizeof(*p), GFP_KERNEL);
+ if (!p)
+ return;
+
+ memcpy(p, leds, num_leds * sizeof(*p));
+
+ pdev = platform_device_alloc("leds-gpio", id);
+ if (!pdev)
+ goto err_free_leds;
+
+ memset(&pdata, 0, sizeof(pdata));
+ pdata.num_leds = num_leds;
+ pdata.leds = p;
+
+ err = platform_device_add_data(pdev, &pdata, sizeof(pdata));
+ if (err)
+ goto err_put_pdev;
+
+ err = platform_device_add(pdev);
+ if (err)
+ goto err_put_pdev;
+
+ return;
+
+err_put_pdev:
+ platform_device_put(pdev);
+
+err_free_leds:
+ kfree(p);
+}
diff --git a/arch/mips/ath79/dev-leds-gpio.h b/arch/mips/ath79/dev-leds-gpio.h
new file mode 100644
index 0000000..6e5d885
--- /dev/null
+++ b/arch/mips/ath79/dev-leds-gpio.h
@@ -0,0 +1,21 @@
+/*
+ * Atheros AR71XX/AR724X/AR913X common GPIO LEDs support
+ *
+ * Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org>
+ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
+ *
+ * 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 _ATH79_DEV_LEDS_GPIO_H
+#define _ATH79_DEV_LEDS_GPIO_H
+
+#include <linux/leds.h>
+
+void ath79_register_leds_gpio(int id,
+ unsigned num_leds,
+ struct gpio_led *leds);
+
+#endif /* _ATH79_DEV_LEDS_GPIO_H */
diff --git a/arch/mips/ath79/dev-spi.c b/arch/mips/ath79/dev-spi.c
new file mode 100644
index 0000000..aa30163
--- /dev/null
+++ b/arch/mips/ath79/dev-spi.c
@@ -0,0 +1,38 @@
+/*
+ * Atheros AR71XX/AR724X/AR913X SPI controller device
+ *
+ * Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org>
+ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
+ *
+ * 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/platform_device.h>
+#include <asm/mach-ath79/ar71xx_regs.h>
+#include "dev-spi.h"
+
+static struct resource ath79_spi_resources[] = {
+ {
+ .start = AR71XX_SPI_BASE,
+ .end = AR71XX_SPI_BASE + AR71XX_SPI_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct platform_device ath79_spi_device = {
+ .name = "ath79-spi",
+ .id = -1,
+ .resource = ath79_spi_resources,
+ .num_resources = ARRAY_SIZE(ath79_spi_resources),
+};
+
+void __init ath79_register_spi(struct ath79_spi_platform_data *pdata,
+ struct spi_board_info const *info,
+ unsigned n)
+{
+ spi_register_board_info(info, n);
+ ath79_spi_device.dev.platform_data = pdata;
+ platform_device_register(&ath79_spi_device);
+}
diff --git a/arch/mips/ath79/dev-spi.h b/arch/mips/ath79/dev-spi.h
new file mode 100644
index 0000000..d732565
--- /dev/null
+++ b/arch/mips/ath79/dev-spi.h
@@ -0,0 +1,22 @@
+/*
+ * Atheros AR71XX/AR724X/AR913X SPI controller device
+ *
+ * Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org>
+ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
+ *
+ * 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 _ATH79_DEV_SPI_H
+#define _ATH79_DEV_SPI_H
+
+#include <linux/spi/spi.h>
+#include <asm/mach-ath79/ath79_spi_platform.h>
+
+void ath79_register_spi(struct ath79_spi_platform_data *pdata,
+ struct spi_board_info const *info,
+ unsigned n);
+
+#endif /* _ATH79_DEV_SPI_H */
diff --git a/arch/mips/ath79/early_printk.c b/arch/mips/ath79/early_printk.c
new file mode 100644
index 0000000..7499b0e
--- /dev/null
+++ b/arch/mips/ath79/early_printk.c
@@ -0,0 +1,36 @@
+/*
+ * Atheros AR71XX/AR724X/AR913X SoC early printk support
+ *
+ * Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org>
+ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
+ *
+ * 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/io.h>
+#include <linux/serial_reg.h>
+#include <asm/addrspace.h>
+
+#include <asm/mach-ath79/ar71xx_regs.h>
+
+static inline void prom_wait_thre(void __iomem *base)
+{
+ u32 lsr;
+
+ do {
+ lsr = __raw_readl(base + UART_LSR * 4);
+ if (lsr & UART_LSR_THRE)
+ break;
+ } while (1);
+}
+
+void prom_putchar(unsigned char ch)
+{
+ void __iomem *base = (void __iomem *)(KSEG1ADDR(AR71XX_UART_BASE));
+
+ prom_wait_thre(base);
+ __raw_writel(ch, base + UART_TX * 4);
+ prom_wait_thre(base);
+}
diff --git a/arch/mips/ath79/gpio.c b/arch/mips/ath79/gpio.c
new file mode 100644
index 0000000..a0c426b
--- /dev/null
+++ b/arch/mips/ath79/gpio.c
@@ -0,0 +1,197 @@
+/*
+ * Atheros AR71XX/AR724X/AR913X GPIO API support
+ *
+ * Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org>
+ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
+ *
+ * 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/init.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/spinlock.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/gpio.h>
+
+#include <asm/mach-ath79/ar71xx_regs.h>
+#include <asm/mach-ath79/ath79.h>
+#include "common.h"
+
+static void __iomem *ath79_gpio_base;
+static unsigned long ath79_gpio_count;
+static DEFINE_SPINLOCK(ath79_gpio_lock);
+
+static void __ath79_gpio_set_value(unsigned gpio, int value)
+{
+ void __iomem *base = ath79_gpio_base;
+
+ if (value)
+ __raw_writel(1 << gpio, base + AR71XX_GPIO_REG_SET);
+ else
+ __raw_writel(1 << gpio, base + AR71XX_GPIO_REG_CLEAR);
+}
+
+static int __ath79_gpio_get_value(unsigned gpio)
+{
+ return (__raw_readl(ath79_gpio_base + AR71XX_GPIO_REG_IN) >> gpio) & 1;
+}
+
+static int ath79_gpio_get_value(struct gpio_chip *chip, unsigned offset)
+{
+ return __ath79_gpio_get_value(offset);
+}
+
+static void ath79_gpio_set_value(struct gpio_chip *chip,
+ unsigned offset, int value)
+{
+ __ath79_gpio_set_value(offset, value);
+}
+
+static int ath79_gpio_direction_input(struct gpio_chip *chip,
+ unsigned offset)
+{
+ void __iomem *base = ath79_gpio_base;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ath79_gpio_lock, flags);
+
+ __raw_writel(__raw_readl(base + AR71XX_GPIO_REG_OE) & ~(1 << offset),
+ base + AR71XX_GPIO_REG_OE);
+
+ spin_unlock_irqrestore(&ath79_gpio_lock, flags);
+
+ return 0;
+}
+
+static int ath79_gpio_direction_output(struct gpio_chip *chip,
+ unsigned offset, int value)
+{
+ void __iomem *base = ath79_gpio_base;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ath79_gpio_lock, flags);
+
+ if (value)
+ __raw_writel(1 << offset, base + AR71XX_GPIO_REG_SET);
+ else
+ __raw_writel(1 << offset, base + AR71XX_GPIO_REG_CLEAR);
+
+ __raw_writel(__raw_readl(base + AR71XX_GPIO_REG_OE) | (1 << offset),
+ base + AR71XX_GPIO_REG_OE);
+
+ spin_unlock_irqrestore(&ath79_gpio_lock, flags);
+
+ return 0;
+}
+
+static struct gpio_chip ath79_gpio_chip = {
+ .label = "ath79",
+ .get = ath79_gpio_get_value,
+ .set = ath79_gpio_set_value,
+ .direction_input = ath79_gpio_direction_input,
+ .direction_output = ath79_gpio_direction_output,
+ .base = 0,
+};
+
+void ath79_gpio_function_enable(u32 mask)
+{
+ void __iomem *base = ath79_gpio_base;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ath79_gpio_lock, flags);
+
+ __raw_writel(__raw_readl(base + AR71XX_GPIO_REG_FUNC) | mask,
+ base + AR71XX_GPIO_REG_FUNC);
+ /* flush write */
+ __raw_readl(base + AR71XX_GPIO_REG_FUNC);
+
+ spin_unlock_irqrestore(&ath79_gpio_lock, flags);
+}
+
+void ath79_gpio_function_disable(u32 mask)
+{
+ void __iomem *base = ath79_gpio_base;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ath79_gpio_lock, flags);
+
+ __raw_writel(__raw_readl(base + AR71XX_GPIO_REG_FUNC) & ~mask,
+ base + AR71XX_GPIO_REG_FUNC);
+ /* flush write */
+ __raw_readl(base + AR71XX_GPIO_REG_FUNC);
+
+ spin_unlock_irqrestore(&ath79_gpio_lock, flags);
+}
+
+void ath79_gpio_function_setup(u32 set, u32 clear)
+{
+ void __iomem *base = ath79_gpio_base;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ath79_gpio_lock, flags);
+
+ __raw_writel((__raw_readl(base + AR71XX_GPIO_REG_FUNC) & ~clear) | set,
+ base + AR71XX_GPIO_REG_FUNC);
+ /* flush write */
+ __raw_readl(base + AR71XX_GPIO_REG_FUNC);
+
+ spin_unlock_irqrestore(&ath79_gpio_lock, flags);
+}
+
+void __init ath79_gpio_init(void)
+{
+ int err;
+
+ if (soc_is_ar71xx())
+ ath79_gpio_count = AR71XX_GPIO_COUNT;
+ else if (soc_is_ar724x())
+ ath79_gpio_count = AR724X_GPIO_COUNT;
+ else if (soc_is_ar913x())
+ ath79_gpio_count = AR913X_GPIO_COUNT;
+ else
+ BUG();
+
+ ath79_gpio_base = ioremap_nocache(AR71XX_GPIO_BASE, AR71XX_GPIO_SIZE);
+ ath79_gpio_chip.ngpio = ath79_gpio_count;
+
+ err = gpiochip_add(&ath79_gpio_chip);
+ if (err)
+ panic("cannot add AR71xx GPIO chip, error=%d", err);
+}
+
+int gpio_get_value(unsigned gpio)
+{
+ if (gpio < ath79_gpio_count)
+ return __ath79_gpio_get_value(gpio);
+
+ return __gpio_get_value(gpio);
+}
+EXPORT_SYMBOL(gpio_get_value);
+
+void gpio_set_value(unsigned gpio, int value)
+{
+ if (gpio < ath79_gpio_count)
+ __ath79_gpio_set_value(gpio, value);
+ else
+ __gpio_set_value(gpio, value);
+}
+EXPORT_SYMBOL(gpio_set_value);
+
+int gpio_to_irq(unsigned gpio)
+{
+ /* FIXME */
+ return -EINVAL;
+}
+EXPORT_SYMBOL(gpio_to_irq);
+
+int irq_to_gpio(unsigned irq)
+{
+ /* FIXME */
+ return -EINVAL;
+}
+EXPORT_SYMBOL(irq_to_gpio);
diff --git a/arch/mips/ath79/irq.c b/arch/mips/ath79/irq.c
new file mode 100644
index 0000000..1bf7f71
--- /dev/null
+++ b/arch/mips/ath79/irq.c
@@ -0,0 +1,187 @@
+/*
+ * Atheros AR71xx/AR724x/AR913x specific interrupt handling
+ *
+ * Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org>
+ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
+ *
+ * Parts of this file are based on Atheros' 2.6.15 BSP
+ *
+ * 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/init.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+
+#include <asm/irq_cpu.h>
+#include <asm/mipsregs.h>
+
+#include <asm/mach-ath79/ath79.h>
+#include <asm/mach-ath79/ar71xx_regs.h>
+#include "common.h"
+
+static unsigned int ath79_ip2_flush_reg;
+static unsigned int ath79_ip3_flush_reg;
+
+static void ath79_misc_irq_handler(unsigned int irq, struct irq_desc *desc)
+{
+ void __iomem *base = ath79_reset_base;
+ u32 pending;
+
+ pending = __raw_readl(base + AR71XX_RESET_REG_MISC_INT_STATUS) &
+ __raw_readl(base + AR71XX_RESET_REG_MISC_INT_ENABLE);
+
+ if (pending & MISC_INT_UART)
+ generic_handle_irq(ATH79_MISC_IRQ_UART);
+
+ else if (pending & MISC_INT_DMA)
+ generic_handle_irq(ATH79_MISC_IRQ_DMA);
+
+ else if (pending & MISC_INT_PERFC)
+ generic_handle_irq(ATH79_MISC_IRQ_PERFC);
+
+ else if (pending & MISC_INT_TIMER)
+ generic_handle_irq(ATH79_MISC_IRQ_TIMER);
+
+ else if (pending & MISC_INT_OHCI)
+ generic_handle_irq(ATH79_MISC_IRQ_OHCI);
+
+ else if (pending & MISC_INT_ERROR)
+ generic_handle_irq(ATH79_MISC_IRQ_ERROR);
+
+ else if (pending & MISC_INT_GPIO)
+ generic_handle_irq(ATH79_MISC_IRQ_GPIO);
+
+ else if (pending & MISC_INT_WDOG)
+ generic_handle_irq(ATH79_MISC_IRQ_WDOG);
+
+ else
+ spurious_interrupt();
+}
+
+static void ar71xx_misc_irq_unmask(unsigned int irq)
+{
+ void __iomem *base = ath79_reset_base;
+ u32 t;
+
+ irq -= ATH79_MISC_IRQ_BASE;
+
+ t = __raw_readl(base + AR71XX_RESET_REG_MISC_INT_ENABLE);
+ __raw_writel(t | (1 << irq), base + AR71XX_RESET_REG_MISC_INT_ENABLE);
+
+ /* flush write */
+ __raw_readl(base + AR71XX_RESET_REG_MISC_INT_ENABLE);
+}
+
+static void ar71xx_misc_irq_mask(unsigned int irq)
+{
+ void __iomem *base = ath79_reset_base;
+ u32 t;
+
+ irq -= ATH79_MISC_IRQ_BASE;
+
+ t = __raw_readl(base + AR71XX_RESET_REG_MISC_INT_ENABLE);
+ __raw_writel(t & ~(1 << irq), base + AR71XX_RESET_REG_MISC_INT_ENABLE);
+
+ /* flush write */
+ __raw_readl(base + AR71XX_RESET_REG_MISC_INT_ENABLE);
+}
+
+static void ar724x_misc_irq_ack(unsigned int irq)
+{
+ void __iomem *base = ath79_reset_base;
+ u32 t;
+
+ irq -= ATH79_MISC_IRQ_BASE;
+
+ t = __raw_readl(base + AR71XX_RESET_REG_MISC_INT_STATUS);
+ __raw_writel(t & ~(1 << irq), base + AR71XX_RESET_REG_MISC_INT_STATUS);
+
+ /* flush write */
+ __raw_readl(base + AR71XX_RESET_REG_MISC_INT_STATUS);
+}
+
+static struct irq_chip ath79_misc_irq_chip = {
+ .name = "MISC",
+ .unmask = ar71xx_misc_irq_unmask,
+ .mask = ar71xx_misc_irq_mask,
+};
+
+static void __init ath79_misc_irq_init(void)
+{
+ void __iomem *base = ath79_reset_base;
+ int i;
+
+ __raw_writel(0, base + AR71XX_RESET_REG_MISC_INT_ENABLE);
+ __raw_writel(0, base + AR71XX_RESET_REG_MISC_INT_STATUS);
+
+ if (soc_is_ar71xx() || soc_is_ar913x())
+ ath79_misc_irq_chip.mask_ack = ar71xx_misc_irq_mask;
+ else if (soc_is_ar724x())
+ ath79_misc_irq_chip.ack = ar724x_misc_irq_ack;
+ else
+ BUG();
+
+ for (i = ATH79_MISC_IRQ_BASE;
+ i < ATH79_MISC_IRQ_BASE + ATH79_MISC_IRQ_COUNT; i++) {
+ irq_desc[i].status = IRQ_DISABLED;
+ set_irq_chip_and_handler(i, &ath79_misc_irq_chip,
+ handle_level_irq);
+ }
+
+ set_irq_chained_handler(ATH79_CPU_IRQ_MISC, ath79_misc_irq_handler);
+}
+
+asmlinkage void plat_irq_dispatch(void)
+{
+ unsigned long pending;
+
+ pending = read_c0_status() & read_c0_cause() & ST0_IM;
+
+ if (pending & STATUSF_IP7)
+ do_IRQ(ATH79_CPU_IRQ_TIMER);
+
+ else if (pending & STATUSF_IP2) {
+ ath79_ddr_wb_flush(ath79_ip2_flush_reg);
+ do_IRQ(ATH79_CPU_IRQ_IP2);
+ }
+
+ else if (pending & STATUSF_IP4)
+ do_IRQ(ATH79_CPU_IRQ_GE0);
+
+ else if (pending & STATUSF_IP5)
+ do_IRQ(ATH79_CPU_IRQ_GE1);
+
+ else if (pending & STATUSF_IP3) {
+ ath79_ddr_wb_flush(ath79_ip3_flush_reg);
+ do_IRQ(ATH79_CPU_IRQ_USB);
+ }
+
+ else if (pending & STATUSF_IP6)
+ do_IRQ(ATH79_CPU_IRQ_MISC);
+
+ else
+ spurious_interrupt();
+}
+
+void __init arch_init_irq(void)
+{
+ if (soc_is_ar71xx()) {
+ ath79_ip2_flush_reg = AR71XX_DDR_REG_FLUSH_PCI;
+ ath79_ip3_flush_reg = AR71XX_DDR_REG_FLUSH_USB;
+ } else if (soc_is_ar724x()) {
+ ath79_ip2_flush_reg = AR724X_DDR_REG_FLUSH_PCIE;
+ ath79_ip3_flush_reg = AR724X_DDR_REG_FLUSH_USB;
+ } else if (soc_is_ar913x()) {
+ ath79_ip2_flush_reg = AR913X_DDR_REG_FLUSH_WMAC;
+ ath79_ip3_flush_reg = AR913X_DDR_REG_FLUSH_USB;
+ } else
+ BUG();
+
+ cp0_perfcount_irq = ATH79_MISC_IRQ_PERFC;
+ mips_cpu_irq_init();
+ ath79_misc_irq_init();
+}
diff --git a/arch/mips/ath79/mach-ap81.c b/arch/mips/ath79/mach-ap81.c
new file mode 100644
index 0000000..eee4c12
--- /dev/null
+++ b/arch/mips/ath79/mach-ap81.c
@@ -0,0 +1,98 @@
+/*
+ * Atheros AP81 board support
+ *
+ * Copyright (C) 2009-2010 Gabor Juhos <juhosg@openwrt.org>
+ * Copyright (C) 2009 Imre Kaloz <kaloz@openwrt.org>
+ *
+ * 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 "machtypes.h"
+#include "dev-ar913x-wmac.h"
+#include "dev-gpio-buttons.h"
+#include "dev-leds-gpio.h"
+#include "dev-spi.h"
+
+#define AP81_GPIO_LED_STATUS 1
+#define AP81_GPIO_LED_AOSS 3
+#define AP81_GPIO_LED_WLAN 6
+#define AP81_GPIO_LED_POWER 14
+
+#define AP81_GPIO_BTN_SW4 12
+#define AP81_GPIO_BTN_SW1 21
+
+#define AP81_KEYS_POLL_INTERVAL 20 /* msecs */
+#define AP81_KEYS_DEBOUNCE_INTERVAL (3 * AP81_KEYS_POLL_INTERVAL)
+
+#define AP81_CAL_DATA_ADDR 0x1fff1000
+
+static struct gpio_led ap81_leds_gpio[] __initdata = {
+ {
+ .name = "ap81:green:status",
+ .gpio = AP81_GPIO_LED_STATUS,
+ .active_low = 1,
+ }, {
+ .name = "ap81:amber:aoss",
+ .gpio = AP81_GPIO_LED_AOSS,
+ .active_low = 1,
+ }, {
+ .name = "ap81:green:wlan",
+ .gpio = AP81_GPIO_LED_WLAN,
+ .active_low = 1,
+ }, {
+ .name = "ap81:green:power",
+ .gpio = AP81_GPIO_LED_POWER,
+ .active_low = 1,
+ }
+};
+
+static struct gpio_keys_button ap81_gpio_keys[] __initdata = {
+ {
+ .desc = "sw1",
+ .type = EV_KEY,
+ .code = BTN_0,
+ .debounce_interval = AP81_KEYS_DEBOUNCE_INTERVAL,
+ .gpio = AP81_GPIO_BTN_SW1,
+ .active_low = 1,
+ } , {
+ .desc = "sw4",
+ .type = EV_KEY,
+ .code = BTN_1,
+ .debounce_interval = AP81_KEYS_DEBOUNCE_INTERVAL,
+ .gpio = AP81_GPIO_BTN_SW4,
+ .active_low = 1,
+ }
+};
+
+static struct spi_board_info ap81_spi_info[] = {
+ {
+ .bus_num = 0,
+ .chip_select = 0,
+ .max_speed_hz = 25000000,
+ .modalias = "m25p64",
+ }
+};
+
+static struct ath79_spi_platform_data ap81_spi_data = {
+ .bus_num = 0,
+ .num_chipselect = 1,
+};
+
+static void __init ap81_setup(void)
+{
+ u8 *cal_data = (u8 *) KSEG1ADDR(AP81_CAL_DATA_ADDR);
+
+ ath79_register_leds_gpio(-1, ARRAY_SIZE(ap81_leds_gpio),
+ ap81_leds_gpio);
+ ath79_register_gpio_keys_polled(-1, AP81_KEYS_POLL_INTERVAL,
+ ARRAY_SIZE(ap81_gpio_keys),
+ ap81_gpio_keys);
+ ath79_register_spi(&ap81_spi_data, ap81_spi_info,
+ ARRAY_SIZE(ap81_spi_info));
+ ath79_register_ar913x_wmac(cal_data);
+}
+
+MIPS_MACHINE(ATH79_MACH_AP81, "AP81", "Atheros AP81 reference board",
+ ap81_setup);
diff --git a/arch/mips/ath79/mach-pb44.c b/arch/mips/ath79/mach-pb44.c
new file mode 100644
index 0000000..ec7b7a1
--- /dev/null
+++ b/arch/mips/ath79/mach-pb44.c
@@ -0,0 +1,118 @@
+/*
+ * Atheros PB44 reference board support
+ *
+ * Copyright (C) 2009-2010 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * 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/platform_device.h>
+#include <linux/i2c.h>
+#include <linux/i2c-gpio.h>
+#include <linux/i2c/pcf857x.h>
+
+#include "machtypes.h"
+#include "dev-gpio-buttons.h"
+#include "dev-leds-gpio.h"
+#include "dev-spi.h"
+
+#define PB44_GPIO_I2C_SCL 0
+#define PB44_GPIO_I2C_SDA 1
+
+#define PB44_GPIO_EXP_BASE 16
+#define PB44_GPIO_SW_RESET (PB44_GPIO_EXP_BASE + 6)
+#define PB44_GPIO_SW_JUMP (PB44_GPIO_EXP_BASE + 8)
+#define PB44_GPIO_LED_JUMP1 (PB44_GPIO_EXP_BASE + 9)
+#define PB44_GPIO_LED_JUMP2 (PB44_GPIO_EXP_BASE + 10)
+
+#define PB44_KEYS_POLL_INTERVAL 20 /* msecs */
+#define PB44_KEYS_DEBOUNCE_INTERVAL (3 * PB44_KEYS_POLL_INTERVAL)
+
+static struct i2c_gpio_platform_data pb44_i2c_gpio_data = {
+ .sda_pin = PB44_GPIO_I2C_SDA,
+ .scl_pin = PB44_GPIO_I2C_SCL,
+};
+
+static struct platform_device pb44_i2c_gpio_device = {
+ .name = "i2c-gpio",
+ .id = 0,
+ .dev = {
+ .platform_data = &pb44_i2c_gpio_data,
+ }
+};
+
+static struct pcf857x_platform_data pb44_pcf857x_data = {
+ .gpio_base = PB44_GPIO_EXP_BASE,
+};
+
+static struct i2c_board_info pb44_i2c_board_info[] __initdata = {
+ {
+ I2C_BOARD_INFO("pcf8575", 0x20),
+ .platform_data = &pb44_pcf857x_data,
+ },
+};
+
+static struct gpio_led pb44_leds_gpio[] __initdata = {
+ {
+ .name = "pb44:amber:jump1",
+ .gpio = PB44_GPIO_LED_JUMP1,
+ .active_low = 1,
+ }, {
+ .name = "pb44:green:jump2",
+ .gpio = PB44_GPIO_LED_JUMP2,
+ .active_low = 1,
+ },
+};
+
+static struct gpio_keys_button pb44_gpio_keys[] __initdata = {
+ {
+ .desc = "soft_reset",
+ .type = EV_KEY,
+ .code = KEY_RESTART,
+ .debounce_interval = PB44_KEYS_DEBOUNCE_INTERVAL,
+ .gpio = PB44_GPIO_SW_RESET,
+ .active_low = 1,
+ } , {
+ .desc = "jumpstart",
+ .type = EV_KEY,
+ .code = KEY_WPS_BUTTON,
+ .debounce_interval = PB44_KEYS_DEBOUNCE_INTERVAL,
+ .gpio = PB44_GPIO_SW_JUMP,
+ .active_low = 1,
+ }
+};
+
+static struct spi_board_info pb44_spi_info[] = {
+ {
+ .bus_num = 0,
+ .chip_select = 0,
+ .max_speed_hz = 25000000,
+ .modalias = "m25p64",
+ },
+};
+
+static struct ath79_spi_platform_data pb44_spi_data = {
+ .bus_num = 0,
+ .num_chipselect = 1,
+};
+
+static void __init pb44_init(void)
+{
+ i2c_register_board_info(0, pb44_i2c_board_info,
+ ARRAY_SIZE(pb44_i2c_board_info));
+ platform_device_register(&pb44_i2c_gpio_device);
+
+ ath79_register_leds_gpio(-1, ARRAY_SIZE(pb44_leds_gpio),
+ pb44_leds_gpio);
+ ath79_register_gpio_keys_polled(-1, PB44_KEYS_POLL_INTERVAL,
+ ARRAY_SIZE(pb44_gpio_keys),
+ pb44_gpio_keys);
+ ath79_register_spi(&pb44_spi_data, pb44_spi_info,
+ ARRAY_SIZE(pb44_spi_info));
+}
+
+MIPS_MACHINE(ATH79_MACH_PB44, "PB44", "Atheros PB44 reference board",
+ pb44_init);
diff --git a/arch/mips/ath79/machtypes.h b/arch/mips/ath79/machtypes.h
new file mode 100644
index 0000000..3940fe4
--- /dev/null
+++ b/arch/mips/ath79/machtypes.h
@@ -0,0 +1,23 @@
+/*
+ * Atheros AR71XX/AR724X/AR913X machine type definitions
+ *
+ * Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org>
+ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
+ *
+ * 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 _ATH79_MACHTYPE_H
+#define _ATH79_MACHTYPE_H
+
+#include <asm/mips_machine.h>
+
+enum ath79_mach_type {
+ ATH79_MACH_GENERIC = 0,
+ ATH79_MACH_AP81, /* Atheros AP81 reference board */
+ ATH79_MACH_PB44, /* Atheros PB44 reference board */
+};
+
+#endif /* _ATH79_MACHTYPE_H */
diff --git a/arch/mips/ath79/prom.c b/arch/mips/ath79/prom.c
new file mode 100644
index 0000000..e9cbd7c
--- /dev/null
+++ b/arch/mips/ath79/prom.c
@@ -0,0 +1,57 @@
+/*
+ * Atheros AR71XX/AR724X/AR913X specific prom routines
+ *
+ * Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org>
+ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
+ *
+ * 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/init.h>
+#include <linux/io.h>
+#include <linux/string.h>
+
+#include <asm/bootinfo.h>
+#include <asm/addrspace.h>
+
+#include "common.h"
+
+static inline int is_valid_ram_addr(void *addr)
+{
+ if (((u32) addr > KSEG0) &&
+ ((u32) addr < (KSEG0 + ATH79_MEM_SIZE_MAX)))
+ return 1;
+
+ if (((u32) addr > KSEG1) &&
+ ((u32) addr < (KSEG1 + ATH79_MEM_SIZE_MAX)))
+ return 1;
+
+ return 0;
+}
+
+static __init void ath79_prom_init_cmdline(int argc, char **argv)
+{
+ int i;
+
+ if (!is_valid_ram_addr(argv))
+ return;
+
+ for (i = 0; i < argc; i++)
+ if (is_valid_ram_addr(argv[i])) {
+ strlcat(arcs_cmdline, " ", sizeof(arcs_cmdline));
+ strlcat(arcs_cmdline, argv[i], sizeof(arcs_cmdline));
+ }
+}
+
+void __init prom_init(void)
+{
+ ath79_prom_init_cmdline(fw_arg0, (char **)fw_arg1);
+}
+
+void __init prom_free_prom_memory(void)
+{
+ /* We do not have to prom memory to free */
+}
diff --git a/arch/mips/ath79/setup.c b/arch/mips/ath79/setup.c
new file mode 100644
index 0000000..159b42f
--- /dev/null
+++ b/arch/mips/ath79/setup.c
@@ -0,0 +1,206 @@
+/*
+ * Atheros AR71XX/AR724X/AR913X specific setup
+ *
+ * Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org>
+ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
+ *
+ * Parts of this file are based on Atheros' 2.6.15 BSP
+ *
+ * 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/init.h>
+#include <linux/bootmem.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+
+#include <asm/bootinfo.h>
+#include <asm/time.h> /* for mips_hpt_frequency */
+#include <asm/reboot.h> /* for _machine_{restart,halt} */
+#include <asm/mips_machine.h>
+
+#include <asm/mach-ath79/ath79.h>
+#include <asm/mach-ath79/ar71xx_regs.h>
+#include "common.h"
+#include "dev-common.h"
+#include "machtypes.h"
+
+#define ATH79_SYS_TYPE_LEN 64
+
+#define AR71XX_BASE_FREQ 40000000
+#define AR724X_BASE_FREQ 5000000
+#define AR913X_BASE_FREQ 5000000
+
+static char ath79_sys_type[ATH79_SYS_TYPE_LEN];
+
+static void ath79_restart(char *command)
+{
+ ath79_device_reset_set(AR71XX_RESET_FULL_CHIP);
+ for (;;)
+ if (cpu_wait)
+ cpu_wait();
+}
+
+static void ath79_halt(void)
+{
+ while (1)
+ cpu_wait();
+}
+
+static void __init ath79_detect_mem_size(void)
+{
+ unsigned long size;
+
+ for (size = ATH79_MEM_SIZE_MIN; size < ATH79_MEM_SIZE_MAX;
+ size <<= 1) {
+ if (!memcmp(ath79_detect_mem_size,
+ ath79_detect_mem_size + size, 1024))
+ break;
+ }
+
+ add_memory_region(0, size, BOOT_MEM_RAM);
+}
+
+static void __init ath79_detect_sys_type(void)
+{
+ char *chip = "????";
+ u32 id;
+ u32 major;
+ u32 minor;
+ u32 rev = 0;
+
+ id = ath79_reset_rr(AR71XX_RESET_REG_REV_ID);
+ major = id & REV_ID_MAJOR_MASK;
+
+ switch (major) {
+ case REV_ID_MAJOR_AR71XX:
+ minor = id & AR71XX_REV_ID_MINOR_MASK;
+ rev = id >> AR71XX_REV_ID_REVISION_SHIFT;
+ rev &= AR71XX_REV_ID_REVISION_MASK;
+ switch (minor) {
+ case AR71XX_REV_ID_MINOR_AR7130:
+ ath79_soc = ATH79_SOC_AR7130;
+ chip = "7130";
+ break;
+
+ case AR71XX_REV_ID_MINOR_AR7141:
+ ath79_soc = ATH79_SOC_AR7141;
+ chip = "7141";
+ break;
+
+ case AR71XX_REV_ID_MINOR_AR7161:
+ ath79_soc = ATH79_SOC_AR7161;
+ chip = "7161";
+ break;
+ }
+ break;
+
+ case REV_ID_MAJOR_AR7240:
+ ath79_soc = ATH79_SOC_AR7240;
+ chip = "7240";
+ rev = (id & AR724X_REV_ID_REVISION_MASK);
+ break;
+
+ case REV_ID_MAJOR_AR7241:
+ ath79_soc = ATH79_SOC_AR7241;
+ chip = "7241";
+ rev = (id & AR724X_REV_ID_REVISION_MASK);
+ break;
+
+ case REV_ID_MAJOR_AR7242:
+ ath79_soc = ATH79_SOC_AR7242;
+ chip = "7242";
+ rev = (id & AR724X_REV_ID_REVISION_MASK);
+ break;
+
+ case REV_ID_MAJOR_AR913X:
+ minor = id & AR913X_REV_ID_MINOR_MASK;
+ rev = id >> AR913X_REV_ID_REVISION_SHIFT;
+ rev &= AR913X_REV_ID_REVISION_MASK;
+ switch (minor) {
+ case AR913X_REV_ID_MINOR_AR9130:
+ ath79_soc = ATH79_SOC_AR9130;
+ chip = "9130";
+ break;
+
+ case AR913X_REV_ID_MINOR_AR9132:
+ ath79_soc = ATH79_SOC_AR9132;
+ chip = "9132";
+ break;
+ }
+ break;
+
+ default:
+ panic("ath79: unknown SoC, id:0x%08x\n", id);
+ }
+
+ sprintf(ath79_sys_type, "Atheros AR%s rev %u", chip, rev);
+ pr_info("SoC: %s\n", ath79_sys_type);
+}
+
+const char *get_system_type(void)
+{
+ return ath79_sys_type;
+}
+
+unsigned int __cpuinit get_c0_compare_int(void)
+{
+ return CP0_LEGACY_COMPARE_IRQ;
+}
+
+void __init plat_mem_setup(void)
+{
+ set_io_port_base(KSEG1);
+
+ ath79_reset_base = ioremap_nocache(AR71XX_RESET_BASE,
+ AR71XX_RESET_SIZE);
+ ath79_pll_base = ioremap_nocache(AR71XX_PLL_BASE,
+ AR71XX_PLL_SIZE);
+ ath79_ddr_base = ioremap_nocache(AR71XX_DDR_CTRL_BASE,
+ AR71XX_DDR_CTRL_SIZE);
+
+ ath79_detect_sys_type();
+ ath79_detect_mem_size();
+ ath79_clocks_init();
+
+ _machine_restart = ath79_restart;
+ _machine_halt = ath79_halt;
+ pm_power_off = ath79_halt;
+}
+
+void __init plat_time_init(void)
+{
+ struct clk *clk;
+
+ clk = clk_get(NULL, "cpu");
+ if (IS_ERR(clk))
+ panic("unable to get CPU clock, err=%ld", PTR_ERR(clk));
+
+ mips_hpt_frequency = clk_get_rate(clk) / 2;
+}
+
+static int __init ath79_setup(void)
+{
+ ath79_gpio_init();
+ ath79_register_uart();
+ ath79_register_wdt();
+
+ mips_machine_setup();
+
+ return 0;
+}
+
+arch_initcall(ath79_setup);
+
+static void __init ath79_generic_init(void)
+{
+ /* Nothing to do */
+}
+
+MIPS_MACHINE(ATH79_MACH_GENERIC,
+ "Generic",
+ "Generic AR71XX/AR724X/AR913X based board",
+ ath79_generic_init);
diff --git a/arch/mips/configs/ar7_defconfig b/arch/mips/configs/ar7_defconfig
index c78c7e7..6cd5a51 100644
--- a/arch/mips/configs/ar7_defconfig
+++ b/arch/mips/configs/ar7_defconfig
@@ -14,7 +14,7 @@ CONFIG_SYSFS_DEPRECATED_V2=y
CONFIG_RELAY=y
CONFIG_BLK_DEV_INITRD=y
CONFIG_RD_LZMA=y
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_KALLSYMS is not set
# CONFIG_ELF_CORE is not set
# CONFIG_PCSPKR_PLATFORM is not set
diff --git a/arch/mips/configs/bcm47xx_defconfig b/arch/mips/configs/bcm47xx_defconfig
index 927d58b..22fdf2f 100644
--- a/arch/mips/configs/bcm47xx_defconfig
+++ b/arch/mips/configs/bcm47xx_defconfig
@@ -21,7 +21,7 @@ CONFIG_CGROUP_CPUACCT=y
CONFIG_RELAY=y
CONFIG_BLK_DEV_INITRD=y
CONFIG_RD_LZMA=y
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
CONFIG_SLAB=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
diff --git a/arch/mips/configs/bcm63xx_defconfig b/arch/mips/configs/bcm63xx_defconfig
index b806a4e..9190051 100644
--- a/arch/mips/configs/bcm63xx_defconfig
+++ b/arch/mips/configs/bcm63xx_defconfig
@@ -10,7 +10,7 @@ CONFIG_EXPERIMENTAL=y
# CONFIG_SWAP is not set
CONFIG_TINY_RCU=y
CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_PCSPKR_PLATFORM is not set
# CONFIG_FUTEX is not set
# CONFIG_EPOLL is not set
diff --git a/arch/mips/configs/bigsur_defconfig b/arch/mips/configs/bigsur_defconfig
index 9749bc8..1cdff6b 100644
--- a/arch/mips/configs/bigsur_defconfig
+++ b/arch/mips/configs/bigsur_defconfig
@@ -26,7 +26,7 @@ CONFIG_PID_NS=y
CONFIG_NET_NS=y
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_SYSCTL_SYSCALL is not set
# CONFIG_PCSPKR_PLATFORM is not set
CONFIG_SLAB=y
diff --git a/arch/mips/configs/capcella_defconfig b/arch/mips/configs/capcella_defconfig
index 502a8e9..5135dc0 100644
--- a/arch/mips/configs/capcella_defconfig
+++ b/arch/mips/configs/capcella_defconfig
@@ -4,7 +4,7 @@ CONFIG_EXPERIMENTAL=y
CONFIG_SYSVIPC=y
CONFIG_LOG_BUF_SHIFT=14
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
CONFIG_SLAB=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
diff --git a/arch/mips/configs/cavium-octeon_defconfig b/arch/mips/configs/cavium-octeon_defconfig
index 3567b6f..75165df 100644
--- a/arch/mips/configs/cavium-octeon_defconfig
+++ b/arch/mips/configs/cavium-octeon_defconfig
@@ -15,7 +15,7 @@ CONFIG_SYSFS_DEPRECATED_V2=y
CONFIG_RELAY=y
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_PCSPKR_PLATFORM is not set
CONFIG_SLAB=y
CONFIG_MODULES=y
diff --git a/arch/mips/configs/cobalt_defconfig b/arch/mips/configs/cobalt_defconfig
index 6c4f7e9..5419adb 100644
--- a/arch/mips/configs/cobalt_defconfig
+++ b/arch/mips/configs/cobalt_defconfig
@@ -4,7 +4,7 @@ CONFIG_SYSVIPC=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_RELAY=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
# CONFIG_BLK_DEV_BSG is not set
diff --git a/arch/mips/configs/db1000_defconfig b/arch/mips/configs/db1000_defconfig
index dda158b..4044c9e 100644
--- a/arch/mips/configs/db1000_defconfig
+++ b/arch/mips/configs/db1000_defconfig
@@ -11,7 +11,7 @@ CONFIG_POSIX_MQUEUE=y
CONFIG_TINY_RCU=y
CONFIG_LOG_BUF_SHIFT=14
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_KALLSYMS is not set
# CONFIG_PCSPKR_PLATFORM is not set
# CONFIG_VM_EVENT_COUNTERS is not set
diff --git a/arch/mips/configs/db1100_defconfig b/arch/mips/configs/db1100_defconfig
index 7e4fc76..c6b4993 100644
--- a/arch/mips/configs/db1100_defconfig
+++ b/arch/mips/configs/db1100_defconfig
@@ -11,7 +11,7 @@ CONFIG_SYSVIPC=y
CONFIG_POSIX_MQUEUE=y
CONFIG_TINY_RCU=y
CONFIG_LOG_BUF_SHIFT=14
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_SYSCTL_SYSCALL is not set
# CONFIG_KALLSYMS is not set
# CONFIG_PCSPKR_PLATFORM is not set
diff --git a/arch/mips/configs/db1200_defconfig b/arch/mips/configs/db1200_defconfig
index 6fe205f..1f69249 100644
--- a/arch/mips/configs/db1200_defconfig
+++ b/arch/mips/configs/db1200_defconfig
@@ -12,7 +12,7 @@ CONFIG_SYSVIPC=y
CONFIG_POSIX_MQUEUE=y
CONFIG_TINY_RCU=y
CONFIG_LOG_BUF_SHIFT=14
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_SYSCTL_SYSCALL is not set
# CONFIG_KALLSYMS is not set
# CONFIG_PCSPKR_PLATFORM is not set
diff --git a/arch/mips/configs/db1500_defconfig b/arch/mips/configs/db1500_defconfig
index a741c554..b6e21c7 100644
--- a/arch/mips/configs/db1500_defconfig
+++ b/arch/mips/configs/db1500_defconfig
@@ -10,7 +10,7 @@ CONFIG_LOCALVERSION="-db1500"
CONFIG_KERNEL_LZMA=y
CONFIG_SYSVIPC=y
CONFIG_LOG_BUF_SHIFT=14
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_KALLSYMS is not set
# CONFIG_PCSPKR_PLATFORM is not set
# CONFIG_VM_EVENT_COUNTERS is not set
diff --git a/arch/mips/configs/db1550_defconfig b/arch/mips/configs/db1550_defconfig
index cd32dd8..798a553 100644
--- a/arch/mips/configs/db1550_defconfig
+++ b/arch/mips/configs/db1550_defconfig
@@ -11,7 +11,7 @@ CONFIG_SYSVIPC=y
CONFIG_POSIX_MQUEUE=y
CONFIG_TINY_RCU=y
CONFIG_LOG_BUF_SHIFT=14
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_SYSCTL_SYSCALL is not set
# CONFIG_KALLSYMS is not set
# CONFIG_PCSPKR_PLATFORM is not set
diff --git a/arch/mips/configs/decstation_defconfig b/arch/mips/configs/decstation_defconfig
index b15bfd1..87d0340 100644
--- a/arch/mips/configs/decstation_defconfig
+++ b/arch/mips/configs/decstation_defconfig
@@ -4,7 +4,7 @@ CONFIG_EXPERIMENTAL=y
CONFIG_SYSVIPC=y
CONFIG_LOG_BUF_SHIFT=14
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_SYSCTL_SYSCALL is not set
# CONFIG_HOTPLUG is not set
CONFIG_SLAB=y
diff --git a/arch/mips/configs/e55_defconfig b/arch/mips/configs/e55_defconfig
index 0b60c06..0126e66 100644
--- a/arch/mips/configs/e55_defconfig
+++ b/arch/mips/configs/e55_defconfig
@@ -4,7 +4,7 @@ CONFIG_EXPERIMENTAL=y
CONFIG_SYSVIPC=y
CONFIG_LOG_BUF_SHIFT=14
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_HOTPLUG is not set
CONFIG_SLAB=y
CONFIG_MODULES=y
diff --git a/arch/mips/configs/fuloong2e_defconfig b/arch/mips/configs/fuloong2e_defconfig
index 63944a1..e5b73de 100644
--- a/arch/mips/configs/fuloong2e_defconfig
+++ b/arch/mips/configs/fuloong2e_defconfig
@@ -17,7 +17,7 @@ CONFIG_NAMESPACES=y
CONFIG_USER_NS=y
CONFIG_PID_NS=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_PCSPKR_PLATFORM is not set
# CONFIG_COMPAT_BRK is not set
CONFIG_SLAB=y
diff --git a/arch/mips/configs/gpr_defconfig b/arch/mips/configs/gpr_defconfig
index 53edc13..48a40ae 100644
--- a/arch/mips/configs/gpr_defconfig
+++ b/arch/mips/configs/gpr_defconfig
@@ -11,7 +11,7 @@ CONFIG_BSD_PROCESS_ACCT_V3=y
CONFIG_RELAY=y
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
CONFIG_SLAB=y
CONFIG_PROFILING=y
CONFIG_MODULES=y
diff --git a/arch/mips/configs/ip22_defconfig b/arch/mips/configs/ip22_defconfig
index 36de199..d160656 100644
--- a/arch/mips/configs/ip22_defconfig
+++ b/arch/mips/configs/ip22_defconfig
@@ -17,7 +17,7 @@ CONFIG_IPC_NS=y
CONFIG_USER_NS=y
CONFIG_PID_NS=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_HOTPLUG is not set
# CONFIG_PCSPKR_PLATFORM is not set
# CONFIG_COMPAT_BRK is not set
diff --git a/arch/mips/configs/ip27_defconfig b/arch/mips/configs/ip27_defconfig
index 4b16c48..0e36abc 100644
--- a/arch/mips/configs/ip27_defconfig
+++ b/arch/mips/configs/ip27_defconfig
@@ -15,7 +15,7 @@ CONFIG_CGROUPS=y
CONFIG_CPUSETS=y
CONFIG_RELAY=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_PCSPKR_PLATFORM is not set
CONFIG_SLAB=y
CONFIG_MODULES=y
diff --git a/arch/mips/configs/ip28_defconfig b/arch/mips/configs/ip28_defconfig
index 98f2c77..4dbf626 100644
--- a/arch/mips/configs/ip28_defconfig
+++ b/arch/mips/configs/ip28_defconfig
@@ -8,7 +8,7 @@ CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_RELAY=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_HOTPLUG is not set
CONFIG_SLAB=y
CONFIG_MODULES=y
diff --git a/arch/mips/configs/ip32_defconfig b/arch/mips/configs/ip32_defconfig
index 5bea99b..7bbd521 100644
--- a/arch/mips/configs/ip32_defconfig
+++ b/arch/mips/configs/ip32_defconfig
@@ -10,7 +10,7 @@ CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_SYSFS_DEPRECATED_V2=y
CONFIG_RELAY=y
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
CONFIG_SLAB=y
CONFIG_PROFILING=y
CONFIG_OPROFILE=m
diff --git a/arch/mips/configs/jazz_defconfig b/arch/mips/configs/jazz_defconfig
index 6ae46bc..92a60ae 100644
--- a/arch/mips/configs/jazz_defconfig
+++ b/arch/mips/configs/jazz_defconfig
@@ -10,7 +10,7 @@ CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_RELAY=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_SYSCTL_SYSCALL is not set
CONFIG_SLAB=y
CONFIG_MODULES=y
diff --git a/arch/mips/configs/jmr3927_defconfig b/arch/mips/configs/jmr3927_defconfig
index bf24e93..db5705e 100644
--- a/arch/mips/configs/jmr3927_defconfig
+++ b/arch/mips/configs/jmr3927_defconfig
@@ -4,7 +4,7 @@ CONFIG_TOSHIBA_JMR3927=y
CONFIG_SYSVIPC=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_HOTPLUG is not set
# CONFIG_PCSPKR_PLATFORM is not set
CONFIG_SLAB=y
diff --git a/arch/mips/configs/lasat_defconfig b/arch/mips/configs/lasat_defconfig
index 6447261..d9f3db2 100644
--- a/arch/mips/configs/lasat_defconfig
+++ b/arch/mips/configs/lasat_defconfig
@@ -8,7 +8,7 @@ CONFIG_HZ_1000=y
CONFIG_EXPERIMENTAL=y
CONFIG_SYSVIPC=y
CONFIG_LOG_BUF_SHIFT=14
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_SYSCTL_SYSCALL is not set
# CONFIG_KALLSYMS is not set
# CONFIG_HOTPLUG is not set
diff --git a/arch/mips/configs/lemote2f_defconfig b/arch/mips/configs/lemote2f_defconfig
index f7033f3..167c1d0 100644
--- a/arch/mips/configs/lemote2f_defconfig
+++ b/arch/mips/configs/lemote2f_defconfig
@@ -21,7 +21,7 @@ CONFIG_BLK_DEV_INITRD=y
CONFIG_RD_BZIP2=y
CONFIG_RD_LZMA=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
CONFIG_PROFILING=y
CONFIG_OPROFILE=m
CONFIG_MODULES=y
diff --git a/arch/mips/configs/malta_defconfig b/arch/mips/configs/malta_defconfig
index b455d0f..7270f31 100644
--- a/arch/mips/configs/malta_defconfig
+++ b/arch/mips/configs/malta_defconfig
@@ -15,7 +15,7 @@ CONFIG_UTS_NS=y
CONFIG_IPC_NS=y
CONFIG_PID_NS=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_SYSCTL_SYSCALL is not set
# CONFIG_COMPAT_BRK is not set
CONFIG_SLAB=y
@@ -369,7 +369,10 @@ CONFIG_VT_HW_CONSOLE_BINDING=y
CONFIG_SERIAL_8250=y
CONFIG_SERIAL_8250_CONSOLE=y
# CONFIG_HWMON is not set
+CONFIG_FB=y
+CONFIG_FB_CIRRUS=y
# CONFIG_VGA_CONSOLE is not set
+CONFIG_FRAMEBUFFER_CONSOLE=y
CONFIG_HID=m
CONFIG_LEDS_CLASS=m
CONFIG_LEDS_TRIGGER_TIMER=m
diff --git a/arch/mips/configs/markeins_defconfig b/arch/mips/configs/markeins_defconfig
index 86bf001..9c9a123 100644
--- a/arch/mips/configs/markeins_defconfig
+++ b/arch/mips/configs/markeins_defconfig
@@ -9,7 +9,7 @@ CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=14
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
CONFIG_SLAB=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
diff --git a/arch/mips/configs/mipssim_defconfig b/arch/mips/configs/mipssim_defconfig
index 4925f50..b5ad738 100644
--- a/arch/mips/configs/mipssim_defconfig
+++ b/arch/mips/configs/mipssim_defconfig
@@ -7,7 +7,7 @@ CONFIG_EXPERIMENTAL=y
CONFIG_SYSVIPC=y
CONFIG_LOG_BUF_SHIFT=14
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
CONFIG_SLAB=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
diff --git a/arch/mips/configs/mpc30x_defconfig b/arch/mips/configs/mpc30x_defconfig
index efb779f..c16de98 100644
--- a/arch/mips/configs/mpc30x_defconfig
+++ b/arch/mips/configs/mpc30x_defconfig
@@ -5,7 +5,7 @@ CONFIG_SYSVIPC=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_RELAY=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
CONFIG_SLAB=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
diff --git a/arch/mips/configs/msp71xx_defconfig b/arch/mips/configs/msp71xx_defconfig
index ab05145..d1142e9 100644
--- a/arch/mips/configs/msp71xx_defconfig
+++ b/arch/mips/configs/msp71xx_defconfig
@@ -8,7 +8,7 @@ CONFIG_LOCALVERSION="-pmc"
CONFIG_SYSVIPC=y
CONFIG_LOG_BUF_SHIFT=14
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_SHMEM is not set
CONFIG_SLAB=y
CONFIG_MODULES=y
diff --git a/arch/mips/configs/mtx1_defconfig b/arch/mips/configs/mtx1_defconfig
index 81469975..a97a42c6 100644
--- a/arch/mips/configs/mtx1_defconfig
+++ b/arch/mips/configs/mtx1_defconfig
@@ -11,7 +11,7 @@ CONFIG_AUDIT=y
CONFIG_RELAY=y
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
CONFIG_SLAB=y
CONFIG_PROFILING=y
CONFIG_OPROFILE=m
diff --git a/arch/mips/configs/pb1100_defconfig b/arch/mips/configs/pb1100_defconfig
index 1597aa1..75eb1b1 100644
--- a/arch/mips/configs/pb1100_defconfig
+++ b/arch/mips/configs/pb1100_defconfig
@@ -11,7 +11,7 @@ CONFIG_SYSVIPC=y
CONFIG_POSIX_MQUEUE=y
CONFIG_TINY_RCU=y
CONFIG_LOG_BUF_SHIFT=14
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_SYSCTL_SYSCALL is not set
# CONFIG_KALLSYMS is not set
# CONFIG_PCSPKR_PLATFORM is not set
diff --git a/arch/mips/configs/pb1200_defconfig b/arch/mips/configs/pb1200_defconfig
index 96f0d43..dcbe270 100644
--- a/arch/mips/configs/pb1200_defconfig
+++ b/arch/mips/configs/pb1200_defconfig
@@ -12,7 +12,7 @@ CONFIG_SYSVIPC=y
CONFIG_POSIX_MQUEUE=y
CONFIG_TINY_RCU=y
CONFIG_LOG_BUF_SHIFT=14
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_SYSCTL_SYSCALL is not set
# CONFIG_KALLSYMS is not set
# CONFIG_PCSPKR_PLATFORM is not set
diff --git a/arch/mips/configs/pb1500_defconfig b/arch/mips/configs/pb1500_defconfig
index b4bfd48..fa00487 100644
--- a/arch/mips/configs/pb1500_defconfig
+++ b/arch/mips/configs/pb1500_defconfig
@@ -11,7 +11,7 @@ CONFIG_SYSVIPC=y
CONFIG_POSIX_MQUEUE=y
CONFIG_TINY_RCU=y
CONFIG_LOG_BUF_SHIFT=14
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_SYSCTL_SYSCALL is not set
# CONFIG_KALLSYMS is not set
# CONFIG_PCSPKR_PLATFORM is not set
diff --git a/arch/mips/configs/pb1550_defconfig b/arch/mips/configs/pb1550_defconfig
index 5a66002..e83d649 100644
--- a/arch/mips/configs/pb1550_defconfig
+++ b/arch/mips/configs/pb1550_defconfig
@@ -11,7 +11,7 @@ CONFIG_SYSVIPC=y
CONFIG_POSIX_MQUEUE=y
CONFIG_TINY_RCU=y
CONFIG_LOG_BUF_SHIFT=14
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_SYSCTL_SYSCALL is not set
# CONFIG_KALLSYMS is not set
# CONFIG_PCSPKR_PLATFORM is not set
diff --git a/arch/mips/configs/pnx8335-stb225_defconfig b/arch/mips/configs/pnx8335-stb225_defconfig
index 39926a1..f292576 100644
--- a/arch/mips/configs/pnx8335-stb225_defconfig
+++ b/arch/mips/configs/pnx8335-stb225_defconfig
@@ -11,7 +11,7 @@ CONFIG_EXPERIMENTAL=y
CONFIG_SYSVIPC=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
CONFIG_SLAB=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
diff --git a/arch/mips/configs/pnx8550-jbs_defconfig b/arch/mips/configs/pnx8550-jbs_defconfig
index 3376bc8..1d1f206 100644
--- a/arch/mips/configs/pnx8550-jbs_defconfig
+++ b/arch/mips/configs/pnx8550-jbs_defconfig
@@ -6,7 +6,7 @@ CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_SYSCTL_SYSCALL is not set
CONFIG_SLAB=y
CONFIG_MODULES=y
diff --git a/arch/mips/configs/pnx8550-stb810_defconfig b/arch/mips/configs/pnx8550-stb810_defconfig
index 6514f1b..15c66a5 100644
--- a/arch/mips/configs/pnx8550-stb810_defconfig
+++ b/arch/mips/configs/pnx8550-stb810_defconfig
@@ -6,7 +6,7 @@ CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_SYSCTL_SYSCALL is not set
# CONFIG_HOTPLUG is not set
CONFIG_SLAB=y
diff --git a/arch/mips/configs/powertv_defconfig b/arch/mips/configs/powertv_defconfig
index f1f58e91..3b0b6e8 100644
--- a/arch/mips/configs/powertv_defconfig
+++ b/arch/mips/configs/powertv_defconfig
@@ -14,7 +14,7 @@ CONFIG_RELAY=y
CONFIG_BLK_DEV_INITRD=y
# CONFIG_RD_GZIP is not set
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_SYSCTL_SYSCALL is not set
CONFIG_KALLSYMS_ALL=y
# CONFIG_PCSPKR_PLATFORM is not set
diff --git a/arch/mips/configs/rb532_defconfig b/arch/mips/configs/rb532_defconfig
index d6457bc..55902d9 100644
--- a/arch/mips/configs/rb532_defconfig
+++ b/arch/mips/configs/rb532_defconfig
@@ -13,7 +13,7 @@ CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_SYSFS_DEPRECATED_V2=y
CONFIG_BLK_DEV_INITRD=y
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_KALLSYMS is not set
# CONFIG_ELF_CORE is not set
# CONFIG_VM_EVENT_COUNTERS is not set
diff --git a/arch/mips/configs/rbtx49xx_defconfig b/arch/mips/configs/rbtx49xx_defconfig
index 29acfab..9cba856 100644
--- a/arch/mips/configs/rbtx49xx_defconfig
+++ b/arch/mips/configs/rbtx49xx_defconfig
@@ -12,7 +12,7 @@ CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_SYSFS_DEPRECATED_V2=y
CONFIG_BLK_DEV_INITRD=y
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_HOTPLUG is not set
# CONFIG_PCSPKR_PLATFORM is not set
# CONFIG_EPOLL is not set
diff --git a/arch/mips/configs/rm200_defconfig b/arch/mips/configs/rm200_defconfig
index 2b3e476..2c0230e 100644
--- a/arch/mips/configs/rm200_defconfig
+++ b/arch/mips/configs/rm200_defconfig
@@ -12,7 +12,7 @@ CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_RELAY=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
CONFIG_SLAB=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
diff --git a/arch/mips/configs/sb1250-swarm_defconfig b/arch/mips/configs/sb1250-swarm_defconfig
index 64840d7..5b0463e 100644
--- a/arch/mips/configs/sb1250-swarm_defconfig
+++ b/arch/mips/configs/sb1250-swarm_defconfig
@@ -15,7 +15,7 @@ CONFIG_RELAY=y
CONFIG_NAMESPACES=y
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_COMPAT_BRK is not set
CONFIG_SLAB=y
CONFIG_MODULES=y
diff --git a/arch/mips/configs/tb0219_defconfig b/arch/mips/configs/tb0219_defconfig
index d9be37f..30036b4 100644
--- a/arch/mips/configs/tb0219_defconfig
+++ b/arch/mips/configs/tb0219_defconfig
@@ -5,7 +5,7 @@ CONFIG_SYSVIPC=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_SYSFS_DEPRECATED_V2=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_PCSPKR_PLATFORM is not set
CONFIG_SLAB=y
CONFIG_MODULES=y
diff --git a/arch/mips/configs/tb0226_defconfig b/arch/mips/configs/tb0226_defconfig
index 3d25dd0..81bfa1d 100644
--- a/arch/mips/configs/tb0226_defconfig
+++ b/arch/mips/configs/tb0226_defconfig
@@ -5,7 +5,7 @@ CONFIG_SYSVIPC=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_SYSFS_DEPRECATED_V2=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_PCSPKR_PLATFORM is not set
CONFIG_SLAB=y
CONFIG_MODULES=y
diff --git a/arch/mips/configs/tb0287_defconfig b/arch/mips/configs/tb0287_defconfig
index be697c9..c415c4f 100644
--- a/arch/mips/configs/tb0287_defconfig
+++ b/arch/mips/configs/tb0287_defconfig
@@ -4,7 +4,7 @@ CONFIG_SYSVIPC=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_SYSFS_DEPRECATED_V2=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_SYSCTL_SYSCALL is not set
# CONFIG_PCSPKR_PLATFORM is not set
CONFIG_SLAB=y
diff --git a/arch/mips/configs/workpad_defconfig b/arch/mips/configs/workpad_defconfig
index 7ec9287..ee4b2be 100644
--- a/arch/mips/configs/workpad_defconfig
+++ b/arch/mips/configs/workpad_defconfig
@@ -4,7 +4,7 @@ CONFIG_EXPERIMENTAL=y
CONFIG_SYSVIPC=y
CONFIG_LOG_BUF_SHIFT=14
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
CONFIG_SLAB=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
diff --git a/arch/mips/configs/wrppmc_defconfig b/arch/mips/configs/wrppmc_defconfig
index a231b73..44a451b 100644
--- a/arch/mips/configs/wrppmc_defconfig
+++ b/arch/mips/configs/wrppmc_defconfig
@@ -7,7 +7,7 @@ CONFIG_BSD_PROCESS_ACCT=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
CONFIG_KALLSYMS_EXTRA_PASS=y
# CONFIG_EPOLL is not set
CONFIG_SLAB=y
diff --git a/arch/mips/configs/yosemite_defconfig b/arch/mips/configs/yosemite_defconfig
index ab3a3dc..f72d305 100644
--- a/arch/mips/configs/yosemite_defconfig
+++ b/arch/mips/configs/yosemite_defconfig
@@ -8,7 +8,7 @@ CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_RELAY=y
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
CONFIG_SLAB=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
diff --git a/arch/mips/include/asm/cache.h b/arch/mips/include/asm/cache.h
index 37f175c..650ac9b 100644
--- a/arch/mips/include/asm/cache.h
+++ b/arch/mips/include/asm/cache.h
@@ -17,4 +17,6 @@
#define SMP_CACHE_SHIFT L1_CACHE_SHIFT
#define SMP_CACHE_BYTES L1_CACHE_BYTES
+#define __read_mostly __attribute__((__section__(".data.read_mostly")))
+
#endif /* _ASM_CACHE_H */
diff --git a/arch/mips/include/asm/cpu-info.h b/arch/mips/include/asm/cpu-info.h
index b39def3..c454550 100644
--- a/arch/mips/include/asm/cpu-info.h
+++ b/arch/mips/include/asm/cpu-info.h
@@ -78,6 +78,7 @@ struct cpuinfo_mips {
unsigned int watch_reg_use_cnt; /* Usable by ptrace */
#define NUM_WATCH_REGS 4
u16 watch_reg_masks[NUM_WATCH_REGS];
+ unsigned int kscratch_mask; /* Usable KScratch mask. */
} __attribute__((aligned(SMP_CACHE_BYTES)));
extern struct cpuinfo_mips cpu_data[];
diff --git a/arch/mips/include/asm/inst.h b/arch/mips/include/asm/inst.h
index 444ff71..7ebfc39 100644
--- a/arch/mips/include/asm/inst.h
+++ b/arch/mips/include/asm/inst.h
@@ -72,6 +72,7 @@ enum spec2_op {
enum spec3_op {
ext_op, dextm_op, dextu_op, dext_op,
ins_op, dinsm_op, dinsu_op, dins_op,
+ lx_op = 0x0a,
bshfl_op = 0x20,
dbshfl_op = 0x24,
rdhwr_op = 0x3b
@@ -179,6 +180,19 @@ enum mad_func {
};
/*
+ * func field for special3 lx opcodes (Cavium Octeon).
+ */
+enum lx_func {
+ lwx_op = 0x00,
+ lhx_op = 0x04,
+ lbux_op = 0x06,
+ ldx_op = 0x08,
+ lwux_op = 0x10,
+ lhux_op = 0x14,
+ lbx_op = 0x16,
+};
+
+/*
* Damn ... bitfields depend from byteorder :-(
*/
#ifdef __MIPSEB__
diff --git a/arch/mips/include/asm/jump_label.h b/arch/mips/include/asm/jump_label.h
new file mode 100644
index 0000000..7622ccf
--- /dev/null
+++ b/arch/mips/include/asm/jump_label.h
@@ -0,0 +1,48 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (c) 2010 Cavium Networks, Inc.
+ */
+#ifndef _ASM_MIPS_JUMP_LABEL_H
+#define _ASM_MIPS_JUMP_LABEL_H
+
+#include <linux/types.h>
+
+#ifdef __KERNEL__
+
+#define JUMP_LABEL_NOP_SIZE 4
+
+#ifdef CONFIG_64BIT
+#define WORD_INSN ".dword"
+#else
+#define WORD_INSN ".word"
+#endif
+
+#define JUMP_LABEL(key, label) \
+ do { \
+ asm goto("1:\tnop\n\t" \
+ "nop\n\t" \
+ ".pushsection __jump_table, \"a\"\n\t" \
+ WORD_INSN " 1b, %l[" #label "], %0\n\t" \
+ ".popsection\n\t" \
+ : : "i" (key) : : label); \
+ } while (0)
+
+
+#endif /* __KERNEL__ */
+
+#ifdef CONFIG_64BIT
+typedef u64 jump_label_t;
+#else
+typedef u32 jump_label_t;
+#endif
+
+struct jump_entry {
+ jump_label_t code;
+ jump_label_t target;
+ jump_label_t key;
+};
+
+#endif /* _ASM_MIPS_JUMP_LABEL_H */
diff --git a/arch/mips/include/asm/mach-ath79/ar71xx_regs.h b/arch/mips/include/asm/mach-ath79/ar71xx_regs.h
new file mode 100644
index 0000000..cda1c80
--- /dev/null
+++ b/arch/mips/include/asm/mach-ath79/ar71xx_regs.h
@@ -0,0 +1,233 @@
+/*
+ * Atheros AR71XX/AR724X/AR913X SoC register definitions
+ *
+ * Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org>
+ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
+ *
+ * Parts of this file are based on Atheros' 2.6.15 BSP
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#ifndef __ASM_MACH_AR71XX_REGS_H
+#define __ASM_MACH_AR71XX_REGS_H
+
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/bitops.h>
+
+#define AR71XX_APB_BASE 0x18000000
+#define AR71XX_SPI_BASE 0x1f000000
+#define AR71XX_SPI_SIZE 0x01000000
+
+#define AR71XX_DDR_CTRL_BASE (AR71XX_APB_BASE + 0x00000000)
+#define AR71XX_DDR_CTRL_SIZE 0x100
+#define AR71XX_UART_BASE (AR71XX_APB_BASE + 0x00020000)
+#define AR71XX_UART_SIZE 0x100
+#define AR71XX_GPIO_BASE (AR71XX_APB_BASE + 0x00040000)
+#define AR71XX_GPIO_SIZE 0x100
+#define AR71XX_PLL_BASE (AR71XX_APB_BASE + 0x00050000)
+#define AR71XX_PLL_SIZE 0x100
+#define AR71XX_RESET_BASE (AR71XX_APB_BASE + 0x00060000)
+#define AR71XX_RESET_SIZE 0x100
+
+#define AR913X_WMAC_BASE (AR71XX_APB_BASE + 0x000C0000)
+#define AR913X_WMAC_SIZE 0x30000
+
+/*
+ * DDR_CTRL block
+ */
+#define AR71XX_DDR_REG_PCI_WIN0 0x7c
+#define AR71XX_DDR_REG_PCI_WIN1 0x80
+#define AR71XX_DDR_REG_PCI_WIN2 0x84
+#define AR71XX_DDR_REG_PCI_WIN3 0x88
+#define AR71XX_DDR_REG_PCI_WIN4 0x8c
+#define AR71XX_DDR_REG_PCI_WIN5 0x90
+#define AR71XX_DDR_REG_PCI_WIN6 0x94
+#define AR71XX_DDR_REG_PCI_WIN7 0x98
+#define AR71XX_DDR_REG_FLUSH_GE0 0x9c
+#define AR71XX_DDR_REG_FLUSH_GE1 0xa0
+#define AR71XX_DDR_REG_FLUSH_USB 0xa4
+#define AR71XX_DDR_REG_FLUSH_PCI 0xa8
+
+#define AR724X_DDR_REG_FLUSH_GE0 0x7c
+#define AR724X_DDR_REG_FLUSH_GE1 0x80
+#define AR724X_DDR_REG_FLUSH_USB 0x84
+#define AR724X_DDR_REG_FLUSH_PCIE 0x88
+
+#define AR913X_DDR_REG_FLUSH_GE0 0x7c
+#define AR913X_DDR_REG_FLUSH_GE1 0x80
+#define AR913X_DDR_REG_FLUSH_USB 0x84
+#define AR913X_DDR_REG_FLUSH_WMAC 0x88
+
+/*
+ * PLL block
+ */
+#define AR71XX_PLL_REG_CPU_CONFIG 0x00
+#define AR71XX_PLL_REG_SEC_CONFIG 0x04
+#define AR71XX_PLL_REG_ETH0_INT_CLOCK 0x10
+#define AR71XX_PLL_REG_ETH1_INT_CLOCK 0x14
+
+#define AR71XX_PLL_DIV_SHIFT 3
+#define AR71XX_PLL_DIV_MASK 0x1f
+#define AR71XX_CPU_DIV_SHIFT 16
+#define AR71XX_CPU_DIV_MASK 0x3
+#define AR71XX_DDR_DIV_SHIFT 18
+#define AR71XX_DDR_DIV_MASK 0x3
+#define AR71XX_AHB_DIV_SHIFT 20
+#define AR71XX_AHB_DIV_MASK 0x7
+
+#define AR724X_PLL_REG_CPU_CONFIG 0x00
+#define AR724X_PLL_REG_PCIE_CONFIG 0x18
+
+#define AR724X_PLL_DIV_SHIFT 0
+#define AR724X_PLL_DIV_MASK 0x3ff
+#define AR724X_PLL_REF_DIV_SHIFT 10
+#define AR724X_PLL_REF_DIV_MASK 0xf
+#define AR724X_AHB_DIV_SHIFT 19
+#define AR724X_AHB_DIV_MASK 0x1
+#define AR724X_DDR_DIV_SHIFT 22
+#define AR724X_DDR_DIV_MASK 0x3
+
+#define AR913X_PLL_REG_CPU_CONFIG 0x00
+#define AR913X_PLL_REG_ETH_CONFIG 0x04
+#define AR913X_PLL_REG_ETH0_INT_CLOCK 0x14
+#define AR913X_PLL_REG_ETH1_INT_CLOCK 0x18
+
+#define AR913X_PLL_DIV_SHIFT 0
+#define AR913X_PLL_DIV_MASK 0x3ff
+#define AR913X_DDR_DIV_SHIFT 22
+#define AR913X_DDR_DIV_MASK 0x3
+#define AR913X_AHB_DIV_SHIFT 19
+#define AR913X_AHB_DIV_MASK 0x1
+
+/*
+ * RESET block
+ */
+#define AR71XX_RESET_REG_TIMER 0x00
+#define AR71XX_RESET_REG_TIMER_RELOAD 0x04
+#define AR71XX_RESET_REG_WDOG_CTRL 0x08
+#define AR71XX_RESET_REG_WDOG 0x0c
+#define AR71XX_RESET_REG_MISC_INT_STATUS 0x10
+#define AR71XX_RESET_REG_MISC_INT_ENABLE 0x14
+#define AR71XX_RESET_REG_PCI_INT_STATUS 0x18
+#define AR71XX_RESET_REG_PCI_INT_ENABLE 0x1c
+#define AR71XX_RESET_REG_GLOBAL_INT_STATUS 0x20
+#define AR71XX_RESET_REG_RESET_MODULE 0x24
+#define AR71XX_RESET_REG_PERFC_CTRL 0x2c
+#define AR71XX_RESET_REG_PERFC0 0x30
+#define AR71XX_RESET_REG_PERFC1 0x34
+#define AR71XX_RESET_REG_REV_ID 0x90
+
+#define AR913X_RESET_REG_GLOBAL_INT_STATUS 0x18
+#define AR913X_RESET_REG_RESET_MODULE 0x1c
+#define AR913X_RESET_REG_PERF_CTRL 0x20
+#define AR913X_RESET_REG_PERFC0 0x24
+#define AR913X_RESET_REG_PERFC1 0x28
+
+#define AR724X_RESET_REG_RESET_MODULE 0x1c
+
+#define MISC_INT_DMA BIT(7)
+#define MISC_INT_OHCI BIT(6)
+#define MISC_INT_PERFC BIT(5)
+#define MISC_INT_WDOG BIT(4)
+#define MISC_INT_UART BIT(3)
+#define MISC_INT_GPIO BIT(2)
+#define MISC_INT_ERROR BIT(1)
+#define MISC_INT_TIMER BIT(0)
+
+#define AR71XX_RESET_EXTERNAL BIT(28)
+#define AR71XX_RESET_FULL_CHIP BIT(24)
+#define AR71XX_RESET_CPU_NMI BIT(21)
+#define AR71XX_RESET_CPU_COLD BIT(20)
+#define AR71XX_RESET_DMA BIT(19)
+#define AR71XX_RESET_SLIC BIT(18)
+#define AR71XX_RESET_STEREO BIT(17)
+#define AR71XX_RESET_DDR BIT(16)
+#define AR71XX_RESET_GE1_MAC BIT(13)
+#define AR71XX_RESET_GE1_PHY BIT(12)
+#define AR71XX_RESET_USBSUS_OVERRIDE BIT(10)
+#define AR71XX_RESET_GE0_MAC BIT(9)
+#define AR71XX_RESET_GE0_PHY BIT(8)
+#define AR71XX_RESET_USB_OHCI_DLL BIT(6)
+#define AR71XX_RESET_USB_HOST BIT(5)
+#define AR71XX_RESET_USB_PHY BIT(4)
+#define AR71XX_RESET_PCI_BUS BIT(1)
+#define AR71XX_RESET_PCI_CORE BIT(0)
+
+#define AR724X_RESET_GE1_MDIO BIT(23)
+#define AR724X_RESET_GE0_MDIO BIT(22)
+#define AR724X_RESET_PCIE_PHY_SERIAL BIT(10)
+#define AR724X_RESET_PCIE_PHY BIT(7)
+#define AR724X_RESET_PCIE BIT(6)
+#define AR724X_RESET_OHCI_DLL BIT(3)
+
+#define AR913X_RESET_AMBA2WMAC BIT(22)
+
+#define REV_ID_MAJOR_MASK 0xfff0
+#define REV_ID_MAJOR_AR71XX 0x00a0
+#define REV_ID_MAJOR_AR913X 0x00b0
+#define REV_ID_MAJOR_AR7240 0x00c0
+#define REV_ID_MAJOR_AR7241 0x0100
+#define REV_ID_MAJOR_AR7242 0x1100
+
+#define AR71XX_REV_ID_MINOR_MASK 0x3
+#define AR71XX_REV_ID_MINOR_AR7130 0x0
+#define AR71XX_REV_ID_MINOR_AR7141 0x1
+#define AR71XX_REV_ID_MINOR_AR7161 0x2
+#define AR71XX_REV_ID_REVISION_MASK 0x3
+#define AR71XX_REV_ID_REVISION_SHIFT 2
+
+#define AR913X_REV_ID_MINOR_MASK 0x3
+#define AR913X_REV_ID_MINOR_AR9130 0x0
+#define AR913X_REV_ID_MINOR_AR9132 0x1
+#define AR913X_REV_ID_REVISION_MASK 0x3
+#define AR913X_REV_ID_REVISION_SHIFT 2
+
+#define AR724X_REV_ID_REVISION_MASK 0x3
+
+/*
+ * SPI block
+ */
+#define AR71XX_SPI_REG_FS 0x00 /* Function Select */
+#define AR71XX_SPI_REG_CTRL 0x04 /* SPI Control */
+#define AR71XX_SPI_REG_IOC 0x08 /* SPI I/O Control */
+#define AR71XX_SPI_REG_RDS 0x0c /* Read Data Shift */
+
+#define AR71XX_SPI_FS_GPIO BIT(0) /* Enable GPIO mode */
+
+#define AR71XX_SPI_CTRL_RD BIT(6) /* Remap Disable */
+#define AR71XX_SPI_CTRL_DIV_MASK 0x3f
+
+#define AR71XX_SPI_IOC_DO BIT(0) /* Data Out pin */
+#define AR71XX_SPI_IOC_CLK BIT(8) /* CLK pin */
+#define AR71XX_SPI_IOC_CS(n) BIT(16 + (n))
+#define AR71XX_SPI_IOC_CS0 AR71XX_SPI_IOC_CS(0)
+#define AR71XX_SPI_IOC_CS1 AR71XX_SPI_IOC_CS(1)
+#define AR71XX_SPI_IOC_CS2 AR71XX_SPI_IOC_CS(2)
+#define AR71XX_SPI_IOC_CS_ALL (AR71XX_SPI_IOC_CS0 | AR71XX_SPI_IOC_CS1 | \
+ AR71XX_SPI_IOC_CS2)
+
+/*
+ * GPIO block
+ */
+#define AR71XX_GPIO_REG_OE 0x00
+#define AR71XX_GPIO_REG_IN 0x04
+#define AR71XX_GPIO_REG_OUT 0x08
+#define AR71XX_GPIO_REG_SET 0x0c
+#define AR71XX_GPIO_REG_CLEAR 0x10
+#define AR71XX_GPIO_REG_INT_MODE 0x14
+#define AR71XX_GPIO_REG_INT_TYPE 0x18
+#define AR71XX_GPIO_REG_INT_POLARITY 0x1c
+#define AR71XX_GPIO_REG_INT_PENDING 0x20
+#define AR71XX_GPIO_REG_INT_ENABLE 0x24
+#define AR71XX_GPIO_REG_FUNC 0x28
+
+#define AR71XX_GPIO_COUNT 16
+#define AR724X_GPIO_COUNT 18
+#define AR913X_GPIO_COUNT 22
+
+#endif /* __ASM_MACH_AR71XX_REGS_H */
diff --git a/arch/mips/include/asm/mach-ath79/ath79.h b/arch/mips/include/asm/mach-ath79/ath79.h
new file mode 100644
index 0000000..6a9f168
--- /dev/null
+++ b/arch/mips/include/asm/mach-ath79/ath79.h
@@ -0,0 +1,96 @@
+/*
+ * Atheros AR71XX/AR724X/AR913X common definitions
+ *
+ * Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org>
+ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
+ *
+ * Parts of this file are based on Atheros' 2.6.15 BSP
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#ifndef __ASM_MACH_ATH79_H
+#define __ASM_MACH_ATH79_H
+
+#include <linux/types.h>
+#include <linux/io.h>
+
+enum ath79_soc_type {
+ ATH79_SOC_UNKNOWN,
+ ATH79_SOC_AR7130,
+ ATH79_SOC_AR7141,
+ ATH79_SOC_AR7161,
+ ATH79_SOC_AR7240,
+ ATH79_SOC_AR7241,
+ ATH79_SOC_AR7242,
+ ATH79_SOC_AR9130,
+ ATH79_SOC_AR9132
+};
+
+extern enum ath79_soc_type ath79_soc;
+
+static inline int soc_is_ar71xx(void)
+{
+ return (ath79_soc == ATH79_SOC_AR7130 ||
+ ath79_soc == ATH79_SOC_AR7141 ||
+ ath79_soc == ATH79_SOC_AR7161);
+}
+
+static inline int soc_is_ar724x(void)
+{
+ return (ath79_soc == ATH79_SOC_AR7240 ||
+ ath79_soc == ATH79_SOC_AR7241 ||
+ ath79_soc == ATH79_SOC_AR7242);
+}
+
+static inline int soc_is_ar7240(void)
+{
+ return (ath79_soc == ATH79_SOC_AR7240);
+}
+
+static inline int soc_is_ar7241(void)
+{
+ return (ath79_soc == ATH79_SOC_AR7241);
+}
+
+static inline int soc_is_ar7242(void)
+{
+ return (ath79_soc == ATH79_SOC_AR7242);
+}
+
+static inline int soc_is_ar913x(void)
+{
+ return (ath79_soc == ATH79_SOC_AR9130 ||
+ ath79_soc == ATH79_SOC_AR9132);
+}
+
+extern void __iomem *ath79_ddr_base;
+extern void __iomem *ath79_pll_base;
+extern void __iomem *ath79_reset_base;
+
+static inline void ath79_pll_wr(unsigned reg, u32 val)
+{
+ __raw_writel(val, ath79_pll_base + reg);
+}
+
+static inline u32 ath79_pll_rr(unsigned reg)
+{
+ return __raw_readl(ath79_pll_base + reg);
+}
+
+static inline void ath79_reset_wr(unsigned reg, u32 val)
+{
+ __raw_writel(val, ath79_reset_base + reg);
+}
+
+static inline u32 ath79_reset_rr(unsigned reg)
+{
+ return __raw_readl(ath79_reset_base + reg);
+}
+
+void ath79_device_reset_set(u32 mask);
+void ath79_device_reset_clear(u32 mask);
+
+#endif /* __ASM_MACH_ATH79_H */
diff --git a/arch/mips/include/asm/mach-ath79/ath79_spi_platform.h b/arch/mips/include/asm/mach-ath79/ath79_spi_platform.h
new file mode 100644
index 0000000..aa2283e
--- /dev/null
+++ b/arch/mips/include/asm/mach-ath79/ath79_spi_platform.h
@@ -0,0 +1,23 @@
+/*
+ * Platform data definition for Atheros AR71XX/AR724X/AR913X SPI controller
+ *
+ * Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * 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 _ATH79_SPI_PLATFORM_H
+#define _ATH79_SPI_PLATFORM_H
+
+struct ath79_spi_platform_data {
+ unsigned bus_num;
+ unsigned num_chipselect;
+};
+
+struct ath79_spi_controller_data {
+ unsigned gpio;
+};
+
+#endif /* _ATH79_SPI_PLATFORM_H */
diff --git a/arch/mips/include/asm/mach-ath79/cpu-feature-overrides.h b/arch/mips/include/asm/mach-ath79/cpu-feature-overrides.h
new file mode 100644
index 0000000..4476fa0
--- /dev/null
+++ b/arch/mips/include/asm/mach-ath79/cpu-feature-overrides.h
@@ -0,0 +1,56 @@
+/*
+ * Atheros AR71XX/AR724X/AR913X specific CPU feature overrides
+ *
+ * Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org>
+ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
+ *
+ * This file was derived from: include/asm-mips/cpu-features.h
+ * Copyright (C) 2003, 2004 Ralf Baechle
+ * Copyright (C) 2004 Maciej W. Rozycki
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ */
+#ifndef __ASM_MACH_ATH79_CPU_FEATURE_OVERRIDES_H
+#define __ASM_MACH_ATH79_CPU_FEATURE_OVERRIDES_H
+
+#define cpu_has_tlb 1
+#define cpu_has_4kex 1
+#define cpu_has_3k_cache 0
+#define cpu_has_4k_cache 1
+#define cpu_has_tx39_cache 0
+#define cpu_has_sb1_cache 0
+#define cpu_has_fpu 0
+#define cpu_has_32fpr 0
+#define cpu_has_counter 1
+#define cpu_has_watch 1
+#define cpu_has_divec 1
+
+#define cpu_has_prefetch 1
+#define cpu_has_ejtag 1
+#define cpu_has_llsc 1
+
+#define cpu_has_mips16 1
+#define cpu_has_mdmx 0
+#define cpu_has_mips3d 0
+#define cpu_has_smartmips 0
+
+#define cpu_has_mips32r1 1
+#define cpu_has_mips32r2 1
+#define cpu_has_mips64r1 0
+#define cpu_has_mips64r2 0
+
+#define cpu_has_dsp 0
+#define cpu_has_mipsmt 0
+
+#define cpu_has_64bits 0
+#define cpu_has_64bit_zero_reg 0
+#define cpu_has_64bit_gp_regs 0
+#define cpu_has_64bit_addresses 0
+
+#define cpu_dcache_line_size() 32
+#define cpu_icache_line_size() 32
+
+#endif /* __ASM_MACH_ATH79_CPU_FEATURE_OVERRIDES_H */
diff --git a/arch/mips/include/asm/mach-ath79/gpio.h b/arch/mips/include/asm/mach-ath79/gpio.h
new file mode 100644
index 0000000..60dcb62
--- /dev/null
+++ b/arch/mips/include/asm/mach-ath79/gpio.h
@@ -0,0 +1,26 @@
+/*
+ * Atheros AR71XX/AR724X/AR913X GPIO API definitions
+ *
+ * Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org>
+ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ */
+
+#ifndef __ASM_MACH_ATH79_GPIO_H
+#define __ASM_MACH_ATH79_GPIO_H
+
+#define ARCH_NR_GPIOS 64
+#include <asm-generic/gpio.h>
+
+int gpio_to_irq(unsigned gpio);
+int irq_to_gpio(unsigned irq);
+int gpio_get_value(unsigned gpio);
+void gpio_set_value(unsigned gpio, int value);
+
+#define gpio_cansleep __gpio_cansleep
+
+#endif /* __ASM_MACH_ATH79_GPIO_H */
diff --git a/arch/mips/include/asm/mach-ath79/irq.h b/arch/mips/include/asm/mach-ath79/irq.h
new file mode 100644
index 0000000..189bc6e
--- /dev/null
+++ b/arch/mips/include/asm/mach-ath79/irq.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org>
+ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+#ifndef __ASM_MACH_ATH79_IRQ_H
+#define __ASM_MACH_ATH79_IRQ_H
+
+#define MIPS_CPU_IRQ_BASE 0
+#define NR_IRQS 16
+
+#define ATH79_MISC_IRQ_BASE 8
+#define ATH79_MISC_IRQ_COUNT 8
+
+#define ATH79_CPU_IRQ_IP2 (MIPS_CPU_IRQ_BASE + 2)
+#define ATH79_CPU_IRQ_USB (MIPS_CPU_IRQ_BASE + 3)
+#define ATH79_CPU_IRQ_GE0 (MIPS_CPU_IRQ_BASE + 4)
+#define ATH79_CPU_IRQ_GE1 (MIPS_CPU_IRQ_BASE + 5)
+#define ATH79_CPU_IRQ_MISC (MIPS_CPU_IRQ_BASE + 6)
+#define ATH79_CPU_IRQ_TIMER (MIPS_CPU_IRQ_BASE + 7)
+
+#define ATH79_MISC_IRQ_TIMER (ATH79_MISC_IRQ_BASE + 0)
+#define ATH79_MISC_IRQ_ERROR (ATH79_MISC_IRQ_BASE + 1)
+#define ATH79_MISC_IRQ_GPIO (ATH79_MISC_IRQ_BASE + 2)
+#define ATH79_MISC_IRQ_UART (ATH79_MISC_IRQ_BASE + 3)
+#define ATH79_MISC_IRQ_WDOG (ATH79_MISC_IRQ_BASE + 4)
+#define ATH79_MISC_IRQ_PERFC (ATH79_MISC_IRQ_BASE + 5)
+#define ATH79_MISC_IRQ_OHCI (ATH79_MISC_IRQ_BASE + 6)
+#define ATH79_MISC_IRQ_DMA (ATH79_MISC_IRQ_BASE + 7)
+
+#include_next <irq.h>
+
+#endif /* __ASM_MACH_ATH79_IRQ_H */
diff --git a/arch/mips/include/asm/mach-ath79/kernel-entry-init.h b/arch/mips/include/asm/mach-ath79/kernel-entry-init.h
new file mode 100644
index 0000000..d8d046b
--- /dev/null
+++ b/arch/mips/include/asm/mach-ath79/kernel-entry-init.h
@@ -0,0 +1,32 @@
+/*
+ * Atheros AR71XX/AR724X/AR913X specific kernel entry setup
+ *
+ * Copyright (C) 2009 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ */
+#ifndef __ASM_MACH_ATH79_KERNEL_ENTRY_H
+#define __ASM_MACH_ATH79_KERNEL_ENTRY_H
+
+ /*
+ * Some bootloaders set the 'Kseg0 coherency algorithm' to
+ * 'Cacheable, noncoherent, write-through, no write allocate'
+ * and this cause performance issues. Let's go and change it to
+ * 'Cacheable, noncoherent, write-back, write allocate'
+ */
+ .macro kernel_entry_setup
+ mfc0 t0, CP0_CONFIG
+ li t1, ~CONF_CM_CMASK
+ and t0, t1
+ ori t0, CONF_CM_CACHABLE_NONCOHERENT
+ mtc0 t0, CP0_CONFIG
+ nop
+ .endm
+
+ .macro smp_slave_setup
+ .endm
+
+#endif /* __ASM_MACH_ATH79_KERNEL_ENTRY_H */
diff --git a/arch/mips/include/asm/mach-ath79/war.h b/arch/mips/include/asm/mach-ath79/war.h
new file mode 100644
index 0000000..323d9f1
--- /dev/null
+++ b/arch/mips/include/asm/mach-ath79/war.h
@@ -0,0 +1,25 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2002, 2004, 2007 by Ralf Baechle <ralf@linux-mips.org>
+ */
+#ifndef __ASM_MACH_ATH79_WAR_H
+#define __ASM_MACH_ATH79_WAR_H
+
+#define R4600_V1_INDEX_ICACHEOP_WAR 0
+#define R4600_V1_HIT_CACHEOP_WAR 0
+#define R4600_V2_HIT_CACHEOP_WAR 0
+#define R5432_CP0_INTERRUPT_WAR 0
+#define BCM1250_M3_WAR 0
+#define SIBYTE_1956_WAR 0
+#define MIPS4K_ICACHE_REFILL_WAR 0
+#define MIPS_CACHE_SYNC_WAR 0
+#define TX49XX_ICACHE_INDEX_INV_WAR 0
+#define RM9000_CDEX_SMP_WAR 0
+#define ICACHE_REFILLS_WORKAROUND_WAR 0
+#define R10000_LLSC_WAR 0
+#define MIPS34K_MISSED_ITLB_WAR 0
+
+#endif /* __ASM_MACH_ATH79_WAR_H */
diff --git a/arch/mips/include/asm/mips_machine.h b/arch/mips/include/asm/mips_machine.h
new file mode 100644
index 0000000..363bb35
--- /dev/null
+++ b/arch/mips/include/asm/mips_machine.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ */
+
+#ifndef __ASM_MIPS_MACHINE_H
+#define __ASM_MIPS_MACHINE_H
+
+#include <linux/init.h>
+#include <linux/stddef.h>
+
+#include <asm/bootinfo.h>
+
+struct mips_machine {
+ unsigned long mach_type;
+ const char *mach_id;
+ const char *mach_name;
+ void (*mach_setup)(void);
+};
+
+#define MIPS_MACHINE(_type, _id, _name, _setup) \
+static const char machine_name_##_type[] __initconst \
+ __aligned(1) = _name; \
+static const char machine_id_##_type[] __initconst \
+ __aligned(1) = _id; \
+static struct mips_machine machine_##_type \
+ __used __section(.mips.machines.init) = \
+{ \
+ .mach_type = _type, \
+ .mach_id = machine_id_##_type, \
+ .mach_name = machine_name_##_type, \
+ .mach_setup = _setup, \
+};
+
+extern long __mips_machines_start;
+extern long __mips_machines_end;
+
+#ifdef CONFIG_MIPS_MACHINE
+int mips_machtype_setup(char *id) __init;
+void mips_machine_setup(void) __init;
+void mips_set_machine_name(const char *name) __init;
+char *mips_get_machine_name(void);
+#else
+static inline int mips_machtype_setup(char *id) { return 1; }
+static inline void mips_machine_setup(void) { }
+static inline void mips_set_machine_name(const char *name) { }
+static inline char *mips_get_machine_name(void) { return NULL; }
+#endif /* CONFIG_MIPS_MACHINE */
+
+#endif /* __ASM_MIPS_MACHINE_H */
diff --git a/arch/mips/include/asm/mmu_context.h b/arch/mips/include/asm/mmu_context.h
index d959273..73c0d45 100644
--- a/arch/mips/include/asm/mmu_context.h
+++ b/arch/mips/include/asm/mmu_context.h
@@ -29,13 +29,7 @@
#define TLBMISS_HANDLER_SETUP_PGD(pgd) \
tlbmiss_handler_setup_pgd((unsigned long)(pgd))
-static inline void tlbmiss_handler_setup_pgd(unsigned long pgd)
-{
- /* Check for swapper_pg_dir and convert to physical address. */
- if ((pgd & CKSEG3) == CKSEG0)
- pgd = CPHYSADDR(pgd);
- write_c0_context(pgd << 11);
-}
+extern void tlbmiss_handler_setup_pgd(unsigned long pgd);
#define TLBMISS_HANDLER_SETUP() \
do { \
diff --git a/arch/mips/include/asm/uasm.h b/arch/mips/include/asm/uasm.h
index 892062d..dcbd4bb 100644
--- a/arch/mips/include/asm/uasm.h
+++ b/arch/mips/include/asm/uasm.h
@@ -115,7 +115,12 @@ Ip_0(_tlbwr);
Ip_u3u1u2(_xor);
Ip_u2u1u3(_xori);
Ip_u2u1msbu3(_dins);
+Ip_u2u1msbu3(_dinsm);
Ip_u1(_syscall);
+Ip_u1u2s3(_bbit0);
+Ip_u1u2s3(_bbit1);
+Ip_u3u1u2(_lwx);
+Ip_u3u1u2(_ldx);
/* Handle labels. */
struct uasm_label {
@@ -153,6 +158,7 @@ static inline void __uasminit uasm_l##lb(struct uasm_label **lab, u32 *addr) \
# define UASM_i_SUBU(buf, rs, rt, rd) uasm_i_dsubu(buf, rs, rt, rd)
# define UASM_i_LL(buf, rs, rt, off) uasm_i_lld(buf, rs, rt, off)
# define UASM_i_SC(buf, rs, rt, off) uasm_i_scd(buf, rs, rt, off)
+# define UASM_i_LWX(buf, rs, rt, rd) uasm_i_ldx(buf, rs, rt, rd)
#else
# define UASM_i_LW(buf, rs, rt, off) uasm_i_lw(buf, rs, rt, off)
# define UASM_i_SW(buf, rs, rt, off) uasm_i_sw(buf, rs, rt, off)
@@ -167,6 +173,7 @@ static inline void __uasminit uasm_l##lb(struct uasm_label **lab, u32 *addr) \
# define UASM_i_SUBU(buf, rs, rt, rd) uasm_i_subu(buf, rs, rt, rd)
# define UASM_i_LL(buf, rs, rt, off) uasm_i_ll(buf, rs, rt, off)
# define UASM_i_SC(buf, rs, rt, off) uasm_i_sc(buf, rs, rt, off)
+# define UASM_i_LWX(buf, rs, rt, rd) uasm_i_lwx(buf, rs, rt, rd)
#endif
#define uasm_i_b(buf, off) uasm_i_beq(buf, 0, 0, off)
diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile
index 22b2e0e..cedee2b 100644
--- a/arch/mips/kernel/Makefile
+++ b/arch/mips/kernel/Makefile
@@ -95,6 +95,7 @@ obj-$(CONFIG_GPIO_TXX9) += gpio_txx9.o
obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o
obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
obj-$(CONFIG_SPINLOCK_TEST) += spinlock_test.o
+obj-$(CONFIG_MIPS_MACHINE) += mips_machine.o
obj-$(CONFIG_OF) += prom.o
@@ -106,4 +107,6 @@ obj-$(CONFIG_MIPS_CPUFREQ) += cpufreq/
obj-$(CONFIG_HW_PERF_EVENTS) += perf_event.o
+obj-$(CONFIG_JUMP_LABEL) += jump_label.o
+
CPPFLAGS_vmlinux.lds := $(KBUILD_CFLAGS)
diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c
index 68dae7b..f65d4c8 100644
--- a/arch/mips/kernel/cpu-probe.c
+++ b/arch/mips/kernel/cpu-probe.c
@@ -739,6 +739,8 @@ static inline unsigned int decode_config4(struct cpuinfo_mips *c)
&& cpu_has_tlb)
c->tlbsize += (config4 & MIPS_CONF4_MMUSIZEEXT) * 0x40;
+ c->kscratch_mask = (config4 >> 16) & 0xff;
+
return config4 & MIPS_CONF_M;
}
diff --git a/arch/mips/kernel/jump_label.c b/arch/mips/kernel/jump_label.c
new file mode 100644
index 0000000..6001610
--- /dev/null
+++ b/arch/mips/kernel/jump_label.c
@@ -0,0 +1,54 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (c) 2010 Cavium Networks, Inc.
+ */
+
+#include <linux/jump_label.h>
+#include <linux/kernel.h>
+#include <linux/memory.h>
+#include <linux/mutex.h>
+#include <linux/types.h>
+#include <linux/cpu.h>
+
+#include <asm/cacheflush.h>
+#include <asm/inst.h>
+
+#ifdef HAVE_JUMP_LABEL
+
+#define J_RANGE_MASK ((1ul << 28) - 1)
+
+void arch_jump_label_transform(struct jump_entry *e,
+ enum jump_label_type type)
+{
+ union mips_instruction insn;
+ union mips_instruction *insn_p =
+ (union mips_instruction *)(unsigned long)e->code;
+
+ /* Jump only works within a 256MB aligned region. */
+ BUG_ON((e->target & ~J_RANGE_MASK) != (e->code & ~J_RANGE_MASK));
+
+ /* Target must have 4 byte alignment. */
+ BUG_ON((e->target & 3) != 0);
+
+ if (type == JUMP_LABEL_ENABLE) {
+ insn.j_format.opcode = j_op;
+ insn.j_format.target = (e->target & J_RANGE_MASK) >> 2;
+ } else {
+ insn.word = 0; /* nop */
+ }
+
+ get_online_cpus();
+ mutex_lock(&text_mutex);
+ *insn_p = insn;
+
+ flush_icache_range((unsigned long)insn_p,
+ (unsigned long)insn_p + sizeof(*insn_p));
+
+ mutex_unlock(&text_mutex);
+ put_online_cpus();
+}
+
+#endif /* HAVE_JUMP_LABEL */
diff --git a/arch/mips/kernel/mips_machine.c b/arch/mips/kernel/mips_machine.c
new file mode 100644
index 0000000..411a058
--- /dev/null
+++ b/arch/mips/kernel/mips_machine.c
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * 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/mm.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+
+#include <asm/mips_machine.h>
+
+static struct mips_machine *mips_machine __initdata;
+static char *mips_machine_name = "Unknown";
+
+#define for_each_machine(mach) \
+ for ((mach) = (struct mips_machine *)&__mips_machines_start; \
+ (mach) && \
+ (unsigned long)(mach) < (unsigned long)&__mips_machines_end; \
+ (mach)++)
+
+__init void mips_set_machine_name(const char *name)
+{
+ char *p;
+
+ if (name == NULL)
+ return;
+
+ p = kstrdup(name, GFP_KERNEL);
+ if (!p)
+ pr_err("MIPS: no memory for machine_name\n");
+
+ mips_machine_name = p;
+}
+
+char *mips_get_machine_name(void)
+{
+ return mips_machine_name;
+}
+
+__init int mips_machtype_setup(char *id)
+{
+ struct mips_machine *mach;
+
+ for_each_machine(mach) {
+ if (mach->mach_id == NULL)
+ continue;
+
+ if (strcmp(mach->mach_id, id) == 0) {
+ mips_machtype = mach->mach_type;
+ return 0;
+ }
+ }
+
+ pr_err("MIPS: no machine found for id '%s', supported machines:\n", id);
+ pr_err("%-24s %s\n", "id", "name");
+ for_each_machine(mach)
+ pr_err("%-24s %s\n", mach->mach_id, mach->mach_name);
+
+ return 1;
+}
+
+__setup("machtype=", mips_machtype_setup);
+
+__init void mips_machine_setup(void)
+{
+ struct mips_machine *mach;
+
+ for_each_machine(mach) {
+ if (mips_machtype == mach->mach_type) {
+ mips_machine = mach;
+ break;
+ }
+ }
+
+ if (!mips_machine)
+ return;
+
+ mips_set_machine_name(mips_machine->mach_name);
+ pr_info("MIPS: machine is %s\n", mips_machine_name);
+
+ if (mips_machine->mach_setup)
+ mips_machine->mach_setup();
+}
diff --git a/arch/mips/kernel/module.c b/arch/mips/kernel/module.c
index d87a72e..dd940b7 100644
--- a/arch/mips/kernel/module.c
+++ b/arch/mips/kernel/module.c
@@ -30,6 +30,8 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/spinlock.h>
+#include <linux/jump_label.h>
+
#include <asm/pgtable.h> /* MODULE_START */
struct mips_hi16 {
@@ -382,6 +384,9 @@ int module_finalize(const Elf_Ehdr *hdr,
const Elf_Shdr *s;
char *secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
+ /* Make jump label nops. */
+ jump_label_apply_nops(me);
+
INIT_LIST_HEAD(&me->arch.dbe_list);
for (s = sechdrs; s < sechdrs + hdr->e_shnum; s++) {
if (strcmp("__dbe_table", secstrings + s->sh_name) != 0)
diff --git a/arch/mips/kernel/proc.c b/arch/mips/kernel/proc.c
index 26109c4..e309665 100644
--- a/arch/mips/kernel/proc.c
+++ b/arch/mips/kernel/proc.c
@@ -12,6 +12,7 @@
#include <asm/cpu-features.h>
#include <asm/mipsregs.h>
#include <asm/processor.h>
+#include <asm/mips_machine.h>
unsigned int vced_count, vcei_count;
@@ -31,8 +32,12 @@ static int show_cpuinfo(struct seq_file *m, void *v)
/*
* For the first processor also print the system type
*/
- if (n == 0)
+ if (n == 0) {
seq_printf(m, "system type\t\t: %s\n", get_system_type());
+ if (mips_get_machine_name())
+ seq_printf(m, "machine\t\t\t: %s\n",
+ mips_get_machine_name());
+ }
seq_printf(m, "processor\t\t: %ld\n", n);
sprintf(fmt, "cpu model\t\t: %%s V%%d.%%d%s\n",
@@ -69,6 +74,8 @@ static int show_cpuinfo(struct seq_file *m, void *v)
);
seq_printf(m, "shadow register sets\t: %d\n",
cpu_data[n].srsets);
+ seq_printf(m, "kscratch registers\t: %d\n",
+ hweight8(cpu_data[n].kscratch_mask));
seq_printf(m, "core\t\t\t: %d\n", cpu_data[n].core);
sprintf(fmt, "VCE%%c exceptions\t\t: %s\n",
diff --git a/arch/mips/kernel/prom.c b/arch/mips/kernel/prom.c
index 9dbe583..a19811e9 100644
--- a/arch/mips/kernel/prom.c
+++ b/arch/mips/kernel/prom.c
@@ -45,11 +45,9 @@ void __init free_mem_mach(unsigned long addr, unsigned long size)
return free_bootmem(addr, size);
}
-u64 __init early_init_dt_alloc_memory_arch(u64 size, u64 align)
+void * __init early_init_dt_alloc_memory_arch(u64 size, u64 align)
{
- return virt_to_phys(
- __alloc_bootmem(size, align, __pa(MAX_DMA_ADDRESS))
- );
+ return __alloc_bootmem(size, align, __pa(MAX_DMA_ADDRESS));
}
#ifdef CONFIG_BLK_DEV_INITRD
diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c
index acd3f2c..8ad1d56 100644
--- a/arch/mips/kernel/setup.c
+++ b/arch/mips/kernel/setup.c
@@ -70,7 +70,7 @@ static char __initdata builtin_cmdline[COMMAND_LINE_SIZE] = CONFIG_CMDLINE;
* mips_io_port_base is the begin of the address space to which x86 style
* I/O ports are mapped.
*/
-const unsigned long mips_io_port_base __read_mostly = -1;
+const unsigned long mips_io_port_base = -1;
EXPORT_SYMBOL(mips_io_port_base);
static struct resource code_resource = { .name = "Kernel code", };
diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c
index e971043..71350f7 100644
--- a/arch/mips/kernel/traps.c
+++ b/arch/mips/kernel/traps.c
@@ -1592,7 +1592,6 @@ void __cpuinit per_cpu_trap_init(void)
#endif /* CONFIG_MIPS_MT_SMTC */
cpu_data[cpu].asid_cache = ASID_FIRST_VERSION;
- TLBMISS_HANDLER_SETUP();
atomic_inc(&init_mm.mm_count);
current->active_mm = &init_mm;
@@ -1614,6 +1613,7 @@ void __cpuinit per_cpu_trap_init(void)
write_c0_wired(0);
}
#endif /* CONFIG_MIPS_MT_SMTC */
+ TLBMISS_HANDLER_SETUP();
}
/* Install CPU exception handler */
diff --git a/arch/mips/kernel/vmlinux.lds.S b/arch/mips/kernel/vmlinux.lds.S
index f25df73..570607b 100644
--- a/arch/mips/kernel/vmlinux.lds.S
+++ b/arch/mips/kernel/vmlinux.lds.S
@@ -98,6 +98,13 @@ SECTIONS
INIT_TEXT_SECTION(PAGE_SIZE)
INIT_DATA_SECTION(16)
+ . = ALIGN(4);
+ .mips.machines.init : AT(ADDR(.mips.machines.init) - LOAD_OFFSET) {
+ __mips_machines_start = .;
+ *(.mips.machines.init)
+ __mips_machines_end = .;
+ }
+
/* .exit.text is discarded at runtime, not link time, to deal with
* references from .rodata
*/
diff --git a/arch/mips/mm/tlbex.c b/arch/mips/mm/tlbex.c
index 93816f3..083d341 100644
--- a/arch/mips/mm/tlbex.c
+++ b/arch/mips/mm/tlbex.c
@@ -26,8 +26,10 @@
#include <linux/smp.h>
#include <linux/string.h>
#include <linux/init.h>
+#include <linux/cache.h>
-#include <asm/mmu_context.h>
+#include <asm/cacheflush.h>
+#include <asm/pgtable.h>
#include <asm/war.h>
#include <asm/uasm.h>
@@ -63,6 +65,52 @@ static inline int __maybe_unused r10000_llsc_war(void)
return R10000_LLSC_WAR;
}
+static int use_bbit_insns(void)
+{
+ switch (current_cpu_type()) {
+ case CPU_CAVIUM_OCTEON:
+ case CPU_CAVIUM_OCTEON_PLUS:
+ case CPU_CAVIUM_OCTEON2:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+static int use_lwx_insns(void)
+{
+ switch (current_cpu_type()) {
+ case CPU_CAVIUM_OCTEON2:
+ return 1;
+ default:
+ return 0;
+ }
+}
+#if defined(CONFIG_CAVIUM_OCTEON_CVMSEG_SIZE) && \
+ CONFIG_CAVIUM_OCTEON_CVMSEG_SIZE > 0
+static bool scratchpad_available(void)
+{
+ return true;
+}
+static int scratchpad_offset(int i)
+{
+ /*
+ * CVMSEG starts at address -32768 and extends for
+ * CAVIUM_OCTEON_CVMSEG_SIZE 128 byte cache lines.
+ */
+ i += 1; /* Kernel use starts at the top and works down. */
+ return CONFIG_CAVIUM_OCTEON_CVMSEG_SIZE * 128 - (8 * i) - 32768;
+}
+#else
+static bool scratchpad_available(void)
+{
+ return false;
+}
+static int scratchpad_offset(int i)
+{
+ BUG();
+}
+#endif
/*
* Found by experiment: At least some revisions of the 4kc throw under
* some circumstances a machine check exception, triggered by invalid
@@ -173,11 +221,41 @@ static struct uasm_reloc relocs[128] __cpuinitdata;
static int check_for_high_segbits __cpuinitdata;
#endif
+static int check_for_high_segbits __cpuinitdata;
+
+static unsigned int kscratch_used_mask __cpuinitdata;
+
+static int __cpuinit allocate_kscratch(void)
+{
+ int r;
+ unsigned int a = cpu_data[0].kscratch_mask & ~kscratch_used_mask;
+
+ r = ffs(a);
+
+ if (r == 0)
+ return -1;
+
+ r--; /* make it zero based */
+
+ kscratch_used_mask |= (1 << r);
+
+ return r;
+}
+
+static int scratch_reg __cpuinitdata;
+static int pgd_reg __cpuinitdata;
+enum vmalloc64_mode {not_refill, refill_scratch, refill_noscratch};
+
#ifndef CONFIG_MIPS_PGD_C0_CONTEXT
+
/*
* CONFIG_MIPS_PGD_C0_CONTEXT implies 64 bit and lack of pgd_current,
* we cannot do r3000 under these circumstances.
+ *
+ * Declare pgd_current here instead of including mmu_context.h to avoid type
+ * conflicts for tlbmiss_handler_setup_pgd
*/
+extern unsigned long pgd_current[];
/*
* The R3000 TLB handler is simple.
@@ -440,21 +518,43 @@ static __cpuinit __maybe_unused void build_convert_pte_to_entrylo(u32 **p,
static __cpuinit void build_restore_pagemask(u32 **p,
struct uasm_reloc **r,
unsigned int tmp,
- enum label_id lid)
+ enum label_id lid,
+ int restore_scratch)
{
- /* Reset default page size */
- if (PM_DEFAULT_MASK >> 16) {
- uasm_i_lui(p, tmp, PM_DEFAULT_MASK >> 16);
- uasm_i_ori(p, tmp, tmp, PM_DEFAULT_MASK & 0xffff);
- uasm_il_b(p, r, lid);
- uasm_i_mtc0(p, tmp, C0_PAGEMASK);
- } else if (PM_DEFAULT_MASK) {
- uasm_i_ori(p, tmp, 0, PM_DEFAULT_MASK);
- uasm_il_b(p, r, lid);
- uasm_i_mtc0(p, tmp, C0_PAGEMASK);
+ if (restore_scratch) {
+ /* Reset default page size */
+ if (PM_DEFAULT_MASK >> 16) {
+ uasm_i_lui(p, tmp, PM_DEFAULT_MASK >> 16);
+ uasm_i_ori(p, tmp, tmp, PM_DEFAULT_MASK & 0xffff);
+ uasm_i_mtc0(p, tmp, C0_PAGEMASK);
+ uasm_il_b(p, r, lid);
+ } else if (PM_DEFAULT_MASK) {
+ uasm_i_ori(p, tmp, 0, PM_DEFAULT_MASK);
+ uasm_i_mtc0(p, tmp, C0_PAGEMASK);
+ uasm_il_b(p, r, lid);
+ } else {
+ uasm_i_mtc0(p, 0, C0_PAGEMASK);
+ uasm_il_b(p, r, lid);
+ }
+ if (scratch_reg > 0)
+ UASM_i_MFC0(p, 1, 31, scratch_reg);
+ else
+ UASM_i_LW(p, 1, scratchpad_offset(0), 0);
} else {
- uasm_il_b(p, r, lid);
- uasm_i_mtc0(p, 0, C0_PAGEMASK);
+ /* Reset default page size */
+ if (PM_DEFAULT_MASK >> 16) {
+ uasm_i_lui(p, tmp, PM_DEFAULT_MASK >> 16);
+ uasm_i_ori(p, tmp, tmp, PM_DEFAULT_MASK & 0xffff);
+ uasm_il_b(p, r, lid);
+ uasm_i_mtc0(p, tmp, C0_PAGEMASK);
+ } else if (PM_DEFAULT_MASK) {
+ uasm_i_ori(p, tmp, 0, PM_DEFAULT_MASK);
+ uasm_il_b(p, r, lid);
+ uasm_i_mtc0(p, tmp, C0_PAGEMASK);
+ } else {
+ uasm_il_b(p, r, lid);
+ uasm_i_mtc0(p, 0, C0_PAGEMASK);
+ }
}
}
@@ -462,7 +562,8 @@ static __cpuinit void build_huge_tlb_write_entry(u32 **p,
struct uasm_label **l,
struct uasm_reloc **r,
unsigned int tmp,
- enum tlb_write_entry wmode)
+ enum tlb_write_entry wmode,
+ int restore_scratch)
{
/* Set huge page tlb entry size */
uasm_i_lui(p, tmp, PM_HUGE_MASK >> 16);
@@ -471,7 +572,7 @@ static __cpuinit void build_huge_tlb_write_entry(u32 **p,
build_tlb_write_entry(p, l, r, wmode);
- build_restore_pagemask(p, r, tmp, label_leave);
+ build_restore_pagemask(p, r, tmp, label_leave, restore_scratch);
}
/*
@@ -482,8 +583,12 @@ build_is_huge_pte(u32 **p, struct uasm_reloc **r, unsigned int tmp,
unsigned int pmd, int lid)
{
UASM_i_LW(p, tmp, 0, pmd);
- uasm_i_andi(p, tmp, tmp, _PAGE_HUGE);
- uasm_il_bnez(p, r, tmp, lid);
+ if (use_bbit_insns()) {
+ uasm_il_bbit1(p, r, tmp, ilog2(_PAGE_HUGE), lid);
+ } else {
+ uasm_i_andi(p, tmp, tmp, _PAGE_HUGE);
+ uasm_il_bnez(p, r, tmp, lid);
+ }
}
static __cpuinit void build_huge_update_entries(u32 **p,
@@ -532,7 +637,7 @@ static __cpuinit void build_huge_handler_tail(u32 **p,
UASM_i_SW(p, pte, 0, ptr);
#endif
build_huge_update_entries(p, pte, ptr);
- build_huge_tlb_write_entry(p, l, r, pte, tlb_indexed);
+ build_huge_tlb_write_entry(p, l, r, pte, tlb_indexed, 0);
}
#endif /* CONFIG_HUGETLB_PAGE */
@@ -573,13 +678,22 @@ build_get_pmde64(u32 **p, struct uasm_label **l, struct uasm_reloc **r,
/* No uasm_i_nop needed here, since the next insn doesn't touch TMP. */
#ifdef CONFIG_MIPS_PGD_C0_CONTEXT
- /*
- * &pgd << 11 stored in CONTEXT [23..63].
- */
- UASM_i_MFC0(p, ptr, C0_CONTEXT);
- uasm_i_dins(p, ptr, 0, 0, 23); /* Clear lower 23 bits of context. */
- uasm_i_ori(p, ptr, ptr, 0x540); /* 1 0 1 0 1 << 6 xkphys cached */
- uasm_i_drotr(p, ptr, ptr, 11);
+ if (pgd_reg != -1) {
+ /* pgd is in pgd_reg */
+ UASM_i_MFC0(p, ptr, 31, pgd_reg);
+ } else {
+ /*
+ * &pgd << 11 stored in CONTEXT [23..63].
+ */
+ UASM_i_MFC0(p, ptr, C0_CONTEXT);
+
+ /* Clear lower 23 bits of context. */
+ uasm_i_dins(p, ptr, 0, 0, 23);
+
+ /* 1 0 1 0 1 << 6 xkphys cached */
+ uasm_i_ori(p, ptr, ptr, 0x540);
+ uasm_i_drotr(p, ptr, ptr, 11);
+ }
#elif defined(CONFIG_SMP)
# ifdef CONFIG_MIPS_MT_SMTC
/*
@@ -620,7 +734,6 @@ build_get_pmde64(u32 **p, struct uasm_label **l, struct uasm_reloc **r,
#endif
}
-enum vmalloc64_mode {not_refill, refill};
/*
* BVADDR is the faulting address, PTR is scratch.
* PTR will hold the pgd for vmalloc.
@@ -638,7 +751,7 @@ build_get_pgd_vmalloc64(u32 **p, struct uasm_label **l, struct uasm_reloc **r,
uasm_l_vmalloc(l, *p);
- if (mode == refill && check_for_high_segbits) {
+ if (mode != not_refill && check_for_high_segbits) {
if (single_insn_swpd) {
uasm_il_bltz(p, r, bvaddr, label_vmalloc_done);
uasm_i_lui(p, ptr, uasm_rel_hi(swpd));
@@ -661,7 +774,7 @@ build_get_pgd_vmalloc64(u32 **p, struct uasm_label **l, struct uasm_reloc **r,
uasm_i_daddiu(p, ptr, ptr, uasm_rel_lo(swpd));
}
}
- if (mode == refill && check_for_high_segbits) {
+ if (mode != not_refill && check_for_high_segbits) {
uasm_l_large_segbits_fault(l, *p);
/*
* We get here if we are an xsseg address, or if we are
@@ -677,7 +790,15 @@ build_get_pgd_vmalloc64(u32 **p, struct uasm_label **l, struct uasm_reloc **r,
*/
UASM_i_LA(p, ptr, (unsigned long)tlb_do_page_fault_0);
uasm_i_jr(p, ptr);
- uasm_i_nop(p);
+
+ if (mode == refill_scratch) {
+ if (scratch_reg > 0)
+ UASM_i_MFC0(p, 1, 31, scratch_reg);
+ else
+ UASM_i_LW(p, 1, scratchpad_offset(0), 0);
+ } else {
+ uasm_i_nop(p);
+ }
}
}
@@ -834,6 +955,185 @@ static void __cpuinit build_update_entries(u32 **p, unsigned int tmp,
#endif
}
+struct mips_huge_tlb_info {
+ int huge_pte;
+ int restore_scratch;
+};
+
+static struct mips_huge_tlb_info __cpuinit
+build_fast_tlb_refill_handler (u32 **p, struct uasm_label **l,
+ struct uasm_reloc **r, unsigned int tmp,
+ unsigned int ptr, int c0_scratch)
+{
+ struct mips_huge_tlb_info rv;
+ unsigned int even, odd;
+ int vmalloc_branch_delay_filled = 0;
+ const int scratch = 1; /* Our extra working register */
+
+ rv.huge_pte = scratch;
+ rv.restore_scratch = 0;
+
+ if (check_for_high_segbits) {
+ UASM_i_MFC0(p, tmp, C0_BADVADDR);
+
+ if (pgd_reg != -1)
+ UASM_i_MFC0(p, ptr, 31, pgd_reg);
+ else
+ UASM_i_MFC0(p, ptr, C0_CONTEXT);
+
+ if (c0_scratch >= 0)
+ UASM_i_MTC0(p, scratch, 31, c0_scratch);
+ else
+ UASM_i_SW(p, scratch, scratchpad_offset(0), 0);
+
+ uasm_i_dsrl_safe(p, scratch, tmp,
+ PGDIR_SHIFT + PGD_ORDER + PAGE_SHIFT - 3);
+ uasm_il_bnez(p, r, scratch, label_vmalloc);
+
+ if (pgd_reg == -1) {
+ vmalloc_branch_delay_filled = 1;
+ /* Clear lower 23 bits of context. */
+ uasm_i_dins(p, ptr, 0, 0, 23);
+ }
+ } else {
+ if (pgd_reg != -1)
+ UASM_i_MFC0(p, ptr, 31, pgd_reg);
+ else
+ UASM_i_MFC0(p, ptr, C0_CONTEXT);
+
+ UASM_i_MFC0(p, tmp, C0_BADVADDR);
+
+ if (c0_scratch >= 0)
+ UASM_i_MTC0(p, scratch, 31, c0_scratch);
+ else
+ UASM_i_SW(p, scratch, scratchpad_offset(0), 0);
+
+ if (pgd_reg == -1)
+ /* Clear lower 23 bits of context. */
+ uasm_i_dins(p, ptr, 0, 0, 23);
+
+ uasm_il_bltz(p, r, tmp, label_vmalloc);
+ }
+
+ if (pgd_reg == -1) {
+ vmalloc_branch_delay_filled = 1;
+ /* 1 0 1 0 1 << 6 xkphys cached */
+ uasm_i_ori(p, ptr, ptr, 0x540);
+ uasm_i_drotr(p, ptr, ptr, 11);
+ }
+
+#ifdef __PAGETABLE_PMD_FOLDED
+#define LOC_PTEP scratch
+#else
+#define LOC_PTEP ptr
+#endif
+
+ if (!vmalloc_branch_delay_filled)
+ /* get pgd offset in bytes */
+ uasm_i_dsrl_safe(p, scratch, tmp, PGDIR_SHIFT - 3);
+
+ uasm_l_vmalloc_done(l, *p);
+
+ /*
+ * tmp ptr
+ * fall-through case = badvaddr *pgd_current
+ * vmalloc case = badvaddr swapper_pg_dir
+ */
+
+ if (vmalloc_branch_delay_filled)
+ /* get pgd offset in bytes */
+ uasm_i_dsrl_safe(p, scratch, tmp, PGDIR_SHIFT - 3);
+
+#ifdef __PAGETABLE_PMD_FOLDED
+ GET_CONTEXT(p, tmp); /* get context reg */
+#endif
+ uasm_i_andi(p, scratch, scratch, (PTRS_PER_PGD - 1) << 3);
+
+ if (use_lwx_insns()) {
+ UASM_i_LWX(p, LOC_PTEP, scratch, ptr);
+ } else {
+ uasm_i_daddu(p, ptr, ptr, scratch); /* add in pgd offset */
+ uasm_i_ld(p, LOC_PTEP, 0, ptr); /* get pmd pointer */
+ }
+
+#ifndef __PAGETABLE_PMD_FOLDED
+ /* get pmd offset in bytes */
+ uasm_i_dsrl_safe(p, scratch, tmp, PMD_SHIFT - 3);
+ uasm_i_andi(p, scratch, scratch, (PTRS_PER_PMD - 1) << 3);
+ GET_CONTEXT(p, tmp); /* get context reg */
+
+ if (use_lwx_insns()) {
+ UASM_i_LWX(p, scratch, scratch, ptr);
+ } else {
+ uasm_i_daddu(p, ptr, ptr, scratch); /* add in pmd offset */
+ UASM_i_LW(p, scratch, 0, ptr);
+ }
+#endif
+ /* Adjust the context during the load latency. */
+ build_adjust_context(p, tmp);
+
+#ifdef CONFIG_HUGETLB_PAGE
+ uasm_il_bbit1(p, r, scratch, ilog2(_PAGE_HUGE), label_tlb_huge_update);
+ /*
+ * The in the LWX case we don't want to do the load in the
+ * delay slot. It cannot issue in the same cycle and may be
+ * speculative and unneeded.
+ */
+ if (use_lwx_insns())
+ uasm_i_nop(p);
+#endif /* CONFIG_HUGETLB_PAGE */
+
+
+ /* build_update_entries */
+ if (use_lwx_insns()) {
+ even = ptr;
+ odd = tmp;
+ UASM_i_LWX(p, even, scratch, tmp);
+ UASM_i_ADDIU(p, tmp, tmp, sizeof(pte_t));
+ UASM_i_LWX(p, odd, scratch, tmp);
+ } else {
+ UASM_i_ADDU(p, ptr, scratch, tmp); /* add in offset */
+ even = tmp;
+ odd = ptr;
+ UASM_i_LW(p, even, 0, ptr); /* get even pte */
+ UASM_i_LW(p, odd, sizeof(pte_t), ptr); /* get odd pte */
+ }
+ if (kernel_uses_smartmips_rixi) {
+ uasm_i_dsrl_safe(p, even, even, ilog2(_PAGE_NO_EXEC));
+ uasm_i_dsrl_safe(p, odd, odd, ilog2(_PAGE_NO_EXEC));
+ uasm_i_drotr(p, even, even,
+ ilog2(_PAGE_GLOBAL) - ilog2(_PAGE_NO_EXEC));
+ UASM_i_MTC0(p, even, C0_ENTRYLO0); /* load it */
+ uasm_i_drotr(p, odd, odd,
+ ilog2(_PAGE_GLOBAL) - ilog2(_PAGE_NO_EXEC));
+ } else {
+ uasm_i_dsrl_safe(p, even, even, ilog2(_PAGE_GLOBAL));
+ UASM_i_MTC0(p, even, C0_ENTRYLO0); /* load it */
+ uasm_i_dsrl_safe(p, odd, odd, ilog2(_PAGE_GLOBAL));
+ }
+ UASM_i_MTC0(p, odd, C0_ENTRYLO1); /* load it */
+
+ if (c0_scratch >= 0) {
+ UASM_i_MFC0(p, scratch, 31, c0_scratch);
+ build_tlb_write_entry(p, l, r, tlb_random);
+ uasm_l_leave(l, *p);
+ rv.restore_scratch = 1;
+ } else if (PAGE_SHIFT == 14 || PAGE_SHIFT == 13) {
+ build_tlb_write_entry(p, l, r, tlb_random);
+ uasm_l_leave(l, *p);
+ UASM_i_LW(p, scratch, scratchpad_offset(0), 0);
+ } else {
+ UASM_i_LW(p, scratch, scratchpad_offset(0), 0);
+ build_tlb_write_entry(p, l, r, tlb_random);
+ uasm_l_leave(l, *p);
+ rv.restore_scratch = 1;
+ }
+
+ uasm_i_eret(p); /* return from trap */
+
+ return rv;
+}
+
/*
* For a 64-bit kernel, we are using the 64-bit XTLB refill exception
* because EXL == 0. If we wrap, we can also use the 32 instruction
@@ -849,54 +1149,67 @@ static void __cpuinit build_r4000_tlb_refill_handler(void)
struct uasm_reloc *r = relocs;
u32 *f;
unsigned int final_len;
+ struct mips_huge_tlb_info htlb_info;
+ enum vmalloc64_mode vmalloc_mode;
memset(tlb_handler, 0, sizeof(tlb_handler));
memset(labels, 0, sizeof(labels));
memset(relocs, 0, sizeof(relocs));
memset(final_handler, 0, sizeof(final_handler));
- /*
- * create the plain linear handler
- */
- if (bcm1250_m3_war()) {
- unsigned int segbits = 44;
+ if (scratch_reg == 0)
+ scratch_reg = allocate_kscratch();
- uasm_i_dmfc0(&p, K0, C0_BADVADDR);
- uasm_i_dmfc0(&p, K1, C0_ENTRYHI);
- uasm_i_xor(&p, K0, K0, K1);
- uasm_i_dsrl_safe(&p, K1, K0, 62);
- uasm_i_dsrl_safe(&p, K0, K0, 12 + 1);
- uasm_i_dsll_safe(&p, K0, K0, 64 + 12 + 1 - segbits);
- uasm_i_or(&p, K0, K0, K1);
- uasm_il_bnez(&p, &r, K0, label_leave);
- /* No need for uasm_i_nop */
- }
+ if ((scratch_reg > 0 || scratchpad_available()) && use_bbit_insns()) {
+ htlb_info = build_fast_tlb_refill_handler(&p, &l, &r, K0, K1,
+ scratch_reg);
+ vmalloc_mode = refill_scratch;
+ } else {
+ htlb_info.huge_pte = K0;
+ htlb_info.restore_scratch = 0;
+ vmalloc_mode = refill_noscratch;
+ /*
+ * create the plain linear handler
+ */
+ if (bcm1250_m3_war()) {
+ unsigned int segbits = 44;
+
+ uasm_i_dmfc0(&p, K0, C0_BADVADDR);
+ uasm_i_dmfc0(&p, K1, C0_ENTRYHI);
+ uasm_i_xor(&p, K0, K0, K1);
+ uasm_i_dsrl_safe(&p, K1, K0, 62);
+ uasm_i_dsrl_safe(&p, K0, K0, 12 + 1);
+ uasm_i_dsll_safe(&p, K0, K0, 64 + 12 + 1 - segbits);
+ uasm_i_or(&p, K0, K0, K1);
+ uasm_il_bnez(&p, &r, K0, label_leave);
+ /* No need for uasm_i_nop */
+ }
#ifdef CONFIG_64BIT
- build_get_pmde64(&p, &l, &r, K0, K1); /* get pmd in K1 */
+ build_get_pmde64(&p, &l, &r, K0, K1); /* get pmd in K1 */
#else
- build_get_pgde32(&p, K0, K1); /* get pgd in K1 */
+ build_get_pgde32(&p, K0, K1); /* get pgd in K1 */
#endif
#ifdef CONFIG_HUGETLB_PAGE
- build_is_huge_pte(&p, &r, K0, K1, label_tlb_huge_update);
+ build_is_huge_pte(&p, &r, K0, K1, label_tlb_huge_update);
#endif
- build_get_ptep(&p, K0, K1);
- build_update_entries(&p, K0, K1);
- build_tlb_write_entry(&p, &l, &r, tlb_random);
- uasm_l_leave(&l, p);
- uasm_i_eret(&p); /* return from trap */
-
+ build_get_ptep(&p, K0, K1);
+ build_update_entries(&p, K0, K1);
+ build_tlb_write_entry(&p, &l, &r, tlb_random);
+ uasm_l_leave(&l, p);
+ uasm_i_eret(&p); /* return from trap */
+ }
#ifdef CONFIG_HUGETLB_PAGE
uasm_l_tlb_huge_update(&l, p);
- UASM_i_LW(&p, K0, 0, K1);
- build_huge_update_entries(&p, K0, K1);
- build_huge_tlb_write_entry(&p, &l, &r, K0, tlb_random);
+ build_huge_update_entries(&p, htlb_info.huge_pte, K1);
+ build_huge_tlb_write_entry(&p, &l, &r, K0, tlb_random,
+ htlb_info.restore_scratch);
#endif
#ifdef CONFIG_64BIT
- build_get_pgd_vmalloc64(&p, &l, &r, K0, K1, refill);
+ build_get_pgd_vmalloc64(&p, &l, &r, K0, K1, vmalloc_mode);
#endif
/*
@@ -1014,6 +1327,55 @@ static void __cpuinit build_r4000_tlb_refill_handler(void)
u32 handle_tlbl[FASTPATH_SIZE] __cacheline_aligned;
u32 handle_tlbs[FASTPATH_SIZE] __cacheline_aligned;
u32 handle_tlbm[FASTPATH_SIZE] __cacheline_aligned;
+#ifdef CONFIG_MIPS_PGD_C0_CONTEXT
+u32 tlbmiss_handler_setup_pgd[16] __cacheline_aligned;
+
+static void __cpuinit build_r4000_setup_pgd(void)
+{
+ const int a0 = 4;
+ const int a1 = 5;
+ u32 *p = tlbmiss_handler_setup_pgd;
+ struct uasm_label *l = labels;
+ struct uasm_reloc *r = relocs;
+
+ memset(tlbmiss_handler_setup_pgd, 0, sizeof(tlbmiss_handler_setup_pgd));
+ memset(labels, 0, sizeof(labels));
+ memset(relocs, 0, sizeof(relocs));
+
+ pgd_reg = allocate_kscratch();
+
+ if (pgd_reg == -1) {
+ /* PGD << 11 in c0_Context */
+ /*
+ * If it is a ckseg0 address, convert to a physical
+ * address. Shifting right by 29 and adding 4 will
+ * result in zero for these addresses.
+ *
+ */
+ UASM_i_SRA(&p, a1, a0, 29);
+ UASM_i_ADDIU(&p, a1, a1, 4);
+ uasm_il_bnez(&p, &r, a1, label_tlbl_goaround1);
+ uasm_i_nop(&p);
+ uasm_i_dinsm(&p, a0, 0, 29, 64 - 29);
+ uasm_l_tlbl_goaround1(&l, p);
+ UASM_i_SLL(&p, a0, a0, 11);
+ uasm_i_jr(&p, 31);
+ UASM_i_MTC0(&p, a0, C0_CONTEXT);
+ } else {
+ /* PGD in c0_KScratch */
+ uasm_i_jr(&p, 31);
+ UASM_i_MTC0(&p, a0, 31, pgd_reg);
+ }
+ if (p - tlbmiss_handler_setup_pgd > ARRAY_SIZE(tlbmiss_handler_setup_pgd))
+ panic("tlbmiss_handler_setup_pgd space exceeded");
+ uasm_resolve_relocs(relocs, labels);
+ pr_debug("Wrote tlbmiss_handler_setup_pgd (%u instructions).\n",
+ (unsigned int)(p - tlbmiss_handler_setup_pgd));
+
+ dump_handler(tlbmiss_handler_setup_pgd,
+ ARRAY_SIZE(tlbmiss_handler_setup_pgd));
+}
+#endif
static void __cpuinit
iPTE_LW(u32 **p, unsigned int pte, unsigned int ptr)
@@ -1100,14 +1462,20 @@ build_pte_present(u32 **p, struct uasm_reloc **r,
unsigned int pte, unsigned int ptr, enum label_id lid)
{
if (kernel_uses_smartmips_rixi) {
- uasm_i_andi(p, pte, pte, _PAGE_PRESENT);
- uasm_il_beqz(p, r, pte, lid);
+ if (use_bbit_insns()) {
+ uasm_il_bbit0(p, r, pte, ilog2(_PAGE_PRESENT), lid);
+ uasm_i_nop(p);
+ } else {
+ uasm_i_andi(p, pte, pte, _PAGE_PRESENT);
+ uasm_il_beqz(p, r, pte, lid);
+ iPTE_LW(p, pte, ptr);
+ }
} else {
uasm_i_andi(p, pte, pte, _PAGE_PRESENT | _PAGE_READ);
uasm_i_xori(p, pte, pte, _PAGE_PRESENT | _PAGE_READ);
uasm_il_bnez(p, r, pte, lid);
+ iPTE_LW(p, pte, ptr);
}
- iPTE_LW(p, pte, ptr);
}
/* Make PTE valid, store result in PTR. */
@@ -1128,10 +1496,17 @@ static void __cpuinit
build_pte_writable(u32 **p, struct uasm_reloc **r,
unsigned int pte, unsigned int ptr, enum label_id lid)
{
- uasm_i_andi(p, pte, pte, _PAGE_PRESENT | _PAGE_WRITE);
- uasm_i_xori(p, pte, pte, _PAGE_PRESENT | _PAGE_WRITE);
- uasm_il_bnez(p, r, pte, lid);
- iPTE_LW(p, pte, ptr);
+ if (use_bbit_insns()) {
+ uasm_il_bbit0(p, r, pte, ilog2(_PAGE_PRESENT), lid);
+ uasm_i_nop(p);
+ uasm_il_bbit0(p, r, pte, ilog2(_PAGE_WRITE), lid);
+ uasm_i_nop(p);
+ } else {
+ uasm_i_andi(p, pte, pte, _PAGE_PRESENT | _PAGE_WRITE);
+ uasm_i_xori(p, pte, pte, _PAGE_PRESENT | _PAGE_WRITE);
+ uasm_il_bnez(p, r, pte, lid);
+ iPTE_LW(p, pte, ptr);
+ }
}
/* Make PTE writable, update software status bits as well, then store
@@ -1155,12 +1530,19 @@ static void __cpuinit
build_pte_modifiable(u32 **p, struct uasm_reloc **r,
unsigned int pte, unsigned int ptr, enum label_id lid)
{
- uasm_i_andi(p, pte, pte, _PAGE_WRITE);
- uasm_il_beqz(p, r, pte, lid);
- iPTE_LW(p, pte, ptr);
+ if (use_bbit_insns()) {
+ uasm_il_bbit0(p, r, pte, ilog2(_PAGE_WRITE), lid);
+ uasm_i_nop(p);
+ } else {
+ uasm_i_andi(p, pte, pte, _PAGE_WRITE);
+ uasm_il_beqz(p, r, pte, lid);
+ iPTE_LW(p, pte, ptr);
+ }
}
#ifndef CONFIG_MIPS_PGD_C0_CONTEXT
+
+
/*
* R3000 style TLB load/store/modify handlers.
*/
@@ -1402,14 +1784,23 @@ static void __cpuinit build_r4000_tlb_load_handler(void)
* If the page is not _PAGE_VALID, RI or XI could not
* have triggered it. Skip the expensive test..
*/
- uasm_i_andi(&p, K0, K0, _PAGE_VALID);
- uasm_il_beqz(&p, &r, K0, label_tlbl_goaround1);
+ if (use_bbit_insns()) {
+ uasm_il_bbit0(&p, &r, K0, ilog2(_PAGE_VALID),
+ label_tlbl_goaround1);
+ } else {
+ uasm_i_andi(&p, K0, K0, _PAGE_VALID);
+ uasm_il_beqz(&p, &r, K0, label_tlbl_goaround1);
+ }
uasm_i_nop(&p);
uasm_i_tlbr(&p);
/* Examine entrylo 0 or 1 based on ptr. */
- uasm_i_andi(&p, K0, K1, sizeof(pte_t));
- uasm_i_beqz(&p, K0, 8);
+ if (use_bbit_insns()) {
+ uasm_i_bbit0(&p, K1, ilog2(sizeof(pte_t)), 8);
+ } else {
+ uasm_i_andi(&p, K0, K1, sizeof(pte_t));
+ uasm_i_beqz(&p, K0, 8);
+ }
UASM_i_MFC0(&p, K0, C0_ENTRYLO0); /* load it in the delay slot*/
UASM_i_MFC0(&p, K0, C0_ENTRYLO1); /* load it if ptr is odd */
@@ -1417,12 +1808,18 @@ static void __cpuinit build_r4000_tlb_load_handler(void)
* If the entryLo (now in K0) is valid (bit 1), RI or
* XI must have triggered it.
*/
- uasm_i_andi(&p, K0, K0, 2);
- uasm_il_bnez(&p, &r, K0, label_nopage_tlbl);
-
- uasm_l_tlbl_goaround1(&l, p);
- /* Reload the PTE value */
- iPTE_LW(&p, K0, K1);
+ if (use_bbit_insns()) {
+ uasm_il_bbit1(&p, &r, K0, 1, label_nopage_tlbl);
+ /* Reload the PTE value */
+ iPTE_LW(&p, K0, K1);
+ uasm_l_tlbl_goaround1(&l, p);
+ } else {
+ uasm_i_andi(&p, K0, K0, 2);
+ uasm_il_bnez(&p, &r, K0, label_nopage_tlbl);
+ uasm_l_tlbl_goaround1(&l, p);
+ /* Reload the PTE value */
+ iPTE_LW(&p, K0, K1);
+ }
}
build_make_valid(&p, &r, K0, K1);
build_r4000_tlbchange_handler_tail(&p, &l, &r, K0, K1);
@@ -1442,23 +1839,35 @@ static void __cpuinit build_r4000_tlb_load_handler(void)
* If the page is not _PAGE_VALID, RI or XI could not
* have triggered it. Skip the expensive test..
*/
- uasm_i_andi(&p, K0, K0, _PAGE_VALID);
- uasm_il_beqz(&p, &r, K0, label_tlbl_goaround2);
+ if (use_bbit_insns()) {
+ uasm_il_bbit0(&p, &r, K0, ilog2(_PAGE_VALID),
+ label_tlbl_goaround2);
+ } else {
+ uasm_i_andi(&p, K0, K0, _PAGE_VALID);
+ uasm_il_beqz(&p, &r, K0, label_tlbl_goaround2);
+ }
uasm_i_nop(&p);
uasm_i_tlbr(&p);
/* Examine entrylo 0 or 1 based on ptr. */
- uasm_i_andi(&p, K0, K1, sizeof(pte_t));
- uasm_i_beqz(&p, K0, 8);
-
+ if (use_bbit_insns()) {
+ uasm_i_bbit0(&p, K1, ilog2(sizeof(pte_t)), 8);
+ } else {
+ uasm_i_andi(&p, K0, K1, sizeof(pte_t));
+ uasm_i_beqz(&p, K0, 8);
+ }
UASM_i_MFC0(&p, K0, C0_ENTRYLO0); /* load it in the delay slot*/
UASM_i_MFC0(&p, K0, C0_ENTRYLO1); /* load it if ptr is odd */
/*
* If the entryLo (now in K0) is valid (bit 1), RI or
* XI must have triggered it.
*/
- uasm_i_andi(&p, K0, K0, 2);
- uasm_il_beqz(&p, &r, K0, label_tlbl_goaround2);
+ if (use_bbit_insns()) {
+ uasm_il_bbit0(&p, &r, K0, 1, label_tlbl_goaround2);
+ } else {
+ uasm_i_andi(&p, K0, K0, 2);
+ uasm_il_beqz(&p, &r, K0, label_tlbl_goaround2);
+ }
/* Reload the PTE value */
iPTE_LW(&p, K0, K1);
@@ -1466,7 +1875,7 @@ static void __cpuinit build_r4000_tlb_load_handler(void)
* We clobbered C0_PAGEMASK, restore it. On the other branch
* it is restored in build_huge_tlb_write_entry.
*/
- build_restore_pagemask(&p, &r, K0, label_nopage_tlbl);
+ build_restore_pagemask(&p, &r, K0, label_nopage_tlbl, 0);
uasm_l_tlbl_goaround2(&l, p);
}
@@ -1623,13 +2032,16 @@ void __cpuinit build_tlb_refill_handler(void)
break;
default:
- build_r4000_tlb_refill_handler();
if (!run_once) {
+#ifdef CONFIG_MIPS_PGD_C0_CONTEXT
+ build_r4000_setup_pgd();
+#endif
build_r4000_tlb_load_handler();
build_r4000_tlb_store_handler();
build_r4000_tlb_modify_handler();
run_once++;
}
+ build_r4000_tlb_refill_handler();
}
}
@@ -1641,4 +2053,8 @@ void __cpuinit flush_tlb_handlers(void)
(unsigned long)handle_tlbs + sizeof(handle_tlbs));
local_flush_icache_range((unsigned long)handle_tlbm,
(unsigned long)handle_tlbm + sizeof(handle_tlbm));
+#ifdef CONFIG_MIPS_PGD_C0_CONTEXT
+ local_flush_icache_range((unsigned long)tlbmiss_handler_setup_pgd,
+ (unsigned long)tlbmiss_handler_setup_pgd + sizeof(handle_tlbm));
+#endif
}
diff --git a/arch/mips/mm/uasm.c b/arch/mips/mm/uasm.c
index 23afdeb..5fa1851 100644
--- a/arch/mips/mm/uasm.c
+++ b/arch/mips/mm/uasm.c
@@ -68,7 +68,8 @@ enum opcode {
insn_pref, insn_rfe, insn_sc, insn_scd, insn_sd, insn_sll,
insn_sra, insn_srl, insn_rotr, insn_subu, insn_sw, insn_tlbp,
insn_tlbr, insn_tlbwi, insn_tlbwr, insn_xor, insn_xori,
- insn_dins, insn_syscall, insn_bbit0, insn_bbit1
+ insn_dins, insn_dinsm, insn_syscall, insn_bbit0, insn_bbit1,
+ insn_lwx, insn_ldx
};
struct insn {
@@ -142,9 +143,12 @@ static struct insn insn_table[] __uasminitdata = {
{ insn_xor, M(spec_op, 0, 0, 0, 0, xor_op), RS | RT | RD },
{ insn_xori, M(xori_op, 0, 0, 0, 0, 0), RS | RT | UIMM },
{ insn_dins, M(spec3_op, 0, 0, 0, 0, dins_op), RS | RT | RD | RE },
+ { insn_dinsm, M(spec3_op, 0, 0, 0, 0, dinsm_op), RS | RT | RD | RE },
{ insn_syscall, M(spec_op, 0, 0, 0, 0, syscall_op), SCIMM},
{ insn_bbit0, M(lwc2_op, 0, 0, 0, 0, 0), RS | RT | BIMM },
{ insn_bbit1, M(swc2_op, 0, 0, 0, 0, 0), RS | RT | BIMM },
+ { insn_lwx, M(spec3_op, 0, 0, 0, lwx_op, lx_op), RS | RT | RD },
+ { insn_ldx, M(spec3_op, 0, 0, 0, ldx_op, lx_op), RS | RT | RD },
{ insn_invalid, 0, 0 }
};
@@ -152,91 +156,83 @@ static struct insn insn_table[] __uasminitdata = {
static inline __uasminit u32 build_rs(u32 arg)
{
- if (arg & ~RS_MASK)
- printk(KERN_WARNING "Micro-assembler field overflow\n");
+ WARN(arg & ~RS_MASK, KERN_WARNING "Micro-assembler field overflow\n");
return (arg & RS_MASK) << RS_SH;
}
static inline __uasminit u32 build_rt(u32 arg)
{
- if (arg & ~RT_MASK)
- printk(KERN_WARNING "Micro-assembler field overflow\n");
+ WARN(arg & ~RT_MASK, KERN_WARNING "Micro-assembler field overflow\n");
return (arg & RT_MASK) << RT_SH;
}
static inline __uasminit u32 build_rd(u32 arg)
{
- if (arg & ~RD_MASK)
- printk(KERN_WARNING "Micro-assembler field overflow\n");
+ WARN(arg & ~RD_MASK, KERN_WARNING "Micro-assembler field overflow\n");
return (arg & RD_MASK) << RD_SH;
}
static inline __uasminit u32 build_re(u32 arg)
{
- if (arg & ~RE_MASK)
- printk(KERN_WARNING "Micro-assembler field overflow\n");
+ WARN(arg & ~RE_MASK, KERN_WARNING "Micro-assembler field overflow\n");
return (arg & RE_MASK) << RE_SH;
}
static inline __uasminit u32 build_simm(s32 arg)
{
- if (arg > 0x7fff || arg < -0x8000)
- printk(KERN_WARNING "Micro-assembler field overflow\n");
+ WARN(arg > 0x7fff || arg < -0x8000,
+ KERN_WARNING "Micro-assembler field overflow\n");
return arg & 0xffff;
}
static inline __uasminit u32 build_uimm(u32 arg)
{
- if (arg & ~IMM_MASK)
- printk(KERN_WARNING "Micro-assembler field overflow\n");
+ WARN(arg & ~IMM_MASK, KERN_WARNING "Micro-assembler field overflow\n");
return arg & IMM_MASK;
}
static inline __uasminit u32 build_bimm(s32 arg)
{
- if (arg > 0x1ffff || arg < -0x20000)
- printk(KERN_WARNING "Micro-assembler field overflow\n");
+ WARN(arg > 0x1ffff || arg < -0x20000,
+ KERN_WARNING "Micro-assembler field overflow\n");
- if (arg & 0x3)
- printk(KERN_WARNING "Invalid micro-assembler branch target\n");
+ WARN(arg & 0x3, KERN_WARNING "Invalid micro-assembler branch target\n");
return ((arg < 0) ? (1 << 15) : 0) | ((arg >> 2) & 0x7fff);
}
static inline __uasminit u32 build_jimm(u32 arg)
{
- if (arg & ~((JIMM_MASK) << 2))
- printk(KERN_WARNING "Micro-assembler field overflow\n");
+ WARN(arg & ~(JIMM_MASK << 2),
+ KERN_WARNING "Micro-assembler field overflow\n");
return (arg >> 2) & JIMM_MASK;
}
static inline __uasminit u32 build_scimm(u32 arg)
{
- if (arg & ~SCIMM_MASK)
- printk(KERN_WARNING "Micro-assembler field overflow\n");
+ WARN(arg & ~SCIMM_MASK,
+ KERN_WARNING "Micro-assembler field overflow\n");
return (arg & SCIMM_MASK) << SCIMM_SH;
}
static inline __uasminit u32 build_func(u32 arg)
{
- if (arg & ~FUNC_MASK)
- printk(KERN_WARNING "Micro-assembler field overflow\n");
+ WARN(arg & ~FUNC_MASK, KERN_WARNING "Micro-assembler field overflow\n");
return arg & FUNC_MASK;
}
static inline __uasminit u32 build_set(u32 arg)
{
- if (arg & ~SET_MASK)
- printk(KERN_WARNING "Micro-assembler field overflow\n");
+ WARN(arg & ~SET_MASK, KERN_WARNING "Micro-assembler field overflow\n");
return arg & SET_MASK;
}
@@ -340,6 +336,13 @@ Ip_u2u1msbu3(op) \
} \
UASM_EXPORT_SYMBOL(uasm_i##op);
+#define I_u2u1msb32u3(op) \
+Ip_u2u1msbu3(op) \
+{ \
+ build_insn(buf, insn##op, b, a, c+d-33, c); \
+} \
+UASM_EXPORT_SYMBOL(uasm_i##op);
+
#define I_u1u2(op) \
Ip_u1u2(op) \
{ \
@@ -422,9 +425,12 @@ I_0(_tlbwr)
I_u3u1u2(_xor)
I_u2u1u3(_xori)
I_u2u1msbu3(_dins);
+I_u2u1msb32u3(_dinsm);
I_u1(_syscall);
I_u1u2s3(_bbit0);
I_u1u2s3(_bbit1);
+I_u3u1u2(_lwx)
+I_u3u1u2(_ldx)
#ifdef CONFIG_CPU_CAVIUM_OCTEON
#include <asm/octeon/octeon.h>
diff --git a/arch/mips/sibyte/common/sb_tbprof.c b/arch/mips/sibyte/common/sb_tbprof.c
index 87ccdb4..48853ab 100644
--- a/arch/mips/sibyte/common/sb_tbprof.c
+++ b/arch/mips/sibyte/common/sb_tbprof.c
@@ -410,14 +410,13 @@ static int sbprof_tb_open(struct inode *inode, struct file *filp)
return -EBUSY;
memset(&sbp, 0, sizeof(struct sbprof_tb));
- sbp.sbprof_tbbuf = vmalloc(MAX_TBSAMPLE_BYTES);
+ sbp.sbprof_tbbuf = vzalloc(MAX_TBSAMPLE_BYTES);
if (!sbp.sbprof_tbbuf) {
sbp.open = SB_CLOSED;
wmb();
return -ENOMEM;
}
- memset(sbp.sbprof_tbbuf, 0, MAX_TBSAMPLE_BYTES);
init_waitqueue_head(&sbp.tb_sync);
init_waitqueue_head(&sbp.tb_read);
mutex_init(&sbp.lock);
diff --git a/arch/mips/txx9/generic/pci.c b/arch/mips/txx9/generic/pci.c
index 96e69a0..85a87de 100644
--- a/arch/mips/txx9/generic/pci.c
+++ b/arch/mips/txx9/generic/pci.c
@@ -213,11 +213,8 @@ txx9_alloc_pci_controller(struct pci_controller *pcic,
pcic->mem_offset = 0; /* busaddr == physaddr */
- printk(KERN_INFO "PCI: IO 0x%08llx-0x%08llx MEM 0x%08llx-0x%08llx\n",
- (unsigned long long)pcic->mem_resource[1].start,
- (unsigned long long)pcic->mem_resource[1].end,
- (unsigned long long)pcic->mem_resource[0].start,
- (unsigned long long)pcic->mem_resource[0].end);
+ printk(KERN_INFO "PCI: IO %pR MEM %pR\n",
+ &pcic->mem_resource[1], &pcic->mem_resource[0]);
/* register_pci_controller() will request MEM resource */
release_resource(&pcic->mem_resource[0]);
diff --git a/arch/mn10300/Kconfig b/arch/mn10300/Kconfig
index 8ed41cf..243bfa2 100644
--- a/arch/mn10300/Kconfig
+++ b/arch/mn10300/Kconfig
@@ -1,6 +1,7 @@
config MN10300
def_bool y
select HAVE_OPROFILE
+ select GENERIC_HARDIRQS
config AM33_2
def_bool n
@@ -34,9 +35,6 @@ config RWSEM_GENERIC_SPINLOCK
config RWSEM_XCHGADD_ALGORITHM
bool
-config GENERIC_HARDIRQS_NO__DO_IRQ
- def_bool y
-
config GENERIC_CALIBRATE_DELAY
def_bool y
@@ -79,10 +77,6 @@ config QUICKLIST
config ARCH_HAS_ILOG2_U32
def_bool y
-# Use the generic interrupt handling code in kernel/irq/
-config GENERIC_HARDIRQS
- def_bool y
-
config HOTPLUG_CPU
def_bool n
diff --git a/arch/mn10300/configs/asb2303_defconfig b/arch/mn10300/configs/asb2303_defconfig
index 3f749b6..1fd41ec 100644
--- a/arch/mn10300/configs/asb2303_defconfig
+++ b/arch/mn10300/configs/asb2303_defconfig
@@ -4,7 +4,7 @@ CONFIG_BSD_PROCESS_ACCT=y
CONFIG_TINY_RCU=y
CONFIG_LOG_BUF_SHIFT=14
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_KALLSYMS is not set
# CONFIG_HOTPLUG is not set
# CONFIG_VM_EVENT_COUNTERS is not set
diff --git a/arch/mn10300/configs/asb2364_defconfig b/arch/mn10300/configs/asb2364_defconfig
index 83ce2f2..31d7626 100644
--- a/arch/mn10300/configs/asb2364_defconfig
+++ b/arch/mn10300/configs/asb2364_defconfig
@@ -15,7 +15,7 @@ CONFIG_CGROUP_CPUACCT=y
CONFIG_RESOURCE_COUNTERS=y
CONFIG_RELAY=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_KALLSYMS is not set
# CONFIG_VM_EVENT_COUNTERS is not set
CONFIG_SLAB=y
diff --git a/arch/parisc/Kconfig b/arch/parisc/Kconfig
index 0888675..fed2946 100644
--- a/arch/parisc/Kconfig
+++ b/arch/parisc/Kconfig
@@ -12,7 +12,10 @@ config PARISC
select HAVE_IRQ_WORK
select HAVE_PERF_EVENTS
select GENERIC_ATOMIC64 if !64BIT
- select GENERIC_HARDIRQS_NO__DO_IRQ
+ select HAVE_GENERIC_HARDIRQS
+ select GENERIC_IRQ_PROBE
+ select IRQ_PER_CPU
+
help
The PA-RISC microprocessor is designed by Hewlett-Packard and used
in many of their workstations & servers (HP9000 700 and 800 series,
@@ -66,22 +69,9 @@ config TIME_LOW_RES
depends on SMP
default y
-config GENERIC_HARDIRQS
- def_bool y
-
-config GENERIC_IRQ_PROBE
- def_bool y
-
config HAVE_LATENCYTOP_SUPPORT
def_bool y
-config IRQ_PER_CPU
- bool
- default y
-
-config GENERIC_HARDIRQS_NO__DO_IRQ
- def_bool y
-
# unless you want to implement ACPI on PA-RISC ... ;-)
config PM
bool
diff --git a/arch/parisc/configs/a500_defconfig b/arch/parisc/configs/a500_defconfig
index f9305f3..b647b18 100644
--- a/arch/parisc/configs/a500_defconfig
+++ b/arch/parisc/configs/a500_defconfig
@@ -8,7 +8,7 @@ CONFIG_LOG_BUF_SHIFT=16
CONFIG_SYSFS_DEPRECATED_V2=y
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
CONFIG_KALLSYMS_ALL=y
CONFIG_SLAB=y
CONFIG_PROFILING=y
diff --git a/arch/parisc/configs/c3000_defconfig b/arch/parisc/configs/c3000_defconfig
index 628d3e0..311ca36 100644
--- a/arch/parisc/configs/c3000_defconfig
+++ b/arch/parisc/configs/c3000_defconfig
@@ -6,7 +6,7 @@ CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=16
CONFIG_SYSFS_DEPRECATED_V2=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
CONFIG_KALLSYMS_ALL=y
CONFIG_SLAB=y
CONFIG_PROFILING=y
diff --git a/arch/parisc/include/asm/pgtable.h b/arch/parisc/include/asm/pgtable.h
index 865f37a..6f1f65d 100644
--- a/arch/parisc/include/asm/pgtable.h
+++ b/arch/parisc/include/asm/pgtable.h
@@ -10,11 +10,13 @@
* we simulate an x86-style page table for the linux mm code
*/
-#include <linux/mm.h> /* for vm_area_struct */
#include <linux/bitops.h>
+#include <linux/spinlock.h>
#include <asm/processor.h>
#include <asm/cache.h>
+struct vm_area_struct;
+
/*
* kern_addr_valid(ADDR) tests if ADDR is pointing to valid kernel
* memory. For the return value to be meaningful, ADDR must be >=
diff --git a/arch/parisc/kernel/firmware.c b/arch/parisc/kernel/firmware.c
index df971fa..4896ed0 100644
--- a/arch/parisc/kernel/firmware.c
+++ b/arch/parisc/kernel/firmware.c
@@ -1126,15 +1126,13 @@ int pdc_iodc_print(const unsigned char *str, unsigned count)
unsigned int i;
unsigned long flags;
- for (i = 0; i < count && i < 79;) {
+ for (i = 0; i < count;) {
switch(str[i]) {
case '\n':
iodc_dbuf[i+0] = '\r';
iodc_dbuf[i+1] = '\n';
i += 2;
goto print;
- case '\b': /* BS */
- i--; /* overwrite last */
default:
iodc_dbuf[i] = str[i];
i++;
@@ -1142,15 +1140,6 @@ int pdc_iodc_print(const unsigned char *str, unsigned count)
}
}
- /* if we're at the end of line, and not already inserting a newline,
- * insert one anyway. iodc console doesn't claim to support >79 char
- * lines. don't account for this in the return value.
- */
- if (i == 79 && iodc_dbuf[i-1] != '\n') {
- iodc_dbuf[i+0] = '\r';
- iodc_dbuf[i+1] = '\n';
- }
-
print:
spin_lock_irqsave(&pdc_lock, flags);
real32_call(PAGE0->mem_cons.iodc_io,
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 959f38c..7d69e9b 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -36,24 +36,12 @@ config GENERIC_TIME_VSYSCALL
config GENERIC_CLOCKEVENTS
def_bool y
-config GENERIC_HARDIRQS
- bool
- default y
-
-config GENERIC_HARDIRQS_NO__DO_IRQ
- bool
- default y
-
config HAVE_SETUP_PER_CPU_AREA
def_bool PPC64
config NEED_PER_CPU_EMBED_FIRST_CHUNK
def_bool PPC64
-config IRQ_PER_CPU
- bool
- default y
-
config NR_IRQS
int "Number of virtual interrupt numbers"
range 32 32768
@@ -143,6 +131,9 @@ config PPC
select HAVE_PERF_EVENTS
select HAVE_REGS_AND_STACK_ACCESS_API
select HAVE_HW_BREAKPOINT if PERF_EVENTS && PPC_BOOK3S_64
+ select HAVE_GENERIC_HARDIRQS
+ select HAVE_SPARSE_IRQ
+ select IRQ_PER_CPU
config EARLY_PRINTK
bool
@@ -392,19 +383,6 @@ config IRQ_ALL_CPUS
CPU. Generally saying Y is safe, although some problems have been
reported with SMP Power Macintoshes with this option enabled.
-config SPARSE_IRQ
- bool "Support sparse irq numbering"
- default n
- help
- This enables support for sparse irqs. This is useful for distro
- kernels that want to define a high CONFIG_NR_CPUS value but still
- want to have low kernel memory footprint on smaller machines.
-
- ( Sparse IRQs can also be beneficial on NUMA boxes, as they spread
- out the irq_desc[] array in a more NUMA-friendly way. )
-
- If you don't know what to do here, say N.
-
config NUMA
bool "NUMA support"
depends on PPC64
diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile
index 96deec6..8917816 100644
--- a/arch/powerpc/boot/Makefile
+++ b/arch/powerpc/boot/Makefile
@@ -368,7 +368,7 @@ INSTALL := install
extra-installed := $(patsubst $(obj)/%, $(DESTDIR)$(WRAPPER_OBJDIR)/%, $(extra-y))
hostprogs-installed := $(patsubst %, $(DESTDIR)$(WRAPPER_BINDIR)/%, $(hostprogs-y))
wrapper-installed := $(DESTDIR)$(WRAPPER_BINDIR)/wrapper
-dts-installed := $(patsubst $(obj)/dts/%, $(DESTDIR)$(WRAPPER_DTSDIR)/%, $(wildcard $(obj)/dts/*.dts))
+dts-installed := $(patsubst $(dtstree)/%, $(DESTDIR)$(WRAPPER_DTSDIR)/%, $(wildcard $(dtstree)/*.dts))
all-installed := $(extra-installed) $(hostprogs-installed) $(wrapper-installed) $(dts-installed)
diff --git a/arch/powerpc/boot/dts/mpc8308rdb.dts b/arch/powerpc/boot/dts/mpc8308rdb.dts
index d3db02f..a0bd188 100644
--- a/arch/powerpc/boot/dts/mpc8308rdb.dts
+++ b/arch/powerpc/boot/dts/mpc8308rdb.dts
@@ -109,7 +109,7 @@
#address-cells = <1>;
#size-cells = <1>;
device_type = "soc";
- compatible = "fsl,mpc8315-immr", "simple-bus";
+ compatible = "fsl,mpc8308-immr", "simple-bus";
ranges = <0 0xe0000000 0x00100000>;
reg = <0xe0000000 0x00000200>;
bus-frequency = <0>;
diff --git a/arch/powerpc/boot/dts/p1022ds.dts b/arch/powerpc/boot/dts/p1022ds.dts
index 2bbecbb..69422eb 100644
--- a/arch/powerpc/boot/dts/p1022ds.dts
+++ b/arch/powerpc/boot/dts/p1022ds.dts
@@ -291,13 +291,13 @@
ranges = <0x0 0xc100 0x200>;
cell-index = <1>;
dma00: dma-channel@0 {
- compatible = "fsl,eloplus-dma-channel";
+ compatible = "fsl,ssi-dma-channel";
reg = <0x0 0x80>;
cell-index = <0>;
interrupts = <76 2>;
};
dma01: dma-channel@80 {
- compatible = "fsl,eloplus-dma-channel";
+ compatible = "fsl,ssi-dma-channel";
reg = <0x80 0x80>;
cell-index = <1>;
interrupts = <77 2>;
diff --git a/arch/powerpc/configs/40x/acadia_defconfig b/arch/powerpc/configs/40x/acadia_defconfig
index 97fedce..4182c77 100644
--- a/arch/powerpc/configs/40x/acadia_defconfig
+++ b/arch/powerpc/configs/40x/acadia_defconfig
@@ -5,7 +5,7 @@ CONFIG_POSIX_MQUEUE=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
CONFIG_KALLSYMS_ALL=y
CONFIG_KALLSYMS_EXTRA_PASS=y
CONFIG_MODULES=y
diff --git a/arch/powerpc/configs/40x/ep405_defconfig b/arch/powerpc/configs/40x/ep405_defconfig
index 33b3c24..2dbb293 100644
--- a/arch/powerpc/configs/40x/ep405_defconfig
+++ b/arch/powerpc/configs/40x/ep405_defconfig
@@ -5,7 +5,7 @@ CONFIG_POSIX_MQUEUE=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
CONFIG_KALLSYMS_ALL=y
CONFIG_KALLSYMS_EXTRA_PASS=y
CONFIG_MODULES=y
diff --git a/arch/powerpc/configs/40x/hcu4_defconfig b/arch/powerpc/configs/40x/hcu4_defconfig
index 4613079..ebeb4ac 100644
--- a/arch/powerpc/configs/40x/hcu4_defconfig
+++ b/arch/powerpc/configs/40x/hcu4_defconfig
@@ -5,7 +5,7 @@ CONFIG_POSIX_MQUEUE=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
CONFIG_KALLSYMS_ALL=y
CONFIG_KALLSYMS_EXTRA_PASS=y
CONFIG_MODULES=y
diff --git a/arch/powerpc/configs/40x/kilauea_defconfig b/arch/powerpc/configs/40x/kilauea_defconfig
index 34b8c1a..532ea9d 100644
--- a/arch/powerpc/configs/40x/kilauea_defconfig
+++ b/arch/powerpc/configs/40x/kilauea_defconfig
@@ -5,7 +5,7 @@ CONFIG_POSIX_MQUEUE=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
CONFIG_KALLSYMS_ALL=y
CONFIG_KALLSYMS_EXTRA_PASS=y
CONFIG_MODULES=y
diff --git a/arch/powerpc/configs/40x/makalu_defconfig b/arch/powerpc/configs/40x/makalu_defconfig
index 651be09..3c142ac 100644
--- a/arch/powerpc/configs/40x/makalu_defconfig
+++ b/arch/powerpc/configs/40x/makalu_defconfig
@@ -5,7 +5,7 @@ CONFIG_POSIX_MQUEUE=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
CONFIG_KALLSYMS_ALL=y
CONFIG_KALLSYMS_EXTRA_PASS=y
CONFIG_MODULES=y
diff --git a/arch/powerpc/configs/40x/walnut_defconfig b/arch/powerpc/configs/40x/walnut_defconfig
index ded455e..ff57d48 100644
--- a/arch/powerpc/configs/40x/walnut_defconfig
+++ b/arch/powerpc/configs/40x/walnut_defconfig
@@ -5,7 +5,7 @@ CONFIG_POSIX_MQUEUE=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
CONFIG_KALLSYMS_ALL=y
CONFIG_KALLSYMS_EXTRA_PASS=y
CONFIG_MODULES=y
diff --git a/arch/powerpc/configs/44x/arches_defconfig b/arch/powerpc/configs/44x/arches_defconfig
index 63746a0..3ed16d5 100644
--- a/arch/powerpc/configs/44x/arches_defconfig
+++ b/arch/powerpc/configs/44x/arches_defconfig
@@ -5,7 +5,7 @@ CONFIG_POSIX_MQUEUE=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
# CONFIG_BLK_DEV_BSG is not set
diff --git a/arch/powerpc/configs/44x/bamboo_defconfig b/arch/powerpc/configs/44x/bamboo_defconfig
index f5f2a4e..b1b7d2c 100644
--- a/arch/powerpc/configs/44x/bamboo_defconfig
+++ b/arch/powerpc/configs/44x/bamboo_defconfig
@@ -5,7 +5,7 @@ CONFIG_POSIX_MQUEUE=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
# CONFIG_BLK_DEV_BSG is not set
diff --git a/arch/powerpc/configs/44x/bluestone_defconfig b/arch/powerpc/configs/44x/bluestone_defconfig
index ac65b48..30a0a8e 100644
--- a/arch/powerpc/configs/44x/bluestone_defconfig
+++ b/arch/powerpc/configs/44x/bluestone_defconfig
@@ -4,7 +4,7 @@ CONFIG_SYSVIPC=y
CONFIG_POSIX_MQUEUE=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_BLK_DEV_INITRD=y
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_VM_EVENT_COUNTERS is not set
# CONFIG_PCI_QUIRKS is not set
# CONFIG_COMPAT_BRK is not set
diff --git a/arch/powerpc/configs/44x/canyonlands_defconfig b/arch/powerpc/configs/44x/canyonlands_defconfig
index 17e4dd9..a46942a 100644
--- a/arch/powerpc/configs/44x/canyonlands_defconfig
+++ b/arch/powerpc/configs/44x/canyonlands_defconfig
@@ -5,7 +5,7 @@ CONFIG_POSIX_MQUEUE=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
# CONFIG_BLK_DEV_BSG is not set
diff --git a/arch/powerpc/configs/44x/ebony_defconfig b/arch/powerpc/configs/44x/ebony_defconfig
index fedd03f..07d77e5 100644
--- a/arch/powerpc/configs/44x/ebony_defconfig
+++ b/arch/powerpc/configs/44x/ebony_defconfig
@@ -5,7 +5,7 @@ CONFIG_POSIX_MQUEUE=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
CONFIG_KALLSYMS_ALL=y
CONFIG_KALLSYMS_EXTRA_PASS=y
CONFIG_MODULES=y
diff --git a/arch/powerpc/configs/44x/eiger_defconfig b/arch/powerpc/configs/44x/eiger_defconfig
index ebff701..2ce7e9a 100644
--- a/arch/powerpc/configs/44x/eiger_defconfig
+++ b/arch/powerpc/configs/44x/eiger_defconfig
@@ -5,7 +5,7 @@ CONFIG_POSIX_MQUEUE=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
# CONFIG_BLK_DEV_BSG is not set
diff --git a/arch/powerpc/configs/44x/icon_defconfig b/arch/powerpc/configs/44x/icon_defconfig
index 865e93f..18730ff 100644
--- a/arch/powerpc/configs/44x/icon_defconfig
+++ b/arch/powerpc/configs/44x/icon_defconfig
@@ -6,7 +6,7 @@ CONFIG_LOG_BUF_SHIFT=14
CONFIG_SYSFS_DEPRECATED_V2=y
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
# CONFIG_BLK_DEV_BSG is not set
diff --git a/arch/powerpc/configs/44x/iss476-smp_defconfig b/arch/powerpc/configs/44x/iss476-smp_defconfig
index 8ece4c7..92f863a 100644
--- a/arch/powerpc/configs/44x/iss476-smp_defconfig
+++ b/arch/powerpc/configs/44x/iss476-smp_defconfig
@@ -7,7 +7,7 @@ CONFIG_LOG_BUF_SHIFT=14
CONFIG_SYSFS_DEPRECATED_V2=y
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
CONFIG_KALLSYMS_ALL=y
CONFIG_KALLSYMS_EXTRA_PASS=y
CONFIG_PROFILING=y
diff --git a/arch/powerpc/configs/44x/katmai_defconfig b/arch/powerpc/configs/44x/katmai_defconfig
index 4ca9b48..34c0914 100644
--- a/arch/powerpc/configs/44x/katmai_defconfig
+++ b/arch/powerpc/configs/44x/katmai_defconfig
@@ -5,7 +5,7 @@ CONFIG_POSIX_MQUEUE=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
# CONFIG_BLK_DEV_BSG is not set
diff --git a/arch/powerpc/configs/44x/rainier_defconfig b/arch/powerpc/configs/44x/rainier_defconfig
index e3b65d2..21c33fa 100644
--- a/arch/powerpc/configs/44x/rainier_defconfig
+++ b/arch/powerpc/configs/44x/rainier_defconfig
@@ -5,7 +5,7 @@ CONFIG_POSIX_MQUEUE=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
# CONFIG_BLK_DEV_BSG is not set
diff --git a/arch/powerpc/configs/44x/redwood_defconfig b/arch/powerpc/configs/44x/redwood_defconfig
index 64cd0f3..01cc2b1 100644
--- a/arch/powerpc/configs/44x/redwood_defconfig
+++ b/arch/powerpc/configs/44x/redwood_defconfig
@@ -5,7 +5,7 @@ CONFIG_POSIX_MQUEUE=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
# CONFIG_BLK_DEV_BSG is not set
diff --git a/arch/powerpc/configs/44x/sam440ep_defconfig b/arch/powerpc/configs/44x/sam440ep_defconfig
index 01d0336..dfcffed 100644
--- a/arch/powerpc/configs/44x/sam440ep_defconfig
+++ b/arch/powerpc/configs/44x/sam440ep_defconfig
@@ -6,7 +6,7 @@ CONFIG_IKCONFIG=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
# CONFIG_BLK_DEV_BSG is not set
diff --git a/arch/powerpc/configs/44x/sequoia_defconfig b/arch/powerpc/configs/44x/sequoia_defconfig
index 89b2f96..47e399f 100644
--- a/arch/powerpc/configs/44x/sequoia_defconfig
+++ b/arch/powerpc/configs/44x/sequoia_defconfig
@@ -5,7 +5,7 @@ CONFIG_POSIX_MQUEUE=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
# CONFIG_BLK_DEV_BSG is not set
diff --git a/arch/powerpc/configs/44x/taishan_defconfig b/arch/powerpc/configs/44x/taishan_defconfig
index e3386cf..a6a002e 100644
--- a/arch/powerpc/configs/44x/taishan_defconfig
+++ b/arch/powerpc/configs/44x/taishan_defconfig
@@ -5,7 +5,7 @@ CONFIG_POSIX_MQUEUE=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
# CONFIG_BLK_DEV_BSG is not set
diff --git a/arch/powerpc/configs/44x/warp_defconfig b/arch/powerpc/configs/44x/warp_defconfig
index 9c13b9d..6cf9d66 100644
--- a/arch/powerpc/configs/44x/warp_defconfig
+++ b/arch/powerpc/configs/44x/warp_defconfig
@@ -8,7 +8,7 @@ CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
# CONFIG_BLK_DEV_BSG is not set
diff --git a/arch/powerpc/configs/52xx/cm5200_defconfig b/arch/powerpc/configs/52xx/cm5200_defconfig
index f234c4d..69b57da 100644
--- a/arch/powerpc/configs/52xx/cm5200_defconfig
+++ b/arch/powerpc/configs/52xx/cm5200_defconfig
@@ -3,7 +3,7 @@ CONFIG_SYSVIPC=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_SYSCTL_SYSCALL is not set
# CONFIG_KALLSYMS is not set
# CONFIG_EPOLL is not set
diff --git a/arch/powerpc/configs/52xx/lite5200b_defconfig b/arch/powerpc/configs/52xx/lite5200b_defconfig
index a4a795c..f3638ae 100644
--- a/arch/powerpc/configs/52xx/lite5200b_defconfig
+++ b/arch/powerpc/configs/52xx/lite5200b_defconfig
@@ -3,7 +3,7 @@ CONFIG_SYSVIPC=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_SYSCTL_SYSCALL is not set
# CONFIG_KALLSYMS is not set
# CONFIG_EPOLL is not set
diff --git a/arch/powerpc/configs/52xx/motionpro_defconfig b/arch/powerpc/configs/52xx/motionpro_defconfig
index 20d53a1..6828eda 100644
--- a/arch/powerpc/configs/52xx/motionpro_defconfig
+++ b/arch/powerpc/configs/52xx/motionpro_defconfig
@@ -3,7 +3,7 @@ CONFIG_SYSVIPC=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_SYSCTL_SYSCALL is not set
# CONFIG_KALLSYMS is not set
# CONFIG_EPOLL is not set
diff --git a/arch/powerpc/configs/52xx/pcm030_defconfig b/arch/powerpc/configs/52xx/pcm030_defconfig
index 6bd5833..7f7e4a8 100644
--- a/arch/powerpc/configs/52xx/pcm030_defconfig
+++ b/arch/powerpc/configs/52xx/pcm030_defconfig
@@ -8,7 +8,7 @@ CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=14
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_SYSCTL_SYSCALL is not set
# CONFIG_VM_EVENT_COUNTERS is not set
CONFIG_SLAB=y
diff --git a/arch/powerpc/configs/52xx/tqm5200_defconfig b/arch/powerpc/configs/52xx/tqm5200_defconfig
index 3a1f702..959cd2c 100644
--- a/arch/powerpc/configs/52xx/tqm5200_defconfig
+++ b/arch/powerpc/configs/52xx/tqm5200_defconfig
@@ -3,7 +3,7 @@ CONFIG_SYSVIPC=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_SYSCTL_SYSCALL is not set
# CONFIG_KALLSYMS is not set
# CONFIG_EPOLL is not set
diff --git a/arch/powerpc/configs/83xx/asp8347_defconfig b/arch/powerpc/configs/83xx/asp8347_defconfig
index eed42d8..d2762d9 100644
--- a/arch/powerpc/configs/83xx/asp8347_defconfig
+++ b/arch/powerpc/configs/83xx/asp8347_defconfig
@@ -4,7 +4,7 @@ CONFIG_SYSVIPC=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_KALLSYMS is not set
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
diff --git a/arch/powerpc/configs/83xx/kmeter1_defconfig b/arch/powerpc/configs/83xx/kmeter1_defconfig
index e43ecb2..7a7b731 100644
--- a/arch/powerpc/configs/83xx/kmeter1_defconfig
+++ b/arch/powerpc/configs/83xx/kmeter1_defconfig
@@ -3,7 +3,7 @@ CONFIG_EXPERIMENTAL=y
CONFIG_SYSVIPC=y
CONFIG_POSIX_MQUEUE=y
CONFIG_LOG_BUF_SHIFT=14
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_HOTPLUG is not set
CONFIG_SLAB=y
CONFIG_MODULES=y
diff --git a/arch/powerpc/configs/83xx/mpc8313_rdb_defconfig b/arch/powerpc/configs/83xx/mpc8313_rdb_defconfig
index c2e6ab5..c683bce 100644
--- a/arch/powerpc/configs/83xx/mpc8313_rdb_defconfig
+++ b/arch/powerpc/configs/83xx/mpc8313_rdb_defconfig
@@ -3,7 +3,7 @@ CONFIG_SYSVIPC=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_KALLSYMS is not set
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
diff --git a/arch/powerpc/configs/83xx/mpc8315_rdb_defconfig b/arch/powerpc/configs/83xx/mpc8315_rdb_defconfig
index 1d3b200..a721cd3 100644
--- a/arch/powerpc/configs/83xx/mpc8315_rdb_defconfig
+++ b/arch/powerpc/configs/83xx/mpc8315_rdb_defconfig
@@ -3,7 +3,7 @@ CONFIG_SYSVIPC=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_KALLSYMS is not set
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
diff --git a/arch/powerpc/configs/83xx/mpc832x_mds_defconfig b/arch/powerpc/configs/83xx/mpc832x_mds_defconfig
index 91fe73b..a5699a1 100644
--- a/arch/powerpc/configs/83xx/mpc832x_mds_defconfig
+++ b/arch/powerpc/configs/83xx/mpc832x_mds_defconfig
@@ -3,7 +3,7 @@ CONFIG_SYSVIPC=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_KALLSYMS is not set
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
diff --git a/arch/powerpc/configs/83xx/mpc832x_rdb_defconfig b/arch/powerpc/configs/83xx/mpc832x_rdb_defconfig
index 6d300f2..b4da1a7 100644
--- a/arch/powerpc/configs/83xx/mpc832x_rdb_defconfig
+++ b/arch/powerpc/configs/83xx/mpc832x_rdb_defconfig
@@ -3,7 +3,7 @@ CONFIG_SYSVIPC=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_KALLSYMS is not set
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
diff --git a/arch/powerpc/configs/83xx/mpc834x_itx_defconfig b/arch/powerpc/configs/83xx/mpc834x_itx_defconfig
index b236a67..291f822 100644
--- a/arch/powerpc/configs/83xx/mpc834x_itx_defconfig
+++ b/arch/powerpc/configs/83xx/mpc834x_itx_defconfig
@@ -3,7 +3,7 @@ CONFIG_SYSVIPC=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_KALLSYMS is not set
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
diff --git a/arch/powerpc/configs/83xx/mpc834x_itxgp_defconfig b/arch/powerpc/configs/83xx/mpc834x_itxgp_defconfig
index 001dead..f8b228a 100644
--- a/arch/powerpc/configs/83xx/mpc834x_itxgp_defconfig
+++ b/arch/powerpc/configs/83xx/mpc834x_itxgp_defconfig
@@ -3,7 +3,7 @@ CONFIG_SYSVIPC=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_KALLSYMS is not set
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
diff --git a/arch/powerpc/configs/83xx/mpc834x_mds_defconfig b/arch/powerpc/configs/83xx/mpc834x_mds_defconfig
index 9dccefc..99660c0 100644
--- a/arch/powerpc/configs/83xx/mpc834x_mds_defconfig
+++ b/arch/powerpc/configs/83xx/mpc834x_mds_defconfig
@@ -3,7 +3,7 @@ CONFIG_SYSVIPC=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_KALLSYMS is not set
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
diff --git a/arch/powerpc/configs/83xx/mpc836x_mds_defconfig b/arch/powerpc/configs/83xx/mpc836x_mds_defconfig
index d4b165d..10b5c4c 100644
--- a/arch/powerpc/configs/83xx/mpc836x_mds_defconfig
+++ b/arch/powerpc/configs/83xx/mpc836x_mds_defconfig
@@ -3,7 +3,7 @@ CONFIG_SYSVIPC=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_KALLSYMS is not set
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
diff --git a/arch/powerpc/configs/83xx/mpc836x_rdk_defconfig b/arch/powerpc/configs/83xx/mpc836x_rdk_defconfig
index 89ba672..45925d7 100644
--- a/arch/powerpc/configs/83xx/mpc836x_rdk_defconfig
+++ b/arch/powerpc/configs/83xx/mpc836x_rdk_defconfig
@@ -3,7 +3,7 @@ CONFIG_SYSVIPC=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_KALLSYMS is not set
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
diff --git a/arch/powerpc/configs/83xx/mpc837x_mds_defconfig b/arch/powerpc/configs/83xx/mpc837x_mds_defconfig
index 2ea6b40..f367985 100644
--- a/arch/powerpc/configs/83xx/mpc837x_mds_defconfig
+++ b/arch/powerpc/configs/83xx/mpc837x_mds_defconfig
@@ -3,7 +3,7 @@ CONFIG_SYSVIPC=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
CONFIG_SLAB=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
diff --git a/arch/powerpc/configs/83xx/mpc837x_rdb_defconfig b/arch/powerpc/configs/83xx/mpc837x_rdb_defconfig
index bffe3c7..414eda3 100644
--- a/arch/powerpc/configs/83xx/mpc837x_rdb_defconfig
+++ b/arch/powerpc/configs/83xx/mpc837x_rdb_defconfig
@@ -3,7 +3,7 @@ CONFIG_SYSVIPC=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
CONFIG_SLAB=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
diff --git a/arch/powerpc/configs/83xx/sbc834x_defconfig b/arch/powerpc/configs/83xx/sbc834x_defconfig
index fa5c9ee..6d6463f 100644
--- a/arch/powerpc/configs/83xx/sbc834x_defconfig
+++ b/arch/powerpc/configs/83xx/sbc834x_defconfig
@@ -3,7 +3,7 @@ CONFIG_SYSVIPC=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_KALLSYMS is not set
CONFIG_SLAB=y
CONFIG_MODULES=y
diff --git a/arch/powerpc/configs/85xx/ksi8560_defconfig b/arch/powerpc/configs/85xx/ksi8560_defconfig
index 385b1af..8f7c106 100644
--- a/arch/powerpc/configs/85xx/ksi8560_defconfig
+++ b/arch/powerpc/configs/85xx/ksi8560_defconfig
@@ -4,7 +4,7 @@ CONFIG_SYSVIPC=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_BLK_DEV_BSG is not set
CONFIG_KSI8560=y
CONFIG_CPM2=y
diff --git a/arch/powerpc/configs/85xx/mpc8540_ads_defconfig b/arch/powerpc/configs/85xx/mpc8540_ads_defconfig
index 222b704..55e0725 100644
--- a/arch/powerpc/configs/85xx/mpc8540_ads_defconfig
+++ b/arch/powerpc/configs/85xx/mpc8540_ads_defconfig
@@ -4,7 +4,7 @@ CONFIG_SYSVIPC=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_BLK_DEV_BSG is not set
CONFIG_MPC8540_ADS=y
CONFIG_NO_HZ=y
diff --git a/arch/powerpc/configs/85xx/mpc8560_ads_defconfig b/arch/powerpc/configs/85xx/mpc8560_ads_defconfig
index 619702d..d724095 100644
--- a/arch/powerpc/configs/85xx/mpc8560_ads_defconfig
+++ b/arch/powerpc/configs/85xx/mpc8560_ads_defconfig
@@ -4,7 +4,7 @@ CONFIG_SYSVIPC=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_BLK_DEV_BSG is not set
CONFIG_MPC8560_ADS=y
CONFIG_BINFMT_MISC=y
diff --git a/arch/powerpc/configs/85xx/mpc85xx_cds_defconfig b/arch/powerpc/configs/85xx/mpc85xx_cds_defconfig
index 6bf56e8..4b44bea 100644
--- a/arch/powerpc/configs/85xx/mpc85xx_cds_defconfig
+++ b/arch/powerpc/configs/85xx/mpc85xx_cds_defconfig
@@ -4,7 +4,7 @@ CONFIG_SYSVIPC=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_BLK_DEV_BSG is not set
CONFIG_MPC85xx_CDS=y
CONFIG_NO_HZ=y
diff --git a/arch/powerpc/configs/85xx/sbc8548_defconfig b/arch/powerpc/configs/85xx/sbc8548_defconfig
index a9a17d0..5b2b651 100644
--- a/arch/powerpc/configs/85xx/sbc8548_defconfig
+++ b/arch/powerpc/configs/85xx/sbc8548_defconfig
@@ -4,7 +4,7 @@ CONFIG_SYSVIPC=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
CONFIG_SLAB=y
# CONFIG_BLK_DEV_BSG is not set
CONFIG_SBC8548=y
diff --git a/arch/powerpc/configs/85xx/sbc8560_defconfig b/arch/powerpc/configs/85xx/sbc8560_defconfig
index 820e32d..f7fdb03 100644
--- a/arch/powerpc/configs/85xx/sbc8560_defconfig
+++ b/arch/powerpc/configs/85xx/sbc8560_defconfig
@@ -4,7 +4,7 @@ CONFIG_SYSVIPC=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
CONFIG_SLAB=y
# CONFIG_BLK_DEV_BSG is not set
CONFIG_SBC8560=y
diff --git a/arch/powerpc/configs/85xx/socrates_defconfig b/arch/powerpc/configs/85xx/socrates_defconfig
index b6db3f4..77506b5 100644
--- a/arch/powerpc/configs/85xx/socrates_defconfig
+++ b/arch/powerpc/configs/85xx/socrates_defconfig
@@ -4,7 +4,7 @@ CONFIG_SYSVIPC=y
CONFIG_LOG_BUF_SHIFT=16
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_KALLSYMS is not set
# CONFIG_HOTPLUG is not set
# CONFIG_EPOLL is not set
diff --git a/arch/powerpc/configs/85xx/stx_gp3_defconfig b/arch/powerpc/configs/85xx/stx_gp3_defconfig
index 333a41bd2..5d4db15 100644
--- a/arch/powerpc/configs/85xx/stx_gp3_defconfig
+++ b/arch/powerpc/configs/85xx/stx_gp3_defconfig
@@ -4,7 +4,7 @@ CONFIG_SYSVIPC=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
CONFIG_MODULES=y
CONFIG_MODVERSIONS=y
# CONFIG_BLK_DEV_BSG is not set
diff --git a/arch/powerpc/configs/85xx/tqm8540_defconfig b/arch/powerpc/configs/85xx/tqm8540_defconfig
index 33db352..ddcb9f3 100644
--- a/arch/powerpc/configs/85xx/tqm8540_defconfig
+++ b/arch/powerpc/configs/85xx/tqm8540_defconfig
@@ -4,7 +4,7 @@ CONFIG_SYSVIPC=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_KALLSYMS is not set
# CONFIG_HOTPLUG is not set
# CONFIG_EPOLL is not set
diff --git a/arch/powerpc/configs/85xx/tqm8541_defconfig b/arch/powerpc/configs/85xx/tqm8541_defconfig
index f0c20df..981abd6 100644
--- a/arch/powerpc/configs/85xx/tqm8541_defconfig
+++ b/arch/powerpc/configs/85xx/tqm8541_defconfig
@@ -4,7 +4,7 @@ CONFIG_SYSVIPC=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_KALLSYMS is not set
# CONFIG_HOTPLUG is not set
# CONFIG_EPOLL is not set
diff --git a/arch/powerpc/configs/85xx/tqm8548_defconfig b/arch/powerpc/configs/85xx/tqm8548_defconfig
index a883450..37b3d72 100644
--- a/arch/powerpc/configs/85xx/tqm8548_defconfig
+++ b/arch/powerpc/configs/85xx/tqm8548_defconfig
@@ -4,7 +4,7 @@ CONFIG_SYSVIPC=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
# CONFIG_BLK_DEV_BSG is not set
diff --git a/arch/powerpc/configs/85xx/tqm8555_defconfig b/arch/powerpc/configs/85xx/tqm8555_defconfig
index ff95f90..3593b32 100644
--- a/arch/powerpc/configs/85xx/tqm8555_defconfig
+++ b/arch/powerpc/configs/85xx/tqm8555_defconfig
@@ -4,7 +4,7 @@ CONFIG_SYSVIPC=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_KALLSYMS is not set
# CONFIG_HOTPLUG is not set
# CONFIG_EPOLL is not set
diff --git a/arch/powerpc/configs/85xx/tqm8560_defconfig b/arch/powerpc/configs/85xx/tqm8560_defconfig
index 8d6c90e..de413ac 100644
--- a/arch/powerpc/configs/85xx/tqm8560_defconfig
+++ b/arch/powerpc/configs/85xx/tqm8560_defconfig
@@ -4,7 +4,7 @@ CONFIG_SYSVIPC=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_KALLSYMS is not set
# CONFIG_HOTPLUG is not set
# CONFIG_EPOLL is not set
diff --git a/arch/powerpc/configs/85xx/xes_mpc85xx_defconfig b/arch/powerpc/configs/85xx/xes_mpc85xx_defconfig
index f53efe4..5ea3124 100644
--- a/arch/powerpc/configs/85xx/xes_mpc85xx_defconfig
+++ b/arch/powerpc/configs/85xx/xes_mpc85xx_defconfig
@@ -11,7 +11,7 @@ CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
CONFIG_KALLSYMS_ALL=y
CONFIG_KALLSYMS_EXTRA_PASS=y
CONFIG_MODULES=y
diff --git a/arch/powerpc/configs/86xx/gef_ppc9a_defconfig b/arch/powerpc/configs/86xx/gef_ppc9a_defconfig
index 432ebc2..4b24412 100644
--- a/arch/powerpc/configs/86xx/gef_ppc9a_defconfig
+++ b/arch/powerpc/configs/86xx/gef_ppc9a_defconfig
@@ -11,7 +11,7 @@ CONFIG_LOG_BUF_SHIFT=14
CONFIG_RELAY=y
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
CONFIG_SLAB=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
diff --git a/arch/powerpc/configs/86xx/gef_sbc310_defconfig b/arch/powerpc/configs/86xx/gef_sbc310_defconfig
index ce5e919..a360ba4 100644
--- a/arch/powerpc/configs/86xx/gef_sbc310_defconfig
+++ b/arch/powerpc/configs/86xx/gef_sbc310_defconfig
@@ -11,7 +11,7 @@ CONFIG_LOG_BUF_SHIFT=14
CONFIG_RELAY=y
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
CONFIG_SLAB=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
diff --git a/arch/powerpc/configs/86xx/gef_sbc610_defconfig b/arch/powerpc/configs/86xx/gef_sbc610_defconfig
index 589e71e..be2829d 100644
--- a/arch/powerpc/configs/86xx/gef_sbc610_defconfig
+++ b/arch/powerpc/configs/86xx/gef_sbc610_defconfig
@@ -11,7 +11,7 @@ CONFIG_LOG_BUF_SHIFT=14
CONFIG_RELAY=y
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
CONFIG_SLAB=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
diff --git a/arch/powerpc/configs/86xx/mpc8610_hpcd_defconfig b/arch/powerpc/configs/86xx/mpc8610_hpcd_defconfig
index 321fb47..036bfb2 100644
--- a/arch/powerpc/configs/86xx/mpc8610_hpcd_defconfig
+++ b/arch/powerpc/configs/86xx/mpc8610_hpcd_defconfig
@@ -6,7 +6,7 @@ CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
CONFIG_KALLSYMS_EXTRA_PASS=y
# CONFIG_ELF_CORE is not set
CONFIG_MODULES=y
diff --git a/arch/powerpc/configs/86xx/mpc8641_hpcn_defconfig b/arch/powerpc/configs/86xx/mpc8641_hpcn_defconfig
index b5e4639..0c9c7ed 100644
--- a/arch/powerpc/configs/86xx/mpc8641_hpcn_defconfig
+++ b/arch/powerpc/configs/86xx/mpc8641_hpcn_defconfig
@@ -10,7 +10,7 @@ CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
CONFIG_KALLSYMS_ALL=y
CONFIG_KALLSYMS_EXTRA_PASS=y
CONFIG_MODULES=y
diff --git a/arch/powerpc/configs/86xx/sbc8641d_defconfig b/arch/powerpc/configs/86xx/sbc8641d_defconfig
index 71145c3..0a92ca0 100644
--- a/arch/powerpc/configs/86xx/sbc8641d_defconfig
+++ b/arch/powerpc/configs/86xx/sbc8641d_defconfig
@@ -11,7 +11,7 @@ CONFIG_LOG_BUF_SHIFT=14
CONFIG_RELAY=y
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
CONFIG_SLAB=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
diff --git a/arch/powerpc/configs/adder875_defconfig b/arch/powerpc/configs/adder875_defconfig
index ca84c7f..6912874 100644
--- a/arch/powerpc/configs/adder875_defconfig
+++ b/arch/powerpc/configs/adder875_defconfig
@@ -4,7 +4,7 @@ CONFIG_EXPERIMENTAL=y
CONFIG_SYSVIPC=y
CONFIG_LOG_BUF_SHIFT=14
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_SYSCTL_SYSCALL is not set
# CONFIG_ELF_CORE is not set
# CONFIG_BASE_FULL is not set
diff --git a/arch/powerpc/configs/e55xx_smp_defconfig b/arch/powerpc/configs/e55xx_smp_defconfig
index 94d120e..06f9549 100644
--- a/arch/powerpc/configs/e55xx_smp_defconfig
+++ b/arch/powerpc/configs/e55xx_smp_defconfig
@@ -12,7 +12,7 @@ CONFIG_LOG_BUF_SHIFT=14
CONFIG_SYSFS_DEPRECATED_V2=y
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
CONFIG_KALLSYMS_ALL=y
CONFIG_KALLSYMS_EXTRA_PASS=y
CONFIG_MODULES=y
diff --git a/arch/powerpc/configs/ep8248e_defconfig b/arch/powerpc/configs/ep8248e_defconfig
index 2677b08..fceffb3 100644
--- a/arch/powerpc/configs/ep8248e_defconfig
+++ b/arch/powerpc/configs/ep8248e_defconfig
@@ -2,7 +2,7 @@ CONFIG_SYSVIPC=y
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=14
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
CONFIG_KALLSYMS_ALL=y
CONFIG_SLAB=y
# CONFIG_IOSCHED_CFQ is not set
diff --git a/arch/powerpc/configs/ep88xc_defconfig b/arch/powerpc/configs/ep88xc_defconfig
index f9a3112..219fd47 100644
--- a/arch/powerpc/configs/ep88xc_defconfig
+++ b/arch/powerpc/configs/ep88xc_defconfig
@@ -4,7 +4,7 @@ CONFIG_EXPERIMENTAL=y
CONFIG_SYSVIPC=y
CONFIG_LOG_BUF_SHIFT=14
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_SYSCTL_SYSCALL is not set
# CONFIG_ELF_CORE is not set
# CONFIG_BASE_FULL is not set
diff --git a/arch/powerpc/configs/gamecube_defconfig b/arch/powerpc/configs/gamecube_defconfig
index fcf0a39..e74d3a4 100644
--- a/arch/powerpc/configs/gamecube_defconfig
+++ b/arch/powerpc/configs/gamecube_defconfig
@@ -6,7 +6,7 @@ CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_ELF_CORE is not set
CONFIG_PERF_COUNTERS=y
# CONFIG_VM_EVENT_COUNTERS is not set
diff --git a/arch/powerpc/configs/holly_defconfig b/arch/powerpc/configs/holly_defconfig
index b9b63a6..94ebfee 100644
--- a/arch/powerpc/configs/holly_defconfig
+++ b/arch/powerpc/configs/holly_defconfig
@@ -3,7 +3,7 @@ CONFIG_SYSVIPC=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
CONFIG_MODULES=y
# CONFIG_BLK_DEV_BSG is not set
# CONFIG_PPC_CHRP is not set
diff --git a/arch/powerpc/configs/mgcoge_defconfig b/arch/powerpc/configs/mgcoge_defconfig
index c4ed255..39518e9 100644
--- a/arch/powerpc/configs/mgcoge_defconfig
+++ b/arch/powerpc/configs/mgcoge_defconfig
@@ -3,7 +3,7 @@ CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_BLK_DEV_INITRD=y
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
CONFIG_KALLSYMS_ALL=y
CONFIG_SLAB=y
# CONFIG_IOSCHED_CFQ is not set
diff --git a/arch/powerpc/configs/mgsuvd_defconfig b/arch/powerpc/configs/mgsuvd_defconfig
index f276c7c..2a49062 100644
--- a/arch/powerpc/configs/mgsuvd_defconfig
+++ b/arch/powerpc/configs/mgsuvd_defconfig
@@ -4,7 +4,7 @@ CONFIG_EXPERIMENTAL=y
CONFIG_SYSVIPC=y
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_SYSCTL_SYSCALL is not set
# CONFIG_HOTPLUG is not set
# CONFIG_BUG is not set
diff --git a/arch/powerpc/configs/mpc7448_hpc2_defconfig b/arch/powerpc/configs/mpc7448_hpc2_defconfig
index 3b94708..75f0bbf 100644
--- a/arch/powerpc/configs/mpc7448_hpc2_defconfig
+++ b/arch/powerpc/configs/mpc7448_hpc2_defconfig
@@ -4,7 +4,7 @@ CONFIG_SYSVIPC=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_BLK_DEV_BSG is not set
# CONFIG_PPC_CHRP is not set
# CONFIG_PPC_PMAC is not set
diff --git a/arch/powerpc/configs/mpc8272_ads_defconfig b/arch/powerpc/configs/mpc8272_ads_defconfig
index c7d68ff..6a22400 100644
--- a/arch/powerpc/configs/mpc8272_ads_defconfig
+++ b/arch/powerpc/configs/mpc8272_ads_defconfig
@@ -2,7 +2,7 @@ CONFIG_SYSVIPC=y
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=14
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
CONFIG_KALLSYMS_ALL=y
# CONFIG_PPC_CHRP is not set
# CONFIG_PPC_PMAC is not set
diff --git a/arch/powerpc/configs/mpc83xx_defconfig b/arch/powerpc/configs/mpc83xx_defconfig
index 5b1b10f..5aac9a8 100644
--- a/arch/powerpc/configs/mpc83xx_defconfig
+++ b/arch/powerpc/configs/mpc83xx_defconfig
@@ -3,7 +3,7 @@ CONFIG_SYSVIPC=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
CONFIG_SLAB=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
diff --git a/arch/powerpc/configs/mpc85xx_defconfig b/arch/powerpc/configs/mpc85xx_defconfig
index 3aeb594..99a19d1 100644
--- a/arch/powerpc/configs/mpc85xx_defconfig
+++ b/arch/powerpc/configs/mpc85xx_defconfig
@@ -10,7 +10,7 @@ CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
CONFIG_KALLSYMS_ALL=y
CONFIG_KALLSYMS_EXTRA_PASS=y
CONFIG_MODULES=y
diff --git a/arch/powerpc/configs/mpc85xx_smp_defconfig b/arch/powerpc/configs/mpc85xx_smp_defconfig
index d62c801..c636f23 100644
--- a/arch/powerpc/configs/mpc85xx_smp_defconfig
+++ b/arch/powerpc/configs/mpc85xx_smp_defconfig
@@ -12,7 +12,7 @@ CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
CONFIG_KALLSYMS_ALL=y
CONFIG_KALLSYMS_EXTRA_PASS=y
CONFIG_MODULES=y
diff --git a/arch/powerpc/configs/mpc866_ads_defconfig b/arch/powerpc/configs/mpc866_ads_defconfig
index 668215c..5c25882 100644
--- a/arch/powerpc/configs/mpc866_ads_defconfig
+++ b/arch/powerpc/configs/mpc866_ads_defconfig
@@ -4,7 +4,7 @@ CONFIG_EXPERIMENTAL=y
CONFIG_SYSVIPC=y
CONFIG_LOG_BUF_SHIFT=14
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_SYSCTL_SYSCALL is not set
# CONFIG_HOTPLUG is not set
# CONFIG_BUG is not set
diff --git a/arch/powerpc/configs/mpc86xx_defconfig b/arch/powerpc/configs/mpc86xx_defconfig
index 63b90d4..55b5431 100644
--- a/arch/powerpc/configs/mpc86xx_defconfig
+++ b/arch/powerpc/configs/mpc86xx_defconfig
@@ -10,7 +10,7 @@ CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
CONFIG_KALLSYMS_ALL=y
CONFIG_KALLSYMS_EXTRA_PASS=y
CONFIG_MODULES=y
diff --git a/arch/powerpc/configs/mpc885_ads_defconfig b/arch/powerpc/configs/mpc885_ads_defconfig
index f9b8348..9e146cd 100644
--- a/arch/powerpc/configs/mpc885_ads_defconfig
+++ b/arch/powerpc/configs/mpc885_ads_defconfig
@@ -4,7 +4,7 @@ CONFIG_EXPERIMENTAL=y
CONFIG_SYSVIPC=y
CONFIG_LOG_BUF_SHIFT=14
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_SYSCTL_SYSCALL is not set
# CONFIG_ELF_CORE is not set
# CONFIG_BASE_FULL is not set
diff --git a/arch/powerpc/configs/ppc40x_defconfig b/arch/powerpc/configs/ppc40x_defconfig
index 93d7425..bfd634b 100644
--- a/arch/powerpc/configs/ppc40x_defconfig
+++ b/arch/powerpc/configs/ppc40x_defconfig
@@ -5,7 +5,7 @@ CONFIG_POSIX_MQUEUE=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
CONFIG_KALLSYMS_ALL=y
CONFIG_KALLSYMS_EXTRA_PASS=y
CONFIG_MODULES=y
diff --git a/arch/powerpc/configs/ppc44x_defconfig b/arch/powerpc/configs/ppc44x_defconfig
index 2fa05f7..4713320 100644
--- a/arch/powerpc/configs/ppc44x_defconfig
+++ b/arch/powerpc/configs/ppc44x_defconfig
@@ -5,7 +5,7 @@ CONFIG_POSIX_MQUEUE=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
CONFIG_KALLSYMS_ALL=y
CONFIG_KALLSYMS_EXTRA_PASS=y
CONFIG_MODULES=y
diff --git a/arch/powerpc/configs/pq2fads_defconfig b/arch/powerpc/configs/pq2fads_defconfig
index a4353be..baad8db 100644
--- a/arch/powerpc/configs/pq2fads_defconfig
+++ b/arch/powerpc/configs/pq2fads_defconfig
@@ -3,7 +3,7 @@ CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_BLK_DEV_INITRD=y
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
CONFIG_KALLSYMS_ALL=y
# CONFIG_PPC_CHRP is not set
# CONFIG_PPC_PMAC is not set
diff --git a/arch/powerpc/configs/ps3_defconfig b/arch/powerpc/configs/ps3_defconfig
index 49cffe0..caba919 100644
--- a/arch/powerpc/configs/ps3_defconfig
+++ b/arch/powerpc/configs/ps3_defconfig
@@ -8,7 +8,7 @@ CONFIG_SYSVIPC=y
CONFIG_POSIX_MQUEUE=y
CONFIG_NAMESPACES=y
CONFIG_BLK_DEV_INITRD=y
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
CONFIG_KALLSYMS_EXTRA_PASS=y
# CONFIG_PERF_EVENTS is not set
# CONFIG_COMPAT_BRK is not set
diff --git a/arch/powerpc/configs/pseries_defconfig b/arch/powerpc/configs/pseries_defconfig
index f87f0e1..9c3f22c 100644
--- a/arch/powerpc/configs/pseries_defconfig
+++ b/arch/powerpc/configs/pseries_defconfig
@@ -2,7 +2,7 @@ CONFIG_PPC64=y
CONFIG_ALTIVEC=y
CONFIG_VSX=y
CONFIG_SMP=y
-CONFIG_NR_CPUS=128
+CONFIG_NR_CPUS=1024
CONFIG_EXPERIMENTAL=y
CONFIG_SYSVIPC=y
CONFIG_POSIX_MQUEUE=y
@@ -45,6 +45,8 @@ CONFIG_KEXEC=y
CONFIG_IRQ_ALL_CPUS=y
CONFIG_MEMORY_HOTPLUG=y
CONFIG_MEMORY_HOTREMOVE=y
+CONFIG_PPC_64K_PAGES=y
+CONFIG_PPC_SUBPAGE_PROT=y
CONFIG_SCHED_SMT=y
CONFIG_HOTPLUG_PCI=m
CONFIG_HOTPLUG_PCI_RPA=m
@@ -184,6 +186,7 @@ CONFIG_ACENIC_OMIT_TIGON_I=y
CONFIG_E1000=y
CONFIG_E1000E=y
CONFIG_TIGON3=y
+CONFIG_BNX2=m
CONFIG_CHELSIO_T1=m
CONFIG_CHELSIO_T3=m
CONFIG_EHEA=y
@@ -311,9 +314,7 @@ CONFIG_DEBUG_KERNEL=y
# CONFIG_RCU_CPU_STALL_DETECTOR is not set
CONFIG_LATENCYTOP=y
CONFIG_SYSCTL_SYSCALL_CHECK=y
-CONFIG_IRQSOFF_TRACER=y
CONFIG_SCHED_TRACER=y
-CONFIG_STACK_TRACER=y
CONFIG_BLK_DEV_IO_TRACE=y
CONFIG_DEBUG_STACKOVERFLOW=y
CONFIG_DEBUG_STACK_USAGE=y
diff --git a/arch/powerpc/configs/storcenter_defconfig b/arch/powerpc/configs/storcenter_defconfig
index 4f0c10a..ebb2a66 100644
--- a/arch/powerpc/configs/storcenter_defconfig
+++ b/arch/powerpc/configs/storcenter_defconfig
@@ -1,7 +1,7 @@
CONFIG_EXPERIMENTAL=y
CONFIG_SYSVIPC=y
CONFIG_LOG_BUF_SHIFT=14
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_KALLSYMS is not set
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
diff --git a/arch/powerpc/configs/tqm8xx_defconfig b/arch/powerpc/configs/tqm8xx_defconfig
index d0a5b67..8616fde 100644
--- a/arch/powerpc/configs/tqm8xx_defconfig
+++ b/arch/powerpc/configs/tqm8xx_defconfig
@@ -5,7 +5,7 @@ CONFIG_SYSVIPC=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_SYSFS_DEPRECATED_V2=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_SYSCTL_SYSCALL is not set
# CONFIG_ELF_CORE is not set
# CONFIG_BASE_FULL is not set
diff --git a/arch/powerpc/configs/wii_defconfig b/arch/powerpc/configs/wii_defconfig
index bb8ba75..175295f 100644
--- a/arch/powerpc/configs/wii_defconfig
+++ b/arch/powerpc/configs/wii_defconfig
@@ -7,7 +7,7 @@ CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_ELF_CORE is not set
CONFIG_PERF_COUNTERS=y
# CONFIG_VM_EVENT_COUNTERS is not set
diff --git a/arch/powerpc/include/asm/feature-fixups.h b/arch/powerpc/include/asm/feature-fixups.h
index 96a7d06..921a847 100644
--- a/arch/powerpc/include/asm/feature-fixups.h
+++ b/arch/powerpc/include/asm/feature-fixups.h
@@ -37,18 +37,21 @@ label##2: \
.align 2; \
label##3:
-#define MAKE_FTR_SECTION_ENTRY(msk, val, label, sect) \
-label##4: \
- .popsection; \
- .pushsection sect,"a"; \
- .align 3; \
-label##5: \
- FTR_ENTRY_LONG msk; \
- FTR_ENTRY_LONG val; \
- FTR_ENTRY_OFFSET label##1b-label##5b; \
- FTR_ENTRY_OFFSET label##2b-label##5b; \
- FTR_ENTRY_OFFSET label##3b-label##5b; \
- FTR_ENTRY_OFFSET label##4b-label##5b; \
+#define MAKE_FTR_SECTION_ENTRY(msk, val, label, sect) \
+label##4: \
+ .popsection; \
+ .pushsection sect,"a"; \
+ .align 3; \
+label##5: \
+ FTR_ENTRY_LONG msk; \
+ FTR_ENTRY_LONG val; \
+ FTR_ENTRY_OFFSET label##1b-label##5b; \
+ FTR_ENTRY_OFFSET label##2b-label##5b; \
+ FTR_ENTRY_OFFSET label##3b-label##5b; \
+ FTR_ENTRY_OFFSET label##4b-label##5b; \
+ .ifgt (label##4b-label##3b)-(label##2b-label##1b); \
+ .error "Feature section else case larger than body"; \
+ .endif; \
.popsection;
diff --git a/arch/powerpc/include/asm/immap_qe.h b/arch/powerpc/include/asm/immap_qe.h
index 4e10f50..0edb684 100644
--- a/arch/powerpc/include/asm/immap_qe.h
+++ b/arch/powerpc/include/asm/immap_qe.h
@@ -467,13 +467,22 @@ struct qe_immap {
extern struct qe_immap __iomem *qe_immr;
extern phys_addr_t get_qe_base(void);
-static inline unsigned long immrbar_virt_to_phys(void *address)
+/*
+ * Returns the offset within the QE address space of the given pointer.
+ *
+ * Note that the QE does not support 36-bit physical addresses, so if
+ * get_qe_base() returns a number above 4GB, the caller will probably fail.
+ */
+static inline phys_addr_t immrbar_virt_to_phys(void *address)
{
- if ( ((u32)address >= (u32)qe_immr) &&
- ((u32)address < ((u32)qe_immr + QE_IMMAP_SIZE)) )
- return (unsigned long)(address - (u32)qe_immr +
- (u32)get_qe_base());
- return (unsigned long)virt_to_phys(address);
+ void *q = (void *)qe_immr;
+
+ /* Is it a MURAM address? */
+ if ((address >= q) && (address < (q + QE_IMMAP_SIZE)))
+ return get_qe_base() + (address - q);
+
+ /* It's an address returned by kmalloc */
+ return virt_to_phys(address);
}
#endif /* __KERNEL__ */
diff --git a/arch/powerpc/include/asm/irqflags.h b/arch/powerpc/include/asm/irqflags.h
index b85d8dd..b0b06d8 100644
--- a/arch/powerpc/include/asm/irqflags.h
+++ b/arch/powerpc/include/asm/irqflags.h
@@ -12,24 +12,44 @@
#else
#ifdef CONFIG_TRACE_IRQFLAGS
+#ifdef CONFIG_IRQSOFF_TRACER
+/*
+ * Since the ftrace irqsoff latency trace checks CALLER_ADDR1,
+ * which is the stack frame here, we need to force a stack frame
+ * in case we came from user space.
+ */
+#define TRACE_WITH_FRAME_BUFFER(func) \
+ mflr r0; \
+ stdu r1, -32(r1); \
+ std r0, 16(r1); \
+ stdu r1, -32(r1); \
+ bl func; \
+ ld r1, 0(r1); \
+ ld r1, 0(r1);
+#else
+#define TRACE_WITH_FRAME_BUFFER(func) \
+ bl func;
+#endif
+
/*
* Most of the CPU's IRQ-state tracing is done from assembly code; we
* have to call a C function so call a wrapper that saves all the
* C-clobbered registers.
*/
-#define TRACE_ENABLE_INTS bl .trace_hardirqs_on
-#define TRACE_DISABLE_INTS bl .trace_hardirqs_off
-#define TRACE_AND_RESTORE_IRQ_PARTIAL(en,skip) \
- cmpdi en,0; \
- bne 95f; \
- stb en,PACASOFTIRQEN(r13); \
- bl .trace_hardirqs_off; \
- b skip; \
-95: bl .trace_hardirqs_on; \
+#define TRACE_ENABLE_INTS TRACE_WITH_FRAME_BUFFER(.trace_hardirqs_on)
+#define TRACE_DISABLE_INTS TRACE_WITH_FRAME_BUFFER(.trace_hardirqs_off)
+
+#define TRACE_AND_RESTORE_IRQ_PARTIAL(en,skip) \
+ cmpdi en,0; \
+ bne 95f; \
+ stb en,PACASOFTIRQEN(r13); \
+ TRACE_WITH_FRAME_BUFFER(.trace_hardirqs_off) \
+ b skip; \
+95: TRACE_WITH_FRAME_BUFFER(.trace_hardirqs_on) \
li en,1;
#define TRACE_AND_RESTORE_IRQ(en) \
TRACE_AND_RESTORE_IRQ_PARTIAL(en,96f); \
- stb en,PACASOFTIRQEN(r13); \
+ stb en,PACASOFTIRQEN(r13); \
96:
#else
#define TRACE_ENABLE_INTS
diff --git a/arch/powerpc/include/asm/machdep.h b/arch/powerpc/include/asm/machdep.h
index 8433d36..991d599 100644
--- a/arch/powerpc/include/asm/machdep.h
+++ b/arch/powerpc/include/asm/machdep.h
@@ -116,9 +116,6 @@ struct machdep_calls {
* If for some reason there is no irq, but the interrupt
* shouldn't be counted as spurious, return NO_IRQ_IGNORE. */
unsigned int (*get_irq)(void);
-#ifdef CONFIG_KEXEC
- void (*kexec_cpu_down)(int crash_shutdown, int secondary);
-#endif
/* PCI stuff */
/* Called after scanning the bus, before allocating resources */
@@ -235,11 +232,7 @@ struct machdep_calls {
void (*machine_shutdown)(void);
#ifdef CONFIG_KEXEC
- /* Called to do the minimal shutdown needed to run a kexec'd kernel
- * to run successfully.
- * XXX Should we move this one out of kexec scope?
- */
- void (*machine_crash_shutdown)(struct pt_regs *regs);
+ void (*kexec_cpu_down)(int crash_shutdown, int secondary);
/* Called to do what every setup is needed on image and the
* reboot code buffer. Returns 0 on success.
@@ -247,15 +240,6 @@ struct machdep_calls {
* claims to support kexec.
*/
int (*machine_kexec_prepare)(struct kimage *image);
-
- /* Called to handle any machine specific cleanup on image */
- void (*machine_kexec_cleanup)(struct kimage *image);
-
- /* Called to perform the _real_ kexec.
- * Do NOT allocate memory or fail here. We are past the point of
- * no return.
- */
- void (*machine_kexec)(struct kimage *image);
#endif /* CONFIG_KEXEC */
#ifdef CONFIG_SUSPEND
diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h
index ff0005eec..125fc1a 100644
--- a/arch/powerpc/include/asm/reg.h
+++ b/arch/powerpc/include/asm/reg.h
@@ -283,6 +283,7 @@
#define HID0_NOPTI (1<<0) /* No-op dcbt and dcbst instr. */
#define SPRN_HID1 0x3F1 /* Hardware Implementation Register 1 */
+#ifdef CONFIG_6xx
#define HID1_EMCP (1<<31) /* 7450 Machine Check Pin Enable */
#define HID1_DFS (1<<22) /* 7447A Dynamic Frequency Scaling */
#define HID1_PC0 (1<<16) /* 7450 PLL_CFG[0] */
@@ -292,6 +293,7 @@
#define HID1_SYNCBE (1<<11) /* 7450 ABE for sync, eieio */
#define HID1_ABE (1<<10) /* 7450 Address Broadcast Enable */
#define HID1_PS (1<<16) /* 750FX PLL selection */
+#endif
#define SPRN_HID2 0x3F8 /* Hardware Implementation Register 2 */
#define SPRN_HID2_GEKKO 0x398 /* Gekko HID2 Register */
#define SPRN_IABR 0x3F2 /* Instruction Address Breakpoint Register */
diff --git a/arch/powerpc/include/asm/reg_booke.h b/arch/powerpc/include/asm/reg_booke.h
index 667a498..e68c69b 100644
--- a/arch/powerpc/include/asm/reg_booke.h
+++ b/arch/powerpc/include/asm/reg_booke.h
@@ -246,6 +246,20 @@
store or cache line push */
#endif
+/* Bit definitions for the HID1 */
+#ifdef CONFIG_E500
+/* e500v1/v2 */
+#define HID1_PLL_CFG_MASK 0xfc000000 /* PLL_CFG input pins */
+#define HID1_RFXE 0x00020000 /* Read fault exception enable */
+#define HID1_R1DPE 0x00008000 /* R1 data bus parity enable */
+#define HID1_R2DPE 0x00004000 /* R2 data bus parity enable */
+#define HID1_ASTME 0x00002000 /* Address bus streaming mode enable */
+#define HID1_ABE 0x00001000 /* Address broadcast enable */
+#define HID1_MPXTT 0x00000400 /* MPX re-map transfer type */
+#define HID1_ATS 0x00000080 /* Atomic status */
+#define HID1_MID_MASK 0x0000000f /* MID input pins */
+#endif
+
/* Bit definitions for the DBSR. */
/*
* DBSR bits which have conflicting definitions on true Book E versus IBM 40x.
diff --git a/arch/powerpc/include/asm/spu.h b/arch/powerpc/include/asm/spu.h
index 0ab8d869..0c8b35d 100644
--- a/arch/powerpc/include/asm/spu.h
+++ b/arch/powerpc/include/asm/spu.h
@@ -203,14 +203,6 @@ void spu_irq_setaffinity(struct spu *spu, int cpu);
void spu_setup_kernel_slbs(struct spu *spu, struct spu_lscsa *lscsa,
void *code, int code_size);
-#ifdef CONFIG_KEXEC
-void crash_register_spus(struct list_head *list);
-#else
-static inline void crash_register_spus(struct list_head *list)
-{
-}
-#endif
-
extern void spu_invalidate_slbs(struct spu *spu);
extern void spu_associate_mm(struct spu *spu, struct mm_struct *mm);
int spu_64k_pages_available(void);
diff --git a/arch/powerpc/kernel/cpu_setup_fsl_booke.S b/arch/powerpc/kernel/cpu_setup_fsl_booke.S
index 894e64f..5c518ad 100644
--- a/arch/powerpc/kernel/cpu_setup_fsl_booke.S
+++ b/arch/powerpc/kernel/cpu_setup_fsl_booke.S
@@ -64,6 +64,12 @@ _GLOBAL(__setup_cpu_e500v2)
bl __e500_icache_setup
bl __e500_dcache_setup
bl __setup_e500_ivors
+#ifdef CONFIG_RAPIDIO
+ /* Ensure that RFXE is set */
+ mfspr r3,SPRN_HID1
+ oris r3,r3,HID1_RFXE@h
+ mtspr SPRN_HID1,r3
+#endif
mtlr r4
blr
_GLOBAL(__setup_cpu_e500mc)
diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c
index be5ab18..8d74a24 100644
--- a/arch/powerpc/kernel/cputable.c
+++ b/arch/powerpc/kernel/cputable.c
@@ -116,7 +116,6 @@ static struct cpu_spec __initdata cpu_specs[] = {
.pmc_type = PPC_PMC_IBM,
.oprofile_cpu_type = "ppc64/power3",
.oprofile_type = PPC_OPROFILE_RS64,
- .machine_check = machine_check_generic,
.platform = "power3",
},
{ /* Power3+ */
@@ -132,7 +131,6 @@ static struct cpu_spec __initdata cpu_specs[] = {
.pmc_type = PPC_PMC_IBM,
.oprofile_cpu_type = "ppc64/power3",
.oprofile_type = PPC_OPROFILE_RS64,
- .machine_check = machine_check_generic,
.platform = "power3",
},
{ /* Northstar */
@@ -148,7 +146,6 @@ static struct cpu_spec __initdata cpu_specs[] = {
.pmc_type = PPC_PMC_IBM,
.oprofile_cpu_type = "ppc64/rs64",
.oprofile_type = PPC_OPROFILE_RS64,
- .machine_check = machine_check_generic,
.platform = "rs64",
},
{ /* Pulsar */
@@ -164,7 +161,6 @@ static struct cpu_spec __initdata cpu_specs[] = {
.pmc_type = PPC_PMC_IBM,
.oprofile_cpu_type = "ppc64/rs64",
.oprofile_type = PPC_OPROFILE_RS64,
- .machine_check = machine_check_generic,
.platform = "rs64",
},
{ /* I-star */
@@ -180,7 +176,6 @@ static struct cpu_spec __initdata cpu_specs[] = {
.pmc_type = PPC_PMC_IBM,
.oprofile_cpu_type = "ppc64/rs64",
.oprofile_type = PPC_OPROFILE_RS64,
- .machine_check = machine_check_generic,
.platform = "rs64",
},
{ /* S-star */
@@ -196,7 +191,6 @@ static struct cpu_spec __initdata cpu_specs[] = {
.pmc_type = PPC_PMC_IBM,
.oprofile_cpu_type = "ppc64/rs64",
.oprofile_type = PPC_OPROFILE_RS64,
- .machine_check = machine_check_generic,
.platform = "rs64",
},
{ /* Power4 */
@@ -212,7 +206,6 @@ static struct cpu_spec __initdata cpu_specs[] = {
.pmc_type = PPC_PMC_IBM,
.oprofile_cpu_type = "ppc64/power4",
.oprofile_type = PPC_OPROFILE_POWER4,
- .machine_check = machine_check_generic,
.platform = "power4",
},
{ /* Power4+ */
@@ -228,7 +221,6 @@ static struct cpu_spec __initdata cpu_specs[] = {
.pmc_type = PPC_PMC_IBM,
.oprofile_cpu_type = "ppc64/power4",
.oprofile_type = PPC_OPROFILE_POWER4,
- .machine_check = machine_check_generic,
.platform = "power4",
},
{ /* PPC970 */
@@ -247,7 +239,6 @@ static struct cpu_spec __initdata cpu_specs[] = {
.cpu_restore = __restore_cpu_ppc970,
.oprofile_cpu_type = "ppc64/970",
.oprofile_type = PPC_OPROFILE_POWER4,
- .machine_check = machine_check_generic,
.platform = "ppc970",
},
{ /* PPC970FX */
@@ -266,7 +257,6 @@ static struct cpu_spec __initdata cpu_specs[] = {
.cpu_restore = __restore_cpu_ppc970,
.oprofile_cpu_type = "ppc64/970",
.oprofile_type = PPC_OPROFILE_POWER4,
- .machine_check = machine_check_generic,
.platform = "ppc970",
},
{ /* PPC970MP DD1.0 - no DEEPNAP, use regular 970 init */
@@ -285,7 +275,6 @@ static struct cpu_spec __initdata cpu_specs[] = {
.cpu_restore = __restore_cpu_ppc970,
.oprofile_cpu_type = "ppc64/970MP",
.oprofile_type = PPC_OPROFILE_POWER4,
- .machine_check = machine_check_generic,
.platform = "ppc970",
},
{ /* PPC970MP */
@@ -304,7 +293,6 @@ static struct cpu_spec __initdata cpu_specs[] = {
.cpu_restore = __restore_cpu_ppc970,
.oprofile_cpu_type = "ppc64/970MP",
.oprofile_type = PPC_OPROFILE_POWER4,
- .machine_check = machine_check_generic,
.platform = "ppc970",
},
{ /* PPC970GX */
@@ -322,7 +310,6 @@ static struct cpu_spec __initdata cpu_specs[] = {
.cpu_setup = __setup_cpu_ppc970,
.oprofile_cpu_type = "ppc64/970",
.oprofile_type = PPC_OPROFILE_POWER4,
- .machine_check = machine_check_generic,
.platform = "ppc970",
},
{ /* Power5 GR */
@@ -343,7 +330,6 @@ static struct cpu_spec __initdata cpu_specs[] = {
*/
.oprofile_mmcra_sihv = MMCRA_SIHV,
.oprofile_mmcra_sipr = MMCRA_SIPR,
- .machine_check = machine_check_generic,
.platform = "power5",
},
{ /* Power5++ */
@@ -360,7 +346,6 @@ static struct cpu_spec __initdata cpu_specs[] = {
.oprofile_type = PPC_OPROFILE_POWER4,
.oprofile_mmcra_sihv = MMCRA_SIHV,
.oprofile_mmcra_sipr = MMCRA_SIPR,
- .machine_check = machine_check_generic,
.platform = "power5+",
},
{ /* Power5 GS */
@@ -378,7 +363,6 @@ static struct cpu_spec __initdata cpu_specs[] = {
.oprofile_type = PPC_OPROFILE_POWER4,
.oprofile_mmcra_sihv = MMCRA_SIHV,
.oprofile_mmcra_sipr = MMCRA_SIPR,
- .machine_check = machine_check_generic,
.platform = "power5+",
},
{ /* POWER6 in P5+ mode; 2.04-compliant processor */
@@ -390,7 +374,6 @@ static struct cpu_spec __initdata cpu_specs[] = {
.mmu_features = MMU_FTR_HPTE_TABLE,
.icache_bsize = 128,
.dcache_bsize = 128,
- .machine_check = machine_check_generic,
.oprofile_cpu_type = "ppc64/ibm-compat-v1",
.oprofile_type = PPC_OPROFILE_POWER4,
.platform = "power5+",
@@ -413,7 +396,6 @@ static struct cpu_spec __initdata cpu_specs[] = {
.oprofile_mmcra_sipr = POWER6_MMCRA_SIPR,
.oprofile_mmcra_clear = POWER6_MMCRA_THRM |
POWER6_MMCRA_OTHER,
- .machine_check = machine_check_generic,
.platform = "power6x",
},
{ /* 2.05-compliant processor, i.e. Power6 "architected" mode */
@@ -425,7 +407,6 @@ static struct cpu_spec __initdata cpu_specs[] = {
.mmu_features = MMU_FTR_HPTE_TABLE,
.icache_bsize = 128,
.dcache_bsize = 128,
- .machine_check = machine_check_generic,
.oprofile_cpu_type = "ppc64/ibm-compat-v1",
.oprofile_type = PPC_OPROFILE_POWER4,
.platform = "power6",
@@ -440,7 +421,6 @@ static struct cpu_spec __initdata cpu_specs[] = {
MMU_FTR_TLBIE_206,
.icache_bsize = 128,
.dcache_bsize = 128,
- .machine_check = machine_check_generic,
.oprofile_type = PPC_OPROFILE_POWER4,
.oprofile_cpu_type = "ppc64/ibm-compat-v1",
.platform = "power7",
@@ -492,7 +472,6 @@ static struct cpu_spec __initdata cpu_specs[] = {
.pmc_type = PPC_PMC_IBM,
.oprofile_cpu_type = "ppc64/cell-be",
.oprofile_type = PPC_OPROFILE_CELL,
- .machine_check = machine_check_generic,
.platform = "ppc-cell-be",
},
{ /* PA Semi PA6T */
@@ -510,7 +489,6 @@ static struct cpu_spec __initdata cpu_specs[] = {
.cpu_restore = __restore_cpu_pa6t,
.oprofile_cpu_type = "ppc64/pa6t",
.oprofile_type = PPC_OPROFILE_PA6T,
- .machine_check = machine_check_generic,
.platform = "pa6t",
},
{ /* default match */
@@ -524,7 +502,6 @@ static struct cpu_spec __initdata cpu_specs[] = {
.dcache_bsize = 128,
.num_pmcs = 6,
.pmc_type = PPC_PMC_IBM,
- .machine_check = machine_check_generic,
.platform = "power4",
}
#endif /* CONFIG_PPC_BOOK3S_64 */
diff --git a/arch/powerpc/kernel/crash.c b/arch/powerpc/kernel/crash.c
index 832c8c4..3d569e2 100644
--- a/arch/powerpc/kernel/crash.c
+++ b/arch/powerpc/kernel/crash.c
@@ -48,7 +48,7 @@ int crashing_cpu = -1;
static cpumask_t cpus_in_crash = CPU_MASK_NONE;
cpumask_t cpus_in_sr = CPU_MASK_NONE;
-#define CRASH_HANDLER_MAX 2
+#define CRASH_HANDLER_MAX 3
/* NULL terminated list of shutdown handles */
static crash_shutdown_t crash_shutdown_handles[CRASH_HANDLER_MAX+1];
static DEFINE_SPINLOCK(crash_handlers_lock);
@@ -125,7 +125,7 @@ static void crash_kexec_prepare_cpus(int cpu)
smp_wmb();
/*
- * FIXME: Until we will have the way to stop other CPUSs reliabally,
+ * FIXME: Until we will have the way to stop other CPUs reliably,
* the crash CPU will send an IPI and wait for other CPUs to
* respond.
* Delay of at least 10 seconds.
@@ -254,72 +254,6 @@ void crash_kexec_secondary(struct pt_regs *regs)
cpus_in_sr = CPU_MASK_NONE;
}
#endif
-#ifdef CONFIG_SPU_BASE
-
-#include <asm/spu.h>
-#include <asm/spu_priv1.h>
-
-struct crash_spu_info {
- struct spu *spu;
- u32 saved_spu_runcntl_RW;
- u32 saved_spu_status_R;
- u32 saved_spu_npc_RW;
- u64 saved_mfc_sr1_RW;
- u64 saved_mfc_dar;
- u64 saved_mfc_dsisr;
-};
-
-#define CRASH_NUM_SPUS 16 /* Enough for current hardware */
-static struct crash_spu_info crash_spu_info[CRASH_NUM_SPUS];
-
-static void crash_kexec_stop_spus(void)
-{
- struct spu *spu;
- int i;
- u64 tmp;
-
- for (i = 0; i < CRASH_NUM_SPUS; i++) {
- if (!crash_spu_info[i].spu)
- continue;
-
- spu = crash_spu_info[i].spu;
-
- crash_spu_info[i].saved_spu_runcntl_RW =
- in_be32(&spu->problem->spu_runcntl_RW);
- crash_spu_info[i].saved_spu_status_R =
- in_be32(&spu->problem->spu_status_R);
- crash_spu_info[i].saved_spu_npc_RW =
- in_be32(&spu->problem->spu_npc_RW);
-
- crash_spu_info[i].saved_mfc_dar = spu_mfc_dar_get(spu);
- crash_spu_info[i].saved_mfc_dsisr = spu_mfc_dsisr_get(spu);
- tmp = spu_mfc_sr1_get(spu);
- crash_spu_info[i].saved_mfc_sr1_RW = tmp;
-
- tmp &= ~MFC_STATE1_MASTER_RUN_CONTROL_MASK;
- spu_mfc_sr1_set(spu, tmp);
-
- __delay(200);
- }
-}
-
-void crash_register_spus(struct list_head *list)
-{
- struct spu *spu;
-
- list_for_each_entry(spu, list, full_list) {
- if (WARN_ON(spu->number >= CRASH_NUM_SPUS))
- continue;
-
- crash_spu_info[spu->number].spu = spu;
- }
-}
-
-#else
-static inline void crash_kexec_stop_spus(void)
-{
-}
-#endif /* CONFIG_SPU_BASE */
/*
* Register a function to be called on shutdown. Only use this if you
@@ -439,8 +373,6 @@ void default_machine_crash_shutdown(struct pt_regs *regs)
crash_shutdown_cpu = -1;
__debugger_fault_handler = old_handler;
- crash_kexec_stop_spus();
-
if (ppc_md.kexec_cpu_down)
ppc_md.kexec_cpu_down(1, 0);
}
diff --git a/arch/powerpc/kernel/entry_32.S b/arch/powerpc/kernel/entry_32.S
index c22dc1e..56212bc 100644
--- a/arch/powerpc/kernel/entry_32.S
+++ b/arch/powerpc/kernel/entry_32.S
@@ -880,7 +880,18 @@ END_MMU_FTR_SECTION_IFSET(MMU_FTR_TYPE_47x)
*/
andi. r10,r9,MSR_EE
beq 1f
+ /*
+ * Since the ftrace irqsoff latency trace checks CALLER_ADDR1,
+ * which is the stack frame here, we need to force a stack frame
+ * in case we came from user space.
+ */
+ stwu r1,-32(r1)
+ mflr r0
+ stw r0,4(r1)
+ stwu r1,-32(r1)
bl trace_hardirqs_on
+ lwz r1,0(r1)
+ lwz r1,0(r1)
lwz r9,_MSR(r1)
1:
#endif /* CONFIG_TRACE_IRQFLAGS */
diff --git a/arch/powerpc/kernel/machine_kexec.c b/arch/powerpc/kernel/machine_kexec.c
index df7e20c..49a170a 100644
--- a/arch/powerpc/kernel/machine_kexec.c
+++ b/arch/powerpc/kernel/machine_kexec.c
@@ -15,6 +15,7 @@
#include <linux/memblock.h>
#include <linux/of.h>
#include <linux/irq.h>
+#include <linux/ftrace.h>
#include <asm/machdep.h>
#include <asm/prom.h>
@@ -44,10 +45,7 @@ void machine_kexec_mask_interrupts(void) {
void machine_crash_shutdown(struct pt_regs *regs)
{
- if (ppc_md.machine_crash_shutdown)
- ppc_md.machine_crash_shutdown(regs);
- else
- default_machine_crash_shutdown(regs);
+ default_machine_crash_shutdown(regs);
}
/*
@@ -65,8 +63,6 @@ int machine_kexec_prepare(struct kimage *image)
void machine_kexec_cleanup(struct kimage *image)
{
- if (ppc_md.machine_kexec_cleanup)
- ppc_md.machine_kexec_cleanup(image);
}
void arch_crash_save_vmcoreinfo(void)
@@ -87,10 +83,13 @@ void arch_crash_save_vmcoreinfo(void)
*/
void machine_kexec(struct kimage *image)
{
- if (ppc_md.machine_kexec)
- ppc_md.machine_kexec(image);
- else
- default_machine_kexec(image);
+ int save_ftrace_enabled;
+
+ save_ftrace_enabled = __ftrace_enabled_save();
+
+ default_machine_kexec(image);
+
+ __ftrace_enabled_restore(save_ftrace_enabled);
/* Fall back to normal restart if we're still alive. */
machine_restart(NULL);
diff --git a/arch/powerpc/kernel/perf_event.c b/arch/powerpc/kernel/perf_event.c
index 5674807..ab6f6be 100644
--- a/arch/powerpc/kernel/perf_event.c
+++ b/arch/powerpc/kernel/perf_event.c
@@ -1212,6 +1212,7 @@ static void record_and_restart(struct perf_event *event, unsigned long val,
if (left <= 0)
left = period;
record = 1;
+ event->hw.last_period = event->hw.sample_period;
}
if (left < 0x80000000LL)
val = 0x80000000LL - left;
diff --git a/arch/powerpc/kernel/perf_event_fsl_emb.c b/arch/powerpc/kernel/perf_event_fsl_emb.c
index 4dcf5f8..b0dc8f7 100644
--- a/arch/powerpc/kernel/perf_event_fsl_emb.c
+++ b/arch/powerpc/kernel/perf_event_fsl_emb.c
@@ -596,6 +596,7 @@ static void record_and_restart(struct perf_event *event, unsigned long val,
if (left <= 0)
left = period;
record = 1;
+ event->hw.last_period = event->hw.sample_period;
}
if (left < 0x80000000LL)
val = 0x80000000LL - left;
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
index 84906d3..7a1d5cb 100644
--- a/arch/powerpc/kernel/process.c
+++ b/arch/powerpc/kernel/process.c
@@ -631,7 +631,7 @@ void show_regs(struct pt_regs * regs)
#ifdef CONFIG_PPC_ADV_DEBUG_REGS
printk("DEAR: "REG", ESR: "REG"\n", regs->dar, regs->dsisr);
#else
- printk("DAR: "REG", DSISR: "REG"\n", regs->dar, regs->dsisr);
+ printk("DAR: "REG", DSISR: %08lx\n", regs->dar, regs->dsisr);
#endif
printk("TASK = %p[%d] '%s' THREAD: %p",
current, task_pid_nr(current), current->comm, task_thread_info(current));
diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c
index 9e3132d..7185f0d 100644
--- a/arch/powerpc/kernel/prom.c
+++ b/arch/powerpc/kernel/prom.c
@@ -519,9 +519,9 @@ void __init early_init_dt_add_memory_arch(u64 base, u64 size)
memblock_add(base, size);
}
-u64 __init early_init_dt_alloc_memory_arch(u64 size, u64 align)
+void * __init early_init_dt_alloc_memory_arch(u64 size, u64 align)
{
- return memblock_alloc(size, align);
+ return __va(memblock_alloc(size, align));
}
#ifdef CONFIG_BLK_DEV_INITRD
diff --git a/arch/powerpc/kernel/rtas_flash.c b/arch/powerpc/kernel/rtas_flash.c
index 2b442e6..bf5f5ce 100644
--- a/arch/powerpc/kernel/rtas_flash.c
+++ b/arch/powerpc/kernel/rtas_flash.c
@@ -256,31 +256,16 @@ static ssize_t rtas_flash_read(struct file *file, char __user *buf,
struct proc_dir_entry *dp = PDE(file->f_path.dentry->d_inode);
struct rtas_update_flash_t *uf;
char msg[RTAS_MSG_MAXLEN];
- int msglen;
- uf = (struct rtas_update_flash_t *) dp->data;
+ uf = dp->data;
if (!strcmp(dp->name, FIRMWARE_FLASH_NAME)) {
get_flash_status_msg(uf->status, msg);
} else { /* FIRMWARE_UPDATE_NAME */
sprintf(msg, "%d\n", uf->status);
}
- msglen = strlen(msg);
- if (msglen > count)
- msglen = count;
-
- if (ppos && *ppos != 0)
- return 0; /* be cheap */
-
- if (!access_ok(VERIFY_WRITE, buf, msglen))
- return -EINVAL;
- if (copy_to_user(buf, msg, msglen))
- return -EFAULT;
-
- if (ppos)
- *ppos = msglen;
- return msglen;
+ return simple_read_from_buffer(buf, count, ppos, msg, strlen(msg));
}
/* constructor for flash_block_cache */
@@ -394,26 +379,13 @@ static ssize_t manage_flash_read(struct file *file, char __user *buf,
char msg[RTAS_MSG_MAXLEN];
int msglen;
- args_buf = (struct rtas_manage_flash_t *) dp->data;
+ args_buf = dp->data;
if (args_buf == NULL)
return 0;
msglen = sprintf(msg, "%d\n", args_buf->status);
- if (msglen > count)
- msglen = count;
- if (ppos && *ppos != 0)
- return 0; /* be cheap */
-
- if (!access_ok(VERIFY_WRITE, buf, msglen))
- return -EINVAL;
-
- if (copy_to_user(buf, msg, msglen))
- return -EFAULT;
-
- if (ppos)
- *ppos = msglen;
- return msglen;
+ return simple_read_from_buffer(buf, count, ppos, msg, msglen);
}
static ssize_t manage_flash_write(struct file *file, const char __user *buf,
@@ -495,24 +467,11 @@ static ssize_t validate_flash_read(struct file *file, char __user *buf,
char msg[RTAS_MSG_MAXLEN];
int msglen;
- args_buf = (struct rtas_validate_flash_t *) dp->data;
+ args_buf = dp->data;
- if (ppos && *ppos != 0)
- return 0; /* be cheap */
-
msglen = get_validate_flash_msg(args_buf, msg);
- if (msglen > count)
- msglen = count;
-
- if (!access_ok(VERIFY_WRITE, buf, msglen))
- return -EINVAL;
-
- if (copy_to_user(buf, msg, msglen))
- return -EFAULT;
- if (ppos)
- *ppos = msglen;
- return msglen;
+ return simple_read_from_buffer(buf, count, ppos, msg, msglen);
}
static ssize_t validate_flash_write(struct file *file, const char __user *buf,
diff --git a/arch/powerpc/kernel/rtasd.c b/arch/powerpc/kernel/rtasd.c
index 0438f81..049dbec 100644
--- a/arch/powerpc/kernel/rtasd.c
+++ b/arch/powerpc/kernel/rtasd.c
@@ -160,7 +160,7 @@ static int log_rtas_len(char * buf)
/* rtas fixed header */
len = 8;
err = (struct rtas_error_log *)buf;
- if (err->extended_log_length) {
+ if (err->extended && err->extended_log_length) {
/* extended header */
len += err->extended_log_length;
diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c
index 09e4dea..09d31db 100644
--- a/arch/powerpc/kernel/time.c
+++ b/arch/powerpc/kernel/time.c
@@ -265,11 +265,26 @@ void accumulate_stolen_time(void)
{
u64 sst, ust;
- sst = scan_dispatch_log(get_paca()->starttime_user);
- ust = scan_dispatch_log(get_paca()->starttime);
- get_paca()->system_time -= sst;
- get_paca()->user_time -= ust;
- get_paca()->stolen_time += ust + sst;
+ u8 save_soft_enabled = local_paca->soft_enabled;
+ u8 save_hard_enabled = local_paca->hard_enabled;
+
+ /* We are called early in the exception entry, before
+ * soft/hard_enabled are sync'ed to the expected state
+ * for the exception. We are hard disabled but the PACA
+ * needs to reflect that so various debug stuff doesn't
+ * complain
+ */
+ local_paca->soft_enabled = 0;
+ local_paca->hard_enabled = 0;
+
+ sst = scan_dispatch_log(local_paca->starttime_user);
+ ust = scan_dispatch_log(local_paca->starttime);
+ local_paca->system_time -= sst;
+ local_paca->user_time -= ust;
+ local_paca->stolen_time += ust + sst;
+
+ local_paca->soft_enabled = save_soft_enabled;
+ local_paca->hard_enabled = save_hard_enabled;
}
static inline u64 calculate_stolen_time(u64 stop_tb)
diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c
index 1b2cdc8..bd74fac 100644
--- a/arch/powerpc/kernel/traps.c
+++ b/arch/powerpc/kernel/traps.c
@@ -626,12 +626,6 @@ void machine_check_exception(struct pt_regs *regs)
if (recover > 0)
return;
- if (user_mode(regs)) {
- regs->msr |= MSR_RI;
- _exception(SIGBUS, regs, BUS_ADRERR, regs->nip);
- return;
- }
-
#if defined(CONFIG_8xx) && defined(CONFIG_PCI)
/* the qspan pci read routines can cause machine checks -- Cort
*
@@ -643,16 +637,12 @@ void machine_check_exception(struct pt_regs *regs)
return;
#endif
- if (debugger_fault_handler(regs)) {
- regs->msr |= MSR_RI;
+ if (debugger_fault_handler(regs))
return;
- }
if (check_io_access(regs))
return;
- if (debugger_fault_handler(regs))
- return;
die("Machine check", regs, SIGBUS);
/* Must die if the interrupt is not recoverable */
diff --git a/arch/powerpc/lib/feature-fixups-test.S b/arch/powerpc/lib/feature-fixups-test.S
index cb73748..f461311 100644
--- a/arch/powerpc/lib/feature-fixups-test.S
+++ b/arch/powerpc/lib/feature-fixups-test.S
@@ -172,6 +172,25 @@ globl(ftr_fixup_test6_expected)
3: or 3,3,3
+#if 0
+/* Test that if we have a larger else case the assembler spots it and
+ * reports an error. #if 0'ed so as not to break the build normally.
+ */
+ftr_fixup_test7:
+ or 1,1,1
+BEGIN_FTR_SECTION
+ or 2,2,2
+ or 2,2,2
+ or 2,2,2
+FTR_SECTION_ELSE
+ or 3,3,3
+ or 3,3,3
+ or 3,3,3
+ or 3,3,3
+ALT_FTR_SECTION_END(0, 1)
+ or 1,1,1
+#endif
+
#define MAKE_MACRO_TEST(TYPE) \
globl(ftr_fixup_test_ ##TYPE##_macros) \
or 1,1,1; \
diff --git a/arch/powerpc/platforms/83xx/mpc830x_rdb.c b/arch/powerpc/platforms/83xx/mpc830x_rdb.c
index 661d354..d0c4e15 100644
--- a/arch/powerpc/platforms/83xx/mpc830x_rdb.c
+++ b/arch/powerpc/platforms/83xx/mpc830x_rdb.c
@@ -57,12 +57,12 @@ static void __init mpc830x_rdb_init_IRQ(void)
ipic_set_default_priority();
}
-struct const char *board[] __initdata = {
+static const char *board[] __initdata = {
"MPC8308RDB",
"fsl,mpc8308rdb",
"denx,mpc8308_p1m",
NULL
-}
+};
/*
* Called very early, MMU is off, device-tree isn't unflattened
diff --git a/arch/powerpc/platforms/83xx/mpc831x_rdb.c b/arch/powerpc/platforms/83xx/mpc831x_rdb.c
index b54cd73..f859ead 100644
--- a/arch/powerpc/platforms/83xx/mpc831x_rdb.c
+++ b/arch/powerpc/platforms/83xx/mpc831x_rdb.c
@@ -60,11 +60,11 @@ static void __init mpc831x_rdb_init_IRQ(void)
ipic_set_default_priority();
}
-struct const char *board[] __initdata = {
+static const char *board[] __initdata = {
"MPC8313ERDB",
"fsl,mpc8315erdb",
NULL
-}
+};
/*
* Called very early, MMU is off, device-tree isn't unflattened
diff --git a/arch/powerpc/platforms/83xx/mpc83xx.h b/arch/powerpc/platforms/83xx/mpc83xx.h
index 0fea881..82a4345 100644
--- a/arch/powerpc/platforms/83xx/mpc83xx.h
+++ b/arch/powerpc/platforms/83xx/mpc83xx.h
@@ -35,6 +35,8 @@
/* system i/o configuration register high */
#define MPC83XX_SICRH_OFFS 0x118
+#define MPC8308_SICRH_USB_MASK 0x000c0000
+#define MPC8308_SICRH_USB_ULPI 0x00040000
#define MPC834X_SICRH_USB_UTMI 0x00020000
#define MPC831X_SICRH_USB_MASK 0x000000e0
#define MPC831X_SICRH_USB_ULPI 0x000000a0
diff --git a/arch/powerpc/platforms/83xx/usb.c b/arch/powerpc/platforms/83xx/usb.c
index 3ba4bb7..2c64164 100644
--- a/arch/powerpc/platforms/83xx/usb.c
+++ b/arch/powerpc/platforms/83xx/usb.c
@@ -127,7 +127,8 @@ int mpc831x_usb_cfg(void)
/* Configure clock */
immr_node = of_get_parent(np);
- if (immr_node && of_device_is_compatible(immr_node, "fsl,mpc8315-immr"))
+ if (immr_node && (of_device_is_compatible(immr_node, "fsl,mpc8315-immr") ||
+ of_device_is_compatible(immr_node, "fsl,mpc8308-immr")))
clrsetbits_be32(immap + MPC83XX_SCCR_OFFS,
MPC8315_SCCR_USB_MASK,
MPC8315_SCCR_USB_DRCM_01);
@@ -138,7 +139,11 @@ int mpc831x_usb_cfg(void)
/* Configure pin mux for ULPI. There is no pin mux for UTMI */
if (prop && !strcmp(prop, "ulpi")) {
- if (of_device_is_compatible(immr_node, "fsl,mpc8315-immr")) {
+ if (of_device_is_compatible(immr_node, "fsl,mpc8308-immr")) {
+ clrsetbits_be32(immap + MPC83XX_SICRH_OFFS,
+ MPC8308_SICRH_USB_MASK,
+ MPC8308_SICRH_USB_ULPI);
+ } else if (of_device_is_compatible(immr_node, "fsl,mpc8315-immr")) {
clrsetbits_be32(immap + MPC83XX_SICRL_OFFS,
MPC8315_SICRL_USB_MASK,
MPC8315_SICRL_USB_ULPI);
@@ -173,6 +178,9 @@ int mpc831x_usb_cfg(void)
!strcmp(prop, "utmi"))) {
u32 refsel;
+ if (of_device_is_compatible(immr_node, "fsl,mpc8308-immr"))
+ goto out;
+
if (of_device_is_compatible(immr_node, "fsl,mpc8315-immr"))
refsel = CONTROL_REFSEL_24MHZ;
else
@@ -186,9 +194,11 @@ int mpc831x_usb_cfg(void)
temp = CONTROL_PHY_CLK_SEL_ULPI;
#ifdef CONFIG_USB_OTG
/* Set OTG_PORT */
- dr_mode = of_get_property(np, "dr_mode", NULL);
- if (dr_mode && !strcmp(dr_mode, "otg"))
- temp |= CONTROL_OTG_PORT;
+ if (!of_device_is_compatible(immr_node, "fsl,mpc8308-immr")) {
+ dr_mode = of_get_property(np, "dr_mode", NULL);
+ if (dr_mode && !strcmp(dr_mode, "otg"))
+ temp |= CONTROL_OTG_PORT;
+ }
#endif /* CONFIG_USB_OTG */
out_be32(usb_regs + FSL_USB2_CONTROL_OFFS, temp);
} else {
@@ -196,6 +206,7 @@ int mpc831x_usb_cfg(void)
ret = -EINVAL;
}
+out:
iounmap(usb_regs);
of_node_put(np);
return ret;
diff --git a/arch/powerpc/platforms/cell/cpufreq_spudemand.c b/arch/powerpc/platforms/cell/cpufreq_spudemand.c
index 968c1c0..d809836 100644
--- a/arch/powerpc/platforms/cell/cpufreq_spudemand.c
+++ b/arch/powerpc/platforms/cell/cpufreq_spudemand.c
@@ -39,8 +39,6 @@ struct spu_gov_info_struct {
};
static DEFINE_PER_CPU(struct spu_gov_info_struct, spu_gov_info);
-static struct workqueue_struct *kspugov_wq;
-
static int calc_freq(struct spu_gov_info_struct *info)
{
int cpu;
@@ -71,14 +69,14 @@ static void spu_gov_work(struct work_struct *work)
__cpufreq_driver_target(info->policy, target_freq, CPUFREQ_RELATION_H);
delay = usecs_to_jiffies(info->poll_int);
- queue_delayed_work_on(info->policy->cpu, kspugov_wq, &info->work, delay);
+ schedule_delayed_work_on(info->policy->cpu, &info->work, delay);
}
static void spu_gov_init_work(struct spu_gov_info_struct *info)
{
int delay = usecs_to_jiffies(info->poll_int);
INIT_DELAYED_WORK_DEFERRABLE(&info->work, spu_gov_work);
- queue_delayed_work_on(info->policy->cpu, kspugov_wq, &info->work, delay);
+ schedule_delayed_work_on(info->policy->cpu, &info->work, delay);
}
static void spu_gov_cancel_work(struct spu_gov_info_struct *info)
@@ -152,27 +150,15 @@ static int __init spu_gov_init(void)
{
int ret;
- kspugov_wq = create_workqueue("kspugov");
- if (!kspugov_wq) {
- printk(KERN_ERR "creation of kspugov failed\n");
- ret = -EFAULT;
- goto out;
- }
-
ret = cpufreq_register_governor(&spu_governor);
- if (ret) {
+ if (ret)
printk(KERN_ERR "registration of governor failed\n");
- destroy_workqueue(kspugov_wq);
- goto out;
- }
-out:
return ret;
}
static void __exit spu_gov_exit(void)
{
cpufreq_unregister_governor(&spu_governor);
- destroy_workqueue(kspugov_wq);
}
diff --git a/arch/powerpc/platforms/cell/qpace_setup.c b/arch/powerpc/platforms/cell/qpace_setup.c
index 1b57490..d31c594 100644
--- a/arch/powerpc/platforms/cell/qpace_setup.c
+++ b/arch/powerpc/platforms/cell/qpace_setup.c
@@ -145,9 +145,4 @@ define_machine(qpace) {
.calibrate_decr = generic_calibrate_decr,
.progress = qpace_progress,
.init_IRQ = iic_init_IRQ,
-#ifdef CONFIG_KEXEC
- .machine_kexec = default_machine_kexec,
- .machine_kexec_prepare = default_machine_kexec_prepare,
- .machine_crash_shutdown = default_machine_crash_shutdown,
-#endif
};
diff --git a/arch/powerpc/platforms/cell/spu_base.c b/arch/powerpc/platforms/cell/spu_base.c
index 8547e86..acfacce 100644
--- a/arch/powerpc/platforms/cell/spu_base.c
+++ b/arch/powerpc/platforms/cell/spu_base.c
@@ -37,6 +37,7 @@
#include <asm/spu_csa.h>
#include <asm/xmon.h>
#include <asm/prom.h>
+#include <asm/kexec.h>
const struct spu_management_ops *spu_management_ops;
EXPORT_SYMBOL_GPL(spu_management_ops);
@@ -727,6 +728,75 @@ static ssize_t spu_stat_show(struct sys_device *sysdev,
static SYSDEV_ATTR(stat, 0644, spu_stat_show, NULL);
+#ifdef CONFIG_KEXEC
+
+struct crash_spu_info {
+ struct spu *spu;
+ u32 saved_spu_runcntl_RW;
+ u32 saved_spu_status_R;
+ u32 saved_spu_npc_RW;
+ u64 saved_mfc_sr1_RW;
+ u64 saved_mfc_dar;
+ u64 saved_mfc_dsisr;
+};
+
+#define CRASH_NUM_SPUS 16 /* Enough for current hardware */
+static struct crash_spu_info crash_spu_info[CRASH_NUM_SPUS];
+
+static void crash_kexec_stop_spus(void)
+{
+ struct spu *spu;
+ int i;
+ u64 tmp;
+
+ for (i = 0; i < CRASH_NUM_SPUS; i++) {
+ if (!crash_spu_info[i].spu)
+ continue;
+
+ spu = crash_spu_info[i].spu;
+
+ crash_spu_info[i].saved_spu_runcntl_RW =
+ in_be32(&spu->problem->spu_runcntl_RW);
+ crash_spu_info[i].saved_spu_status_R =
+ in_be32(&spu->problem->spu_status_R);
+ crash_spu_info[i].saved_spu_npc_RW =
+ in_be32(&spu->problem->spu_npc_RW);
+
+ crash_spu_info[i].saved_mfc_dar = spu_mfc_dar_get(spu);
+ crash_spu_info[i].saved_mfc_dsisr = spu_mfc_dsisr_get(spu);
+ tmp = spu_mfc_sr1_get(spu);
+ crash_spu_info[i].saved_mfc_sr1_RW = tmp;
+
+ tmp &= ~MFC_STATE1_MASTER_RUN_CONTROL_MASK;
+ spu_mfc_sr1_set(spu, tmp);
+
+ __delay(200);
+ }
+}
+
+static void crash_register_spus(struct list_head *list)
+{
+ struct spu *spu;
+ int ret;
+
+ list_for_each_entry(spu, list, full_list) {
+ if (WARN_ON(spu->number >= CRASH_NUM_SPUS))
+ continue;
+
+ crash_spu_info[spu->number].spu = spu;
+ }
+
+ ret = crash_shutdown_register(&crash_kexec_stop_spus);
+ if (ret)
+ printk(KERN_ERR "Could not register SPU crash handler");
+}
+
+#else
+static inline void crash_register_spus(struct list_head *list)
+{
+}
+#endif
+
static int __init init_spu_base(void)
{
int i, ret = 0;
diff --git a/arch/powerpc/platforms/cell/spufs/file.c b/arch/powerpc/platforms/cell/spufs/file.c
index 02f7b11..3c7c3f8 100644
--- a/arch/powerpc/platforms/cell/spufs/file.c
+++ b/arch/powerpc/platforms/cell/spufs/file.c
@@ -219,24 +219,17 @@ spufs_mem_write(struct file *file, const char __user *buffer,
loff_t pos = *ppos;
int ret;
- if (pos < 0)
- return -EINVAL;
if (pos > LS_SIZE)
return -EFBIG;
- if (size > LS_SIZE - pos)
- size = LS_SIZE - pos;
ret = spu_acquire(ctx);
if (ret)
return ret;
local_store = ctx->ops->get_ls(ctx);
- ret = copy_from_user(local_store + pos, buffer, size);
+ size = simple_write_to_buffer(local_store, LS_SIZE, ppos, buffer, size);
spu_release(ctx);
- if (ret)
- return -EFAULT;
- *ppos = pos + size;
return size;
}
@@ -574,18 +567,15 @@ spufs_regs_write(struct file *file, const char __user *buffer,
if (*pos >= sizeof(lscsa->gprs))
return -EFBIG;
- size = min_t(ssize_t, sizeof(lscsa->gprs) - *pos, size);
- *pos += size;
-
ret = spu_acquire_saved(ctx);
if (ret)
return ret;
- ret = copy_from_user((char *)lscsa->gprs + *pos - size,
- buffer, size) ? -EFAULT : size;
+ size = simple_write_to_buffer(lscsa->gprs, sizeof(lscsa->gprs), pos,
+ buffer, size);
spu_release_saved(ctx);
- return ret;
+ return size;
}
static const struct file_operations spufs_regs_fops = {
@@ -630,18 +620,15 @@ spufs_fpcr_write(struct file *file, const char __user * buffer,
if (*pos >= sizeof(lscsa->fpcr))
return -EFBIG;
- size = min_t(ssize_t, sizeof(lscsa->fpcr) - *pos, size);
-
ret = spu_acquire_saved(ctx);
if (ret)
return ret;
- *pos += size;
- ret = copy_from_user((char *)&lscsa->fpcr + *pos - size,
- buffer, size) ? -EFAULT : size;
+ size = simple_write_to_buffer(&lscsa->fpcr, sizeof(lscsa->fpcr), pos,
+ buffer, size);
spu_release_saved(ctx);
- return ret;
+ return size;
}
static const struct file_operations spufs_fpcr_fops = {
diff --git a/arch/powerpc/platforms/embedded6xx/gamecube.c b/arch/powerpc/platforms/embedded6xx/gamecube.c
index 1106fd9..a138e14 100644
--- a/arch/powerpc/platforms/embedded6xx/gamecube.c
+++ b/arch/powerpc/platforms/embedded6xx/gamecube.c
@@ -75,14 +75,6 @@ static void gamecube_shutdown(void)
flipper_quiesce();
}
-#ifdef CONFIG_KEXEC
-static int gamecube_kexec_prepare(struct kimage *image)
-{
- return 0;
-}
-#endif /* CONFIG_KEXEC */
-
-
define_machine(gamecube) {
.name = "gamecube",
.probe = gamecube_probe,
@@ -95,9 +87,6 @@ define_machine(gamecube) {
.calibrate_decr = generic_calibrate_decr,
.progress = udbg_progress,
.machine_shutdown = gamecube_shutdown,
-#ifdef CONFIG_KEXEC
- .machine_kexec_prepare = gamecube_kexec_prepare,
-#endif
};
diff --git a/arch/powerpc/platforms/embedded6xx/wii.c b/arch/powerpc/platforms/embedded6xx/wii.c
index 649473a..1b5dc1a 100644
--- a/arch/powerpc/platforms/embedded6xx/wii.c
+++ b/arch/powerpc/platforms/embedded6xx/wii.c
@@ -18,7 +18,6 @@
#include <linux/init.h>
#include <linux/irq.h>
#include <linux/seq_file.h>
-#include <linux/kexec.h>
#include <linux/of_platform.h>
#include <linux/memblock.h>
#include <mm/mmu_decl.h>
@@ -226,13 +225,6 @@ static void wii_shutdown(void)
flipper_quiesce();
}
-#ifdef CONFIG_KEXEC
-static int wii_machine_kexec_prepare(struct kimage *image)
-{
- return 0;
-}
-#endif /* CONFIG_KEXEC */
-
define_machine(wii) {
.name = "wii",
.probe = wii_probe,
@@ -246,9 +238,6 @@ define_machine(wii) {
.calibrate_decr = generic_calibrate_decr,
.progress = udbg_progress,
.machine_shutdown = wii_shutdown,
-#ifdef CONFIG_KEXEC
- .machine_kexec_prepare = wii_machine_kexec_prepare,
-#endif
};
static struct of_device_id wii_of_bus[] = {
diff --git a/arch/powerpc/platforms/iseries/Kconfig b/arch/powerpc/platforms/iseries/Kconfig
index 47a20cf..e5bc9f7 100644
--- a/arch/powerpc/platforms/iseries/Kconfig
+++ b/arch/powerpc/platforms/iseries/Kconfig
@@ -2,7 +2,7 @@ config PPC_ISERIES
bool "IBM Legacy iSeries"
depends on PPC64 && PPC_BOOK3S
select PPC_INDIRECT_IO
- select PPC_PCI_CHOICE if EMBEDDED
+ select PPC_PCI_CHOICE if EXPERT
menu "iSeries device drivers"
depends on PPC_ISERIES
diff --git a/arch/powerpc/platforms/pseries/Kconfig b/arch/powerpc/platforms/pseries/Kconfig
index 5d1b743..5b3da4b 100644
--- a/arch/powerpc/platforms/pseries/Kconfig
+++ b/arch/powerpc/platforms/pseries/Kconfig
@@ -10,7 +10,7 @@ config PPC_PSERIES
select RTAS_ERROR_LOGGING
select PPC_UDBG_16550
select PPC_NATIVE
- select PPC_PCI_CHOICE if EMBEDDED
+ select PPC_PCI_CHOICE if EXPERT
default y
config PPC_SPLPAR
@@ -24,9 +24,9 @@ config PPC_SPLPAR
two or more partitions.
config EEH
- bool "PCI Extended Error Handling (EEH)" if EMBEDDED
+ bool "PCI Extended Error Handling (EEH)" if EXPERT
depends on PPC_PSERIES && PCI
- default y if !EMBEDDED
+ default y if !EXPERT
config PSERIES_MSI
bool
diff --git a/arch/powerpc/platforms/pseries/kexec.c b/arch/powerpc/platforms/pseries/kexec.c
index 53cbd53..77d38a5 100644
--- a/arch/powerpc/platforms/pseries/kexec.c
+++ b/arch/powerpc/platforms/pseries/kexec.c
@@ -61,13 +61,3 @@ void __init setup_kexec_cpu_down_xics(void)
{
ppc_md.kexec_cpu_down = pseries_kexec_cpu_down_xics;
}
-
-static int __init pseries_kexec_setup(void)
-{
- ppc_md.machine_kexec = default_machine_kexec;
- ppc_md.machine_kexec_prepare = default_machine_kexec_prepare;
- ppc_md.machine_crash_shutdown = default_machine_crash_shutdown;
-
- return 0;
-}
-machine_device_initcall(pseries, pseries_kexec_setup);
diff --git a/arch/powerpc/platforms/pseries/ras.c b/arch/powerpc/platforms/pseries/ras.c
index a4fc6da..c55d7ad 100644
--- a/arch/powerpc/platforms/pseries/ras.c
+++ b/arch/powerpc/platforms/pseries/ras.c
@@ -54,7 +54,8 @@
static unsigned char ras_log_buf[RTAS_ERROR_LOG_MAX];
static DEFINE_SPINLOCK(ras_log_buf_lock);
-static char mce_data_buf[RTAS_ERROR_LOG_MAX];
+static char global_mce_data_buf[RTAS_ERROR_LOG_MAX];
+static DEFINE_PER_CPU(__u64, mce_data_buf);
static int ras_get_sensor_state_token;
static int ras_check_exception_token;
@@ -196,12 +197,24 @@ static irqreturn_t ras_error_interrupt(int irq, void *dev_id)
return IRQ_HANDLED;
}
-/* Get the error information for errors coming through the
+/*
+ * Some versions of FWNMI place the buffer inside the 4kB page starting at
+ * 0x7000. Other versions place it inside the rtas buffer. We check both.
+ */
+#define VALID_FWNMI_BUFFER(A) \
+ ((((A) >= 0x7000) && ((A) < 0x7ff0)) || \
+ (((A) >= rtas.base) && ((A) < (rtas.base + rtas.size - 16))))
+
+/*
+ * Get the error information for errors coming through the
* FWNMI vectors. The pt_regs' r3 will be updated to reflect
* the actual r3 if possible, and a ptr to the error log entry
* will be returned if found.
*
- * The mce_data_buf does not have any locks or protection around it,
+ * If the RTAS error is not of the extended type, then we put it in a per
+ * cpu 64bit buffer. If it is the extended type we use global_mce_data_buf.
+ *
+ * The global_mce_data_buf does not have any locks or protection around it,
* if a second machine check comes in, or a system reset is done
* before we have logged the error, then we will get corruption in the
* error log. This is preferable over holding off on calling
@@ -210,20 +223,31 @@ static irqreturn_t ras_error_interrupt(int irq, void *dev_id)
*/
static struct rtas_error_log *fwnmi_get_errinfo(struct pt_regs *regs)
{
- unsigned long errdata = regs->gpr[3];
- struct rtas_error_log *errhdr = NULL;
unsigned long *savep;
+ struct rtas_error_log *h, *errhdr = NULL;
+
+ if (!VALID_FWNMI_BUFFER(regs->gpr[3])) {
+ printk(KERN_ERR "FWNMI: corrupt r3\n");
+ return NULL;
+ }
- if ((errdata >= 0x7000 && errdata < 0x7fff0) ||
- (errdata >= rtas.base && errdata < rtas.base + rtas.size - 16)) {
- savep = __va(errdata);
- regs->gpr[3] = savep[0]; /* restore original r3 */
- memset(mce_data_buf, 0, RTAS_ERROR_LOG_MAX);
- memcpy(mce_data_buf, (char *)(savep + 1), RTAS_ERROR_LOG_MAX);
- errhdr = (struct rtas_error_log *)mce_data_buf;
+ savep = __va(regs->gpr[3]);
+ regs->gpr[3] = savep[0]; /* restore original r3 */
+
+ /* If it isn't an extended log we can use the per cpu 64bit buffer */
+ h = (struct rtas_error_log *)&savep[1];
+ if (!h->extended) {
+ memcpy(&__get_cpu_var(mce_data_buf), h, sizeof(__u64));
+ errhdr = (struct rtas_error_log *)&__get_cpu_var(mce_data_buf);
} else {
- printk("FWNMI: corrupt r3\n");
+ int len;
+
+ len = max_t(int, 8+h->extended_log_length, RTAS_ERROR_LOG_MAX);
+ memset(global_mce_data_buf, 0, RTAS_ERROR_LOG_MAX);
+ memcpy(global_mce_data_buf, h, len);
+ errhdr = (struct rtas_error_log *)global_mce_data_buf;
}
+
return errhdr;
}
@@ -235,7 +259,7 @@ static void fwnmi_release_errinfo(void)
{
int ret = rtas_call(rtas_token("ibm,nmi-interlock"), 0, 1, NULL);
if (ret != 0)
- printk("FWNMI: nmi-interlock failed: %d\n", ret);
+ printk(KERN_ERR "FWNMI: nmi-interlock failed: %d\n", ret);
}
int pSeries_system_reset_exception(struct pt_regs *regs)
@@ -259,31 +283,43 @@ int pSeries_system_reset_exception(struct pt_regs *regs)
* Return 1 if corrected (or delivered a signal).
* Return 0 if there is nothing we can do.
*/
-static int recover_mce(struct pt_regs *regs, struct rtas_error_log * err)
+static int recover_mce(struct pt_regs *regs, struct rtas_error_log *err)
{
- int nonfatal = 0;
+ int recovered = 0;
- if (err->disposition == RTAS_DISP_FULLY_RECOVERED) {
+ if (!(regs->msr & MSR_RI)) {
+ /* If MSR_RI isn't set, we cannot recover */
+ recovered = 0;
+
+ } else if (err->disposition == RTAS_DISP_FULLY_RECOVERED) {
/* Platform corrected itself */
- nonfatal = 1;
- } else if ((regs->msr & MSR_RI) &&
- user_mode(regs) &&
- err->severity == RTAS_SEVERITY_ERROR_SYNC &&
- err->disposition == RTAS_DISP_NOT_RECOVERED &&
- err->target == RTAS_TARGET_MEMORY &&
- err->type == RTAS_TYPE_ECC_UNCORR &&
- !(current->pid == 0 || is_global_init(current))) {
- /* Kill off a user process with an ECC error */
- printk(KERN_ERR "MCE: uncorrectable ecc error for pid %d\n",
- current->pid);
- /* XXX something better for ECC error? */
- _exception(SIGBUS, regs, BUS_ADRERR, regs->nip);
- nonfatal = 1;
+ recovered = 1;
+
+ } else if (err->disposition == RTAS_DISP_LIMITED_RECOVERY) {
+ /* Platform corrected itself but could be degraded */
+ printk(KERN_ERR "MCE: limited recovery, system may "
+ "be degraded\n");
+ recovered = 1;
+
+ } else if (user_mode(regs) && !is_global_init(current) &&
+ err->severity == RTAS_SEVERITY_ERROR_SYNC) {
+
+ /*
+ * If we received a synchronous error when in userspace
+ * kill the task. Firmware may report details of the fail
+ * asynchronously, so we can't rely on the target and type
+ * fields being valid here.
+ */
+ printk(KERN_ERR "MCE: uncorrectable error, killing task "
+ "%s:%d\n", current->comm, current->pid);
+
+ _exception(SIGBUS, regs, BUS_MCEERR_AR, regs->nip);
+ recovered = 1;
}
- log_error((char *)err, ERR_TYPE_RTAS_LOG, !nonfatal);
+ log_error((char *)err, ERR_TYPE_RTAS_LOG, 0);
- return nonfatal;
+ return recovered;
}
/*
diff --git a/arch/powerpc/sysdev/fsl_rio.c b/arch/powerpc/sysdev/fsl_rio.c
index 9f99bef..8c6cab0 100644
--- a/arch/powerpc/sysdev/fsl_rio.c
+++ b/arch/powerpc/sysdev/fsl_rio.c
@@ -1555,8 +1555,6 @@ int fsl_rio_setup(struct platform_device *dev)
saved_mcheck_exception = ppc_md.machine_check_exception;
ppc_md.machine_check_exception = fsl_rio_mcheck_exception;
#endif
- /* Ensure that RFXE is set */
- mtspr(SPRN_HID1, (mfspr(SPRN_HID1) | 0x20000));
return 0;
err:
diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c
index 7c13426..b0c8469 100644
--- a/arch/powerpc/sysdev/mpic.c
+++ b/arch/powerpc/sysdev/mpic.c
@@ -674,7 +674,8 @@ void mpic_unmask_irq(unsigned int irq)
/* make sure mask gets to controller before we return to user */
do {
if (!loops--) {
- printk(KERN_ERR "mpic_enable_irq timeout\n");
+ printk(KERN_ERR "%s: timeout on hwirq %u\n",
+ __func__, src);
break;
}
} while(mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI)) & MPIC_VECPRI_MASK);
@@ -695,7 +696,8 @@ void mpic_mask_irq(unsigned int irq)
/* make sure mask gets to controller before we return to user */
do {
if (!loops--) {
- printk(KERN_ERR "mpic_enable_irq timeout\n");
+ printk(KERN_ERR "%s: timeout on hwirq %u\n",
+ __func__, src);
break;
}
} while(!(mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI)) & MPIC_VECPRI_MASK));
diff --git a/arch/s390/defconfig b/arch/s390/defconfig
index d796971..29c82c6 100644
--- a/arch/s390/defconfig
+++ b/arch/s390/defconfig
@@ -5,10 +5,21 @@ CONFIG_AUDIT=y
CONFIG_RCU_TRACE=y
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
+CONFIG_CGROUPS=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_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_PERF_EVENTS=y
+# CONFIG_COMPAT_BRK is not set
CONFIG_SLAB=y
+CONFIG_PROFILING=y
+CONFIG_OPROFILE=y
CONFIG_KPROBES=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
@@ -19,7 +30,9 @@ CONFIG_HIGH_RES_TIMERS=y
CONFIG_PREEMPT=y
CONFIG_MEMORY_HOTPLUG=y
CONFIG_MEMORY_HOTREMOVE=y
+CONFIG_KSM=y
CONFIG_BINFMT_MISC=m
+CONFIG_CMM=m
CONFIG_HZ_100=y
CONFIG_KEXEC=y
CONFIG_PM=y
@@ -105,6 +118,7 @@ CONFIG_DEBUG_LIST=y
CONFIG_DEBUG_NOTIFIERS=y
# CONFIG_RCU_CPU_STALL_DETECTOR is not set
CONFIG_KPROBES_SANITY_TEST=y
+CONFIG_DEBUG_FORCE_WEAK_PER_CPU=y
CONFIG_CPU_NOTIFIER_ERROR_INJECT=m
CONFIG_LATENCYTOP=y
CONFIG_SYSCTL_SYSCALL_CHECK=y
diff --git a/arch/s390/include/asm/compat.h b/arch/s390/include/asm/compat.h
index a875c2f..da359ca 100644
--- a/arch/s390/include/asm/compat.h
+++ b/arch/s390/include/asm/compat.h
@@ -169,7 +169,7 @@ static inline compat_uptr_t ptr_to_compat(void __user *uptr)
static inline int is_compat_task(void)
{
- return test_thread_flag(TIF_31BIT);
+ return is_32bit_task();
}
#else
diff --git a/arch/s390/include/asm/elf.h b/arch/s390/include/asm/elf.h
index 354d426..10c029c 100644
--- a/arch/s390/include/asm/elf.h
+++ b/arch/s390/include/asm/elf.h
@@ -161,7 +161,9 @@ extern unsigned int vdso_enabled;
use of this is to invoke "./ld.so someprog" to test out a new version of
the loader. We need to make sure that it is out of the way of the program
that it will "exec", and that there is sufficient room for the brk. */
-#define ELF_ET_DYN_BASE (STACK_TOP / 3 * 2)
+
+extern unsigned long randomize_et_dyn(unsigned long base);
+#define ELF_ET_DYN_BASE (randomize_et_dyn(STACK_TOP / 3 * 2))
/* This yields a mask that user programs can use to figure out what
instruction set this CPU supports. */
@@ -206,6 +208,8 @@ do { \
current->mm->context.noexec == 0; \
})
+#define STACK_RND_MASK 0x7ffUL
+
#define ARCH_DLINFO \
do { \
if (vdso_enabled) \
@@ -218,4 +222,7 @@ struct linux_binprm;
#define ARCH_HAS_SETUP_ADDITIONAL_PAGES 1
int arch_setup_additional_pages(struct linux_binprm *, int);
+extern unsigned long arch_randomize_brk(struct mm_struct *mm);
+#define arch_randomize_brk arch_randomize_brk
+
#endif
diff --git a/arch/s390/include/asm/system.h b/arch/s390/include/asm/system.h
index 6710b0e..8f8d759 100644
--- a/arch/s390/include/asm/system.h
+++ b/arch/s390/include/asm/system.h
@@ -449,7 +449,7 @@ extern void (*_machine_restart)(char *command);
extern void (*_machine_halt)(void);
extern void (*_machine_power_off)(void);
-#define arch_align_stack(x) (x)
+extern unsigned long arch_align_stack(unsigned long sp);
static inline int tprot(unsigned long addr)
{
diff --git a/arch/s390/include/asm/thread_info.h b/arch/s390/include/asm/thread_info.h
index ebc7709..ad1382f 100644
--- a/arch/s390/include/asm/thread_info.h
+++ b/arch/s390/include/asm/thread_info.h
@@ -118,6 +118,12 @@ static inline struct thread_info *current_thread_info(void)
#define _TIF_SINGLE_STEP (1<<TIF_FREEZE)
#define _TIF_FREEZE (1<<TIF_FREEZE)
+#ifdef CONFIG_64BIT
+#define is_32bit_task() (test_thread_flag(TIF_31BIT))
+#else
+#define is_32bit_task() (1)
+#endif
+
#endif /* __KERNEL__ */
#define PREEMPT_ACTIVE 0x4000000
diff --git a/arch/s390/kernel/process.c b/arch/s390/kernel/process.c
index 6ba4222..a895e69 100644
--- a/arch/s390/kernel/process.c
+++ b/arch/s390/kernel/process.c
@@ -30,9 +30,11 @@
#include <linux/tick.h>
#include <linux/elfcore.h>
#include <linux/kernel_stat.h>
+#include <linux/personality.h>
#include <linux/syscalls.h>
#include <linux/compat.h>
#include <linux/kprobes.h>
+#include <linux/random.h>
#include <asm/compat.h>
#include <asm/uaccess.h>
#include <asm/pgtable.h>
@@ -332,3 +334,39 @@ unsigned long get_wchan(struct task_struct *p)
}
return 0;
}
+
+unsigned long arch_align_stack(unsigned long sp)
+{
+ if (!(current->personality & ADDR_NO_RANDOMIZE) && randomize_va_space)
+ sp -= get_random_int() & ~PAGE_MASK;
+ return sp & ~0xf;
+}
+
+static inline unsigned long brk_rnd(void)
+{
+ /* 8MB for 32bit, 1GB for 64bit */
+ if (is_32bit_task())
+ return (get_random_int() & 0x7ffUL) << PAGE_SHIFT;
+ else
+ return (get_random_int() & 0x3ffffUL) << PAGE_SHIFT;
+}
+
+unsigned long arch_randomize_brk(struct mm_struct *mm)
+{
+ unsigned long ret = PAGE_ALIGN(mm->brk + brk_rnd());
+
+ if (ret < mm->brk)
+ return mm->brk;
+ return ret;
+}
+
+unsigned long randomize_et_dyn(unsigned long base)
+{
+ unsigned long ret = PAGE_ALIGN(base + brk_rnd());
+
+ if (!(current->flags & PF_RANDOMIZE))
+ return base;
+ if (ret < base)
+ return base;
+ return ret;
+}
diff --git a/arch/s390/kernel/vdso.c b/arch/s390/kernel/vdso.c
index e3150dd..f438d74 100644
--- a/arch/s390/kernel/vdso.c
+++ b/arch/s390/kernel/vdso.c
@@ -203,7 +203,6 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
if (!uses_interp)
return 0;
- vdso_base = mm->mmap_base;
#ifdef CONFIG_64BIT
vdso_pagelist = vdso64_pagelist;
vdso_pages = vdso64_pages;
@@ -233,8 +232,7 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
* fail and end up putting it elsewhere.
*/
down_write(&mm->mmap_sem);
- vdso_base = get_unmapped_area(NULL, vdso_base,
- vdso_pages << PAGE_SHIFT, 0, 0);
+ vdso_base = get_unmapped_area(NULL, 0, vdso_pages << PAGE_SHIFT, 0, 0);
if (IS_ERR_VALUE(vdso_base)) {
rc = vdso_base;
goto out_up;
diff --git a/arch/s390/mm/mmap.c b/arch/s390/mm/mmap.c
index 869efba..c9a9f7f 100644
--- a/arch/s390/mm/mmap.c
+++ b/arch/s390/mm/mmap.c
@@ -27,17 +27,44 @@
#include <linux/personality.h>
#include <linux/mm.h>
#include <linux/module.h>
+#include <linux/random.h>
#include <asm/pgalloc.h>
#include <asm/compat.h>
+static unsigned long stack_maxrandom_size(void)
+{
+ if (!(current->flags & PF_RANDOMIZE))
+ return 0;
+ if (current->personality & ADDR_NO_RANDOMIZE)
+ return 0;
+ return STACK_RND_MASK << PAGE_SHIFT;
+}
+
/*
* Top of mmap area (just below the process stack).
*
- * Leave an at least ~128 MB hole.
+ * Leave at least a ~32 MB hole.
*/
-#define MIN_GAP (128*1024*1024)
+#define MIN_GAP (32*1024*1024)
#define MAX_GAP (STACK_TOP/6*5)
+static inline int mmap_is_legacy(void)
+{
+ if (current->personality & ADDR_COMPAT_LAYOUT)
+ return 1;
+ if (rlimit(RLIMIT_STACK) == RLIM_INFINITY)
+ return 1;
+ return sysctl_legacy_va_layout;
+}
+
+static unsigned long mmap_rnd(void)
+{
+ if (!(current->flags & PF_RANDOMIZE))
+ return 0;
+ /* 8MB randomization for mmap_base */
+ return (get_random_int() & 0x7ffUL) << PAGE_SHIFT;
+}
+
static inline unsigned long mmap_base(void)
{
unsigned long gap = rlimit(RLIMIT_STACK);
@@ -46,22 +73,8 @@ static inline unsigned long mmap_base(void)
gap = MIN_GAP;
else if (gap > MAX_GAP)
gap = MAX_GAP;
-
- return STACK_TOP - (gap & PAGE_MASK);
-}
-
-static inline int mmap_is_legacy(void)
-{
-#ifdef CONFIG_64BIT
- /*
- * Force standard allocation for 64 bit programs.
- */
- if (!is_compat_task())
- return 1;
-#endif
- return sysctl_legacy_va_layout ||
- (current->personality & ADDR_COMPAT_LAYOUT) ||
- rlimit(RLIMIT_STACK) == RLIM_INFINITY;
+ gap &= PAGE_MASK;
+ return STACK_TOP - stack_maxrandom_size() - mmap_rnd() - gap;
}
#ifndef CONFIG_64BIT
diff --git a/arch/score/Kconfig b/arch/score/Kconfig
index 4293fdcb..27b2295 100644
--- a/arch/score/Kconfig
+++ b/arch/score/Kconfig
@@ -1,5 +1,9 @@
menu "Machine selection"
+config SCORE
+ def_bool y
+ select HAVE_GENERIC_HARDIRQS
+
choice
prompt "System type"
default MACH_SPCT6600
@@ -53,9 +57,6 @@ config GENERIC_CLOCKEVENTS
config SCHED_NO_NO_OMIT_FRAME_POINTER
def_bool y
-config GENERIC_HARDIRQS_NO__DO_IRQ
- def_bool y
-
config GENERIC_SYSCALL_TABLE
def_bool y
@@ -68,9 +69,6 @@ menu "Kernel type"
config 32BIT
def_bool y
-config GENERIC_HARDIRQS
- def_bool y
-
config ARCH_FLATMEM_ENABLE
def_bool y
diff --git a/arch/score/configs/spct6600_defconfig b/arch/score/configs/spct6600_defconfig
index 9883c50..df1edbf 100644
--- a/arch/score/configs/spct6600_defconfig
+++ b/arch/score/configs/spct6600_defconfig
@@ -9,7 +9,7 @@ CONFIG_LOG_BUF_SHIFT=12
CONFIG_SYSFS_DEPRECATED_V2=y
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_KALLSYMS is not set
# CONFIG_HOTPLUG is not set
CONFIG_SLAB=y
diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig
index 8d411bd..8a9011d 100644
--- a/arch/sh/Kconfig
+++ b/arch/sh/Kconfig
@@ -1,6 +1,6 @@
config SUPERH
def_bool y
- select EMBEDDED
+ select EXPERT
select CLKDEV_LOOKUP
select HAVE_IDE if HAS_IOPORT
select HAVE_MEMBLOCK
diff --git a/arch/sh/kernel/cpu/shmobile/cpuidle.c b/arch/sh/kernel/cpu/shmobile/cpuidle.c
index 83972aa..c19e2a9 100644
--- a/arch/sh/kernel/cpu/shmobile/cpuidle.c
+++ b/arch/sh/kernel/cpu/shmobile/cpuidle.c
@@ -81,7 +81,6 @@ void sh_mobile_setup_cpuidle(void)
state->target_residency = 1 * 2;
state->power_usage = 3;
state->flags = 0;
- state->flags |= CPUIDLE_FLAG_SHALLOW;
state->flags |= CPUIDLE_FLAG_TIME_VALID;
state->enter = cpuidle_sleep_enter;
diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig
index 45d9c87..95695e9 100644
--- a/arch/sparc/Kconfig
+++ b/arch/sparc/Kconfig
@@ -50,6 +50,7 @@ config SPARC64
select RTC_DRV_STARFIRE
select HAVE_PERF_EVENTS
select PERF_USE_VMALLOC
+ select HAVE_GENERIC_HARDIRQS
config ARCH_DEFCONFIG
string
@@ -107,10 +108,6 @@ config NEED_PER_CPU_EMBED_FIRST_CHUNK
config NEED_PER_CPU_PAGE_FIRST_CHUNK
def_bool y if SPARC64
-config GENERIC_HARDIRQS_NO__DO_IRQ
- bool
- def_bool y if SPARC64
-
config MMU
bool
default y
@@ -276,10 +273,6 @@ config HOTPLUG_CPU
can be controlled through /sys/devices/system/cpu/cpu#.
Say N if you want to disable CPU hotplug.
-config GENERIC_HARDIRQS
- bool
- default y if SPARC64
-
source "kernel/time/Kconfig"
if SPARC64
diff --git a/arch/tile/Kconfig b/arch/tile/Kconfig
index e11b5fc..08948e4 100644
--- a/arch/tile/Kconfig
+++ b/arch/tile/Kconfig
@@ -1,24 +1,33 @@
# For a description of the syntax of this configuration file,
# see Documentation/kbuild/config-language.txt.
-config MMU
- def_bool y
-
-config GENERIC_CSUM
- def_bool y
-
-config GENERIC_HARDIRQS
+config TILE
def_bool y
+ select HAVE_KVM if !TILEGX
+ select GENERIC_FIND_FIRST_BIT
+ select GENERIC_FIND_NEXT_BIT
+ select USE_GENERIC_SMP_HELPERS
+ select CC_OPTIMIZE_FOR_SIZE
+ select HAVE_GENERIC_HARDIRQS
+ select GENERIC_IRQ_PROBE
+ select GENERIC_PENDING_IRQ if SMP
-config GENERIC_HARDIRQS_NO__DO_IRQ
- def_bool y
+# FIXME: investigate whether we need/want these options.
+# select HAVE_IOREMAP_PROT
+# select HAVE_OPTPROBES
+# select HAVE_REGS_AND_STACK_ACCESS_API
+# select HAVE_HW_BREAKPOINT
+# select PERF_EVENTS
+# select HAVE_USER_RETURN_NOTIFIER
+# config NO_BOOTMEM
+# config ARCH_SUPPORTS_DEBUG_PAGEALLOC
+# config HUGETLB_PAGE_SIZE_VARIABLE
-config GENERIC_IRQ_PROBE
+config MMU
def_bool y
-config GENERIC_PENDING_IRQ
+config GENERIC_CSUM
def_bool y
- depends on GENERIC_HARDIRQS && SMP
config SEMAPHORE_SLEEPERS
def_bool y
@@ -97,26 +106,6 @@ config HVC_TILE
select HVC_DRIVER
def_bool y
-config TILE
- def_bool y
- select HAVE_KVM if !TILEGX
- select GENERIC_FIND_FIRST_BIT
- select GENERIC_FIND_NEXT_BIT
- select USE_GENERIC_SMP_HELPERS
- select CC_OPTIMIZE_FOR_SIZE
-
-# FIXME: investigate whether we need/want these options.
-# select HAVE_IOREMAP_PROT
-# select HAVE_OPTPROBES
-# select HAVE_REGS_AND_STACK_ACCESS_API
-# select HAVE_HW_BREAKPOINT
-# select PERF_EVENTS
-# select HAVE_USER_RETURN_NOTIFIER
-# config NO_BOOTMEM
-# config ARCH_SUPPORTS_DEBUG_PAGEALLOC
-# config HUGETLB_PAGE_SIZE_VARIABLE
-
-
# Please note: TILE-Gx support is not yet finalized; this is
# the preliminary support. TILE-Gx drivers are only provided
# with the alpha or beta test versions for Tilera customers.
@@ -220,7 +209,7 @@ config FORCE_MAX_ZONEORDER
choice
depends on !TILEGX
- prompt "Memory split" if EMBEDDED
+ prompt "Memory split" if EXPERT
default VMSPLIT_3G
---help---
Select the desired split between kernel and user memory.
diff --git a/arch/tile/Kconfig.debug b/arch/tile/Kconfig.debug
index a81f0fb..9bc161a 100644
--- a/arch/tile/Kconfig.debug
+++ b/arch/tile/Kconfig.debug
@@ -3,7 +3,7 @@ menu "Kernel hacking"
source "lib/Kconfig.debug"
config EARLY_PRINTK
- bool "Early printk" if EMBEDDED && DEBUG_KERNEL
+ bool "Early printk" if EXPERT && DEBUG_KERNEL
default y
help
Write kernel log output directly via the hypervisor console.
diff --git a/arch/tile/configs/tile_defconfig b/arch/tile/configs/tile_defconfig
index 919c54a..0fe54445 100644
--- a/arch/tile/configs/tile_defconfig
+++ b/arch/tile/configs/tile_defconfig
@@ -3,7 +3,7 @@ CONFIG_EXPERIMENTAL=y
CONFIG_SYSVIPC=y
CONFIG_BLK_DEV_INITRD=y
CONFIG_INITRAMFS_SOURCE="usr/contents.txt"
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
# CONFIG_COMPAT_BRK is not set
CONFIG_PROFILING=y
CONFIG_MODULES=y
diff --git a/arch/um/Kconfig.common b/arch/um/Kconfig.common
index 049d048..e351e14 100644
--- a/arch/um/Kconfig.common
+++ b/arch/um/Kconfig.common
@@ -3,14 +3,10 @@ config DEFCONFIG_LIST
option defconfig_list
default "arch/$ARCH/defconfig"
-# UML uses the generic IRQ subsystem
-config GENERIC_HARDIRQS
- bool
- default y
-
config UML
bool
default y
+ select HAVE_GENERIC_HARDIRQS
config MMU
bool
diff --git a/arch/um/Kconfig.um b/arch/um/Kconfig.um
index f8d1d0d..90a438a 100644
--- a/arch/um/Kconfig.um
+++ b/arch/um/Kconfig.um
@@ -120,9 +120,6 @@ config SMP
If you don't know what to do, say N.
-config GENERIC_HARDIRQS_NO__DO_IRQ
- def_bool y
-
config NR_CPUS
int "Maximum number of CPUs (2-32)"
range 2 32
diff --git a/arch/um/defconfig b/arch/um/defconfig
index 564f3de..9f7634f 100644
--- a/arch/um/defconfig
+++ b/arch/um/defconfig
@@ -133,7 +133,7 @@ CONFIG_SYSFS_DEPRECATED=y
# CONFIG_BLK_DEV_INITRD is not set
CONFIG_CC_OPTIMIZE_FOR_SIZE=y
CONFIG_SYSCTL=y
-# CONFIG_EMBEDDED is not set
+# CONFIG_EXPERT is not set
CONFIG_UID16=y
CONFIG_SYSCTL_SYSCALL=y
CONFIG_KALLSYMS=y
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 36ed2e2..d5ed94d 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -627,11 +627,11 @@ config APB_TIMER
as it is off-chip. APB timers are always running regardless of CPU
C states, they are used as per CPU clockevent device when possible.
-# Mark as embedded because too many people got it wrong.
+# Mark as expert because too many people got it wrong.
# The code disables itself when not needed.
config DMI
default y
- bool "Enable DMI scanning" if EMBEDDED
+ bool "Enable DMI scanning" if EXPERT
---help---
Enabled scanning of DMI to identify machine quirks. Say Y
here unless you have verified that your setup is not
@@ -639,7 +639,7 @@ config DMI
BIOS code.
config GART_IOMMU
- bool "GART IOMMU support" if EMBEDDED
+ bool "GART IOMMU support" if EXPERT
default y
select SWIOTLB
depends on X86_64 && PCI && AMD_NB
@@ -889,7 +889,7 @@ config X86_THERMAL_VECTOR
depends on X86_MCE_INTEL
config VM86
- bool "Enable VM86 support" if EMBEDDED
+ bool "Enable VM86 support" if EXPERT
default y
depends on X86_32
---help---
@@ -1073,7 +1073,7 @@ endchoice
choice
depends on EXPERIMENTAL
- prompt "Memory split" if EMBEDDED
+ prompt "Memory split" if EXPERT
default VMSPLIT_3G
depends on X86_32
---help---
@@ -1135,7 +1135,7 @@ config ARCH_DMA_ADDR_T_64BIT
def_bool X86_64 || HIGHMEM64G
config DIRECT_GBPAGES
- bool "Enable 1GB pages for kernel pagetables" if EMBEDDED
+ bool "Enable 1GB pages for kernel pagetables" if EXPERT
default y
depends on X86_64
---help---
@@ -1369,7 +1369,7 @@ config MATH_EMULATION
config MTRR
def_bool y
- prompt "MTRR (Memory Type Range Register) support" if EMBEDDED
+ prompt "MTRR (Memory Type Range Register) support" if EXPERT
---help---
On Intel P6 family processors (Pentium Pro, Pentium II and later)
the Memory Type Range Registers (MTRRs) may be used to control
@@ -1435,7 +1435,7 @@ config MTRR_SANITIZER_SPARE_REG_NR_DEFAULT
config X86_PAT
def_bool y
- prompt "x86 PAT support" if EMBEDDED
+ prompt "x86 PAT support" if EXPERT
depends on MTRR
---help---
Use PAT attributes to setup page level cache control.
@@ -1539,7 +1539,7 @@ config KEXEC_JUMP
code in physical address mode via KEXEC
config PHYSICAL_START
- hex "Physical address where the kernel is loaded" if (EMBEDDED || CRASH_DUMP)
+ hex "Physical address where the kernel is loaded" if (EXPERT || CRASH_DUMP)
default "0x1000000"
---help---
This gives the physical address where the kernel is loaded.
@@ -1934,13 +1934,19 @@ config PCI_MMCONFIG
depends on X86_64 && PCI && ACPI
config PCI_CNB20LE_QUIRK
- bool "Read CNB20LE Host Bridge Windows"
- depends on PCI
+ bool "Read CNB20LE Host Bridge Windows" if EXPERT
+ default n
+ depends on PCI && EXPERIMENTAL
help
Read the PCI windows out of the CNB20LE host bridge. This allows
PCI hotplug to work on systems with the CNB20LE chipset which do
not have ACPI.
+ There's no public spec for this chipset, and this functionality
+ is known to be incomplete.
+
+ You should say N unless you know you need this.
+
config DMAR
bool "Support for DMA Remapping Devices (EXPERIMENTAL)"
depends on PCI_MSI && ACPI && EXPERIMENTAL
@@ -2062,13 +2068,14 @@ config OLPC
bool "One Laptop Per Child support"
select GPIOLIB
select OLPC_OPENFIRMWARE
+ depends on !X86_64 && !X86_PAE
---help---
Add support for detecting the unique features of the OLPC
XO hardware.
config OLPC_XO1
tristate "OLPC XO-1 support"
- depends on OLPC && PCI
+ depends on OLPC && MFD_CS5535
---help---
Add support for non-essential features of the OLPC XO-1 laptop.
diff --git a/arch/x86/Kconfig.cpu b/arch/x86/Kconfig.cpu
index 15588a0..283c5a6 100644
--- a/arch/x86/Kconfig.cpu
+++ b/arch/x86/Kconfig.cpu
@@ -424,7 +424,7 @@ config X86_DEBUGCTLMSR
depends on !(MK6 || MWINCHIPC6 || MWINCHIP3D || MCYRIXIII || M586MMX || M586TSC || M586 || M486 || M386) && !UML
menuconfig PROCESSOR_SELECT
- bool "Supported processor vendors" if EMBEDDED
+ bool "Supported processor vendors" if EXPERT
---help---
This lets you choose what x86 vendor support code your kernel
will include.
diff --git a/arch/x86/Kconfig.debug b/arch/x86/Kconfig.debug
index 45143bb..615e188 100644
--- a/arch/x86/Kconfig.debug
+++ b/arch/x86/Kconfig.debug
@@ -31,7 +31,7 @@ config X86_VERBOSE_BOOTUP
see errors. Disable this if you want silent bootup.
config EARLY_PRINTK
- bool "Early printk" if EMBEDDED
+ bool "Early printk" if EXPERT
default y
---help---
Write kernel log output directly into the VGA buffer or to a serial
@@ -138,7 +138,7 @@ config DEBUG_NX_TEST
config DOUBLEFAULT
default y
- bool "Enable doublefault exception handler" if EMBEDDED
+ bool "Enable doublefault exception handler" if EXPERT
depends on X86_32
---help---
This option allows trapping of rare doublefault exceptions that
diff --git a/arch/x86/include/asm/cacheflush.h b/arch/x86/include/asm/cacheflush.h
index 63e35ec..62f0844 100644
--- a/arch/x86/include/asm/cacheflush.h
+++ b/arch/x86/include/asm/cacheflush.h
@@ -1,48 +1,8 @@
#ifndef _ASM_X86_CACHEFLUSH_H
#define _ASM_X86_CACHEFLUSH_H
-/* Keep includes the same across arches. */
-#include <linux/mm.h>
-
/* Caches aren't brain-dead on the intel. */
-static inline void flush_cache_all(void) { }
-static inline void flush_cache_mm(struct mm_struct *mm) { }
-static inline void flush_cache_dup_mm(struct mm_struct *mm) { }
-static inline void flush_cache_range(struct vm_area_struct *vma,
- unsigned long start, unsigned long end) { }
-static inline void flush_cache_page(struct vm_area_struct *vma,
- unsigned long vmaddr, unsigned long pfn) { }
-#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0
-static inline void flush_dcache_page(struct page *page) { }
-static inline void flush_dcache_mmap_lock(struct address_space *mapping) { }
-static inline void flush_dcache_mmap_unlock(struct address_space *mapping) { }
-static inline void flush_icache_range(unsigned long start,
- unsigned long end) { }
-static inline void flush_icache_page(struct vm_area_struct *vma,
- struct page *page) { }
-static inline void flush_icache_user_range(struct vm_area_struct *vma,
- struct page *page,
- unsigned long addr,
- unsigned long len) { }
-static inline void flush_cache_vmap(unsigned long start, unsigned long end) { }
-static inline void flush_cache_vunmap(unsigned long start,
- unsigned long end) { }
-
-static inline void copy_to_user_page(struct vm_area_struct *vma,
- struct page *page, unsigned long vaddr,
- void *dst, const void *src,
- unsigned long len)
-{
- memcpy(dst, src, len);
-}
-
-static inline void copy_from_user_page(struct vm_area_struct *vma,
- struct page *page, unsigned long vaddr,
- void *dst, const void *src,
- unsigned long len)
-{
- memcpy(dst, src, len);
-}
+#include <asm-generic/cacheflush.h>
#ifdef CONFIG_X86_PAT
/*
diff --git a/arch/x86/include/asm/cpu.h b/arch/x86/include/asm/cpu.h
index 4fab24d..6e6e755 100644
--- a/arch/x86/include/asm/cpu.h
+++ b/arch/x86/include/asm/cpu.h
@@ -32,5 +32,6 @@ extern void arch_unregister_cpu(int);
DECLARE_PER_CPU(int, cpu_state);
+int __cpuinit mwait_usable(const struct cpuinfo_x86 *);
#endif /* _ASM_X86_CPU_H */
diff --git a/arch/x86/include/asm/jump_label.h b/arch/x86/include/asm/jump_label.h
index f52d42e..574dbc2 100644
--- a/arch/x86/include/asm/jump_label.h
+++ b/arch/x86/include/asm/jump_label.h
@@ -14,7 +14,7 @@
do { \
asm goto("1:" \
JUMP_LABEL_INITIAL_NOP \
- ".pushsection __jump_table, \"a\" \n\t"\
+ ".pushsection __jump_table, \"aw\" \n\t"\
_ASM_PTR "1b, %l[" #label "], %c0 \n\t" \
".popsection \n\t" \
: : "i" (key) : : label); \
diff --git a/arch/x86/include/asm/numa_32.h b/arch/x86/include/asm/numa_32.h
index a372290..b0ef2b4 100644
--- a/arch/x86/include/asm/numa_32.h
+++ b/arch/x86/include/asm/numa_32.h
@@ -1,6 +1,8 @@
#ifndef _ASM_X86_NUMA_32_H
#define _ASM_X86_NUMA_32_H
+extern int numa_off;
+
extern int pxm_to_nid(int pxm);
extern void numa_remove_cpu(int cpu);
diff --git a/arch/x86/include/asm/numa_64.h b/arch/x86/include/asm/numa_64.h
index 5ae8728..0493be3 100644
--- a/arch/x86/include/asm/numa_64.h
+++ b/arch/x86/include/asm/numa_64.h
@@ -40,6 +40,7 @@ extern void __cpuinit numa_remove_cpu(int cpu);
#ifdef CONFIG_NUMA_EMU
#define FAKE_NODE_MIN_SIZE ((u64)32 << 20)
#define FAKE_NODE_MIN_HASH_MASK (~(FAKE_NODE_MIN_SIZE - 1UL))
+void numa_emu_cmdline(char *);
#endif /* CONFIG_NUMA_EMU */
#else
static inline void init_cpu_to_node(void) { }
diff --git a/arch/x86/include/asm/percpu.h b/arch/x86/include/asm/percpu.h
index 8ee4516..3788f46 100644
--- a/arch/x86/include/asm/percpu.h
+++ b/arch/x86/include/asm/percpu.h
@@ -414,8 +414,6 @@ do { \
#define this_cpu_xchg_1(pcp, nval) percpu_xchg_op(pcp, nval)
#define this_cpu_xchg_2(pcp, nval) percpu_xchg_op(pcp, nval)
#define this_cpu_xchg_4(pcp, nval) percpu_xchg_op(pcp, nval)
-#define this_cpu_xchg_8(pcp, nval) percpu_xchg_op(pcp, nval)
-#define this_cpu_cmpxchg_8(pcp, oval, nval) percpu_cmpxchg_op(pcp, oval, nval)
#define irqsafe_cpu_add_1(pcp, val) percpu_add_op((pcp), val)
#define irqsafe_cpu_add_2(pcp, val) percpu_add_op((pcp), val)
@@ -432,8 +430,6 @@ do { \
#define irqsafe_cpu_xchg_1(pcp, nval) percpu_xchg_op(pcp, nval)
#define irqsafe_cpu_xchg_2(pcp, nval) percpu_xchg_op(pcp, nval)
#define irqsafe_cpu_xchg_4(pcp, nval) percpu_xchg_op(pcp, nval)
-#define irqsafe_cpu_xchg_8(pcp, nval) percpu_xchg_op(pcp, nval)
-#define irqsafe_cpu_cmpxchg_8(pcp, oval, nval) percpu_cmpxchg_op(pcp, oval, nval)
#ifndef CONFIG_M386
#define __this_cpu_add_return_1(pcp, val) percpu_add_return_op(pcp, val)
@@ -475,11 +471,15 @@ do { \
#define this_cpu_or_8(pcp, val) percpu_to_op("or", (pcp), val)
#define this_cpu_xor_8(pcp, val) percpu_to_op("xor", (pcp), val)
#define this_cpu_add_return_8(pcp, val) percpu_add_return_op(pcp, val)
+#define this_cpu_xchg_8(pcp, nval) percpu_xchg_op(pcp, nval)
+#define this_cpu_cmpxchg_8(pcp, oval, nval) percpu_cmpxchg_op(pcp, oval, nval)
#define irqsafe_cpu_add_8(pcp, val) percpu_add_op((pcp), val)
#define irqsafe_cpu_and_8(pcp, val) percpu_to_op("and", (pcp), val)
#define irqsafe_cpu_or_8(pcp, val) percpu_to_op("or", (pcp), val)
#define irqsafe_cpu_xor_8(pcp, val) percpu_to_op("xor", (pcp), val)
+#define irqsafe_cpu_xchg_8(pcp, nval) percpu_xchg_op(pcp, nval)
+#define irqsafe_cpu_cmpxchg_8(pcp, oval, nval) percpu_cmpxchg_op(pcp, oval, nval)
#endif
/* This is not atomic against other CPUs -- CPU preemption needs to be off */
diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h
index 53fd1d5..45636ce 100644
--- a/arch/x86/include/asm/processor.h
+++ b/arch/x86/include/asm/processor.h
@@ -761,10 +761,11 @@ extern void select_idle_routine(const struct cpuinfo_x86 *c);
extern void init_c1e_mask(void);
extern unsigned long boot_option_idle_override;
-extern unsigned long idle_halt;
-extern unsigned long idle_nomwait;
extern bool c1e_detected;
+enum idle_boot_override {IDLE_NO_OVERRIDE=0, IDLE_HALT, IDLE_NOMWAIT,
+ IDLE_POLL, IDLE_FORCE_MWAIT};
+
extern void enable_sep_cpu(void);
extern int sysenter_setup(void);
diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c
index ec881c6..b3a7113 100644
--- a/arch/x86/kernel/acpi/boot.c
+++ b/arch/x86/kernel/acpi/boot.c
@@ -509,6 +509,7 @@ int acpi_gsi_to_irq(u32 gsi, unsigned int *irq)
return 0;
}
+EXPORT_SYMBOL_GPL(acpi_gsi_to_irq);
int acpi_isa_irq_to_gsi(unsigned isa_irq, u32 *gsi)
{
diff --git a/arch/x86/kernel/apb_timer.c b/arch/x86/kernel/apb_timer.c
index 7c9ab59..51ef31a 100644
--- a/arch/x86/kernel/apb_timer.c
+++ b/arch/x86/kernel/apb_timer.c
@@ -313,14 +313,16 @@ static void apbt_setup_irq(struct apbt_dev *adev)
if (adev->irq == 0)
return;
+ irq_modify_status(adev->irq, 0, IRQ_MOVE_PCNTXT);
+ irq_set_affinity(adev->irq, cpumask_of(adev->cpu));
+ /* APB timer irqs are set up as mp_irqs, timer is edge type */
+ __set_irq_handler(adev->irq, handle_edge_irq, 0, "edge");
+
if (system_state == SYSTEM_BOOTING) {
- irq_modify_status(adev->irq, 0, IRQ_MOVE_PCNTXT);
- irq_set_affinity(adev->irq, cpumask_of(adev->cpu));
- /* APB timer irqs are set up as mp_irqs, timer is edge type */
- __set_irq_handler(adev->irq, handle_edge_irq, 0, "edge");
if (request_irq(adev->irq, apbt_interrupt_handler,
- IRQF_TIMER | IRQF_DISABLED | IRQF_NOBALANCING,
- adev->name, adev)) {
+ IRQF_TIMER | IRQF_DISABLED |
+ IRQF_NOBALANCING,
+ adev->name, adev)) {
printk(KERN_ERR "Failed request IRQ for APBT%d\n",
adev->num);
}
diff --git a/arch/x86/kernel/cpu/intel_cacheinfo.c b/arch/x86/kernel/cpu/intel_cacheinfo.c
index 7283e98..ec2c19a 100644
--- a/arch/x86/kernel/cpu/intel_cacheinfo.c
+++ b/arch/x86/kernel/cpu/intel_cacheinfo.c
@@ -45,6 +45,7 @@ static const struct _cache_table __cpuinitconst cache_table[] =
{ 0x0a, LVL_1_DATA, 8 }, /* 2 way set assoc, 32 byte line size */
{ 0x0c, LVL_1_DATA, 16 }, /* 4-way set assoc, 32 byte line size */
{ 0x0d, LVL_1_DATA, 16 }, /* 4-way set assoc, 64 byte line size */
+ { 0x0e, LVL_1_DATA, 24 }, /* 6-way set assoc, 64 byte line size */
{ 0x21, LVL_2, 256 }, /* 8-way set assoc, 64 byte line size */
{ 0x22, LVL_3, 512 }, /* 4-way set assoc, sectored cache, 64 byte line size */
{ 0x23, LVL_3, MB(1) }, /* 8-way set assoc, sectored cache, 64 byte line size */
@@ -66,6 +67,7 @@ static const struct _cache_table __cpuinitconst cache_table[] =
{ 0x45, LVL_2, MB(2) }, /* 4-way set assoc, 32 byte line size */
{ 0x46, LVL_3, MB(4) }, /* 4-way set assoc, 64 byte line size */
{ 0x47, LVL_3, MB(8) }, /* 8-way set assoc, 64 byte line size */
+ { 0x48, LVL_2, MB(3) }, /* 12-way set assoc, 64 byte line size */
{ 0x49, LVL_3, MB(4) }, /* 16-way set assoc, 64 byte line size */
{ 0x4a, LVL_3, MB(6) }, /* 12-way set assoc, 64 byte line size */
{ 0x4b, LVL_3, MB(8) }, /* 16-way set assoc, 64 byte line size */
@@ -87,6 +89,7 @@ static const struct _cache_table __cpuinitconst cache_table[] =
{ 0x7c, LVL_2, MB(1) }, /* 8-way set assoc, sectored cache, 64 byte line size */
{ 0x7d, LVL_2, MB(2) }, /* 8-way set assoc, 64 byte line size */
{ 0x7f, LVL_2, 512 }, /* 2-way set assoc, 64 byte line size */
+ { 0x80, LVL_2, 512 }, /* 8-way set assoc, 64 byte line size */
{ 0x82, LVL_2, 256 }, /* 8-way set assoc, 32 byte line size */
{ 0x83, LVL_2, 512 }, /* 8-way set assoc, 32 byte line size */
{ 0x84, LVL_2, MB(1) }, /* 8-way set assoc, 32 byte line size */
diff --git a/arch/x86/kernel/cpu/mcheck/therm_throt.c b/arch/x86/kernel/cpu/mcheck/therm_throt.c
index e12246f..6f8c5e9 100644
--- a/arch/x86/kernel/cpu/mcheck/therm_throt.c
+++ b/arch/x86/kernel/cpu/mcheck/therm_throt.c
@@ -59,6 +59,7 @@ struct thermal_state {
/* Callback to handle core threshold interrupts */
int (*platform_thermal_notify)(__u64 msr_val);
+EXPORT_SYMBOL(platform_thermal_notify);
static DEFINE_PER_CPU(struct thermal_state, thermal_state);
diff --git a/arch/x86/kernel/dumpstack.c b/arch/x86/kernel/dumpstack.c
index d6fb146..df20723 100644
--- a/arch/x86/kernel/dumpstack.c
+++ b/arch/x86/kernel/dumpstack.c
@@ -234,6 +234,7 @@ unsigned __kprobes long oops_begin(void)
bust_spinlocks(1);
return flags;
}
+EXPORT_SYMBOL_GPL(oops_begin);
void __kprobes oops_end(unsigned long flags, struct pt_regs *regs, int signr)
{
diff --git a/arch/x86/kernel/e820.c b/arch/x86/kernel/e820.c
index 0c2b7ef..294f26d 100644
--- a/arch/x86/kernel/e820.c
+++ b/arch/x86/kernel/e820.c
@@ -14,6 +14,7 @@
#include <linux/bootmem.h>
#include <linux/pfn.h>
#include <linux/suspend.h>
+#include <linux/acpi.h>
#include <linux/firmware-map.h>
#include <linux/memblock.h>
diff --git a/arch/x86/kernel/irq_32.c b/arch/x86/kernel/irq_32.c
index 48ff6dc..9974d21 100644
--- a/arch/x86/kernel/irq_32.c
+++ b/arch/x86/kernel/irq_32.c
@@ -129,8 +129,7 @@ void __cpuinit irq_ctx_init(int cpu)
irqctx = page_address(alloc_pages_node(cpu_to_node(cpu),
THREAD_FLAGS,
THREAD_ORDER));
- irqctx->tinfo.task = NULL;
- irqctx->tinfo.exec_domain = NULL;
+ memset(&irqctx->tinfo, 0, sizeof(struct thread_info));
irqctx->tinfo.cpu = cpu;
irqctx->tinfo.preempt_count = HARDIRQ_OFFSET;
irqctx->tinfo.addr_limit = MAKE_MM_SEG(0);
@@ -140,10 +139,8 @@ void __cpuinit irq_ctx_init(int cpu)
irqctx = page_address(alloc_pages_node(cpu_to_node(cpu),
THREAD_FLAGS,
THREAD_ORDER));
- irqctx->tinfo.task = NULL;
- irqctx->tinfo.exec_domain = NULL;
+ memset(&irqctx->tinfo, 0, sizeof(struct thread_info));
irqctx->tinfo.cpu = cpu;
- irqctx->tinfo.preempt_count = 0;
irqctx->tinfo.addr_limit = MAKE_MM_SEG(0);
per_cpu(softirq_ctx, cpu) = irqctx;
diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c
index 09c08a1..e764fc0 100644
--- a/arch/x86/kernel/process.c
+++ b/arch/x86/kernel/process.c
@@ -14,6 +14,7 @@
#include <linux/utsname.h>
#include <trace/events/power.h>
#include <linux/hw_breakpoint.h>
+#include <asm/cpu.h>
#include <asm/system.h>
#include <asm/apic.h>
#include <asm/syscalls.h>
@@ -22,11 +23,6 @@
#include <asm/i387.h>
#include <asm/debugreg.h>
-unsigned long idle_halt;
-EXPORT_SYMBOL(idle_halt);
-unsigned long idle_nomwait;
-EXPORT_SYMBOL(idle_nomwait);
-
struct kmem_cache *task_xstate_cachep;
EXPORT_SYMBOL_GPL(task_xstate_cachep);
@@ -327,7 +323,7 @@ long sys_execve(const char __user *name,
/*
* Idle related variables and functions
*/
-unsigned long boot_option_idle_override = 0;
+unsigned long boot_option_idle_override = IDLE_NO_OVERRIDE;
EXPORT_SYMBOL(boot_option_idle_override);
/*
@@ -386,6 +382,8 @@ void default_idle(void)
else
local_irq_enable();
current_thread_info()->status |= TS_POLLING;
+ trace_power_end(smp_processor_id());
+ trace_cpu_idle(PWR_EVENT_EXIT, smp_processor_id());
} else {
local_irq_enable();
/* loop is done by the caller */
@@ -443,8 +441,6 @@ EXPORT_SYMBOL_GPL(cpu_idle_wait);
*/
void mwait_idle_with_hints(unsigned long ax, unsigned long cx)
{
- trace_power_start(POWER_CSTATE, (ax>>4)+1, smp_processor_id());
- trace_cpu_idle((ax>>4)+1, smp_processor_id());
if (!need_resched()) {
if (cpu_has(__this_cpu_ptr(&cpu_info), X86_FEATURE_CLFLUSH_MONITOR))
clflush((void *)&current_thread_info()->flags);
@@ -471,6 +467,8 @@ static void mwait_idle(void)
__sti_mwait(0, 0);
else
local_irq_enable();
+ trace_power_end(smp_processor_id());
+ trace_cpu_idle(PWR_EVENT_EXIT, smp_processor_id());
} else
local_irq_enable();
}
@@ -503,17 +501,16 @@ static void poll_idle(void)
*
* idle=mwait overrides this decision and forces the usage of mwait.
*/
-static int __cpuinitdata force_mwait;
#define MWAIT_INFO 0x05
#define MWAIT_ECX_EXTENDED_INFO 0x01
#define MWAIT_EDX_C1 0xf0
-static int __cpuinit mwait_usable(const struct cpuinfo_x86 *c)
+int __cpuinit mwait_usable(const struct cpuinfo_x86 *c)
{
u32 eax, ebx, ecx, edx;
- if (force_mwait)
+ if (boot_option_idle_override == IDLE_FORCE_MWAIT)
return 1;
if (c->cpuid_level < MWAIT_INFO)
@@ -633,9 +630,10 @@ static int __init idle_setup(char *str)
if (!strcmp(str, "poll")) {
printk("using polling idle threads.\n");
pm_idle = poll_idle;
- } else if (!strcmp(str, "mwait"))
- force_mwait = 1;
- else if (!strcmp(str, "halt")) {
+ boot_option_idle_override = IDLE_POLL;
+ } else if (!strcmp(str, "mwait")) {
+ boot_option_idle_override = IDLE_FORCE_MWAIT;
+ } else if (!strcmp(str, "halt")) {
/*
* When the boot option of idle=halt is added, halt is
* forced to be used for CPU idle. In such case CPU C2/C3
@@ -644,8 +642,7 @@ static int __init idle_setup(char *str)
* the boot_option_idle_override.
*/
pm_idle = default_idle;
- idle_halt = 1;
- return 0;
+ boot_option_idle_override = IDLE_HALT;
} else if (!strcmp(str, "nomwait")) {
/*
* If the boot option of "idle=nomwait" is added,
@@ -653,12 +650,10 @@ static int __init idle_setup(char *str)
* states. In such case it won't touch the variable
* of boot_option_idle_override.
*/
- idle_nomwait = 1;
- return 0;
+ boot_option_idle_override = IDLE_NOMWAIT;
} else
return -1;
- boot_option_idle_override = 1;
return 0;
}
early_param("idle", idle_setup);
diff --git a/arch/x86/kernel/process_32.c b/arch/x86/kernel/process_32.c
index 4b9befa..8d12878 100644
--- a/arch/x86/kernel/process_32.c
+++ b/arch/x86/kernel/process_32.c
@@ -57,8 +57,6 @@
#include <asm/syscalls.h>
#include <asm/debugreg.h>
-#include <trace/events/power.h>
-
asmlinkage void ret_from_fork(void) __asm__("ret_from_fork");
/*
@@ -113,8 +111,6 @@ void cpu_idle(void)
stop_critical_timings();
pm_idle();
start_critical_timings();
- trace_power_end(smp_processor_id());
- trace_cpu_idle(PWR_EVENT_EXIT, smp_processor_id());
}
tick_nohz_restart_sched_tick();
preempt_enable_no_resched();
diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c
index 4c818a7..bd387e8 100644
--- a/arch/x86/kernel/process_64.c
+++ b/arch/x86/kernel/process_64.c
@@ -51,8 +51,6 @@
#include <asm/syscalls.h>
#include <asm/debugreg.h>
-#include <trace/events/power.h>
-
asmlinkage extern void ret_from_fork(void);
DEFINE_PER_CPU(unsigned long, old_rsp);
@@ -141,10 +139,6 @@ void cpu_idle(void)
pm_idle();
start_critical_timings();
- trace_power_end(smp_processor_id());
- trace_cpu_idle(PWR_EVENT_EXIT,
- smp_processor_id());
-
/* In many cases the interrupt that ended idle
has already called exit_idle. But some idle
loops can be woken up without interrupt. */
diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c
index 763df77..0cbe8c0 100644
--- a/arch/x86/kernel/smpboot.c
+++ b/arch/x86/kernel/smpboot.c
@@ -1402,8 +1402,9 @@ static inline void mwait_play_dead(void)
unsigned int highest_subcstate = 0;
int i;
void *mwait_ptr;
+ struct cpuinfo_x86 *c = __this_cpu_ptr(&cpu_info);
- if (!cpu_has(__this_cpu_ptr(&cpu_info), X86_FEATURE_MWAIT))
+ if (!(cpu_has(c, X86_FEATURE_MWAIT) && mwait_usable(c)))
return;
if (!cpu_has(__this_cpu_ptr(&cpu_info), X86_FEATURE_CLFLSH))
return;
diff --git a/arch/x86/kernel/tsc.c b/arch/x86/kernel/tsc.c
index 823f79a..ffe5755 100644
--- a/arch/x86/kernel/tsc.c
+++ b/arch/x86/kernel/tsc.c
@@ -464,7 +464,7 @@ unsigned long native_calibrate_tsc(void)
tsc_pit_min = min(tsc_pit_min, tsc_pit_khz);
/* hpet or pmtimer available ? */
- if (!hpet && !ref1 && !ref2)
+ if (ref1 == ref2)
continue;
/* Check, whether the sampling was disturbed by an SMI */
@@ -935,7 +935,7 @@ static void tsc_refine_calibration_work(struct work_struct *work)
tsc_stop = tsc_read_refs(&ref_stop, hpet);
/* hpet or pmtimer available ? */
- if (!hpet && !ref_start && !ref_stop)
+ if (ref_start == ref_stop)
goto out;
/* Check, whether the sampling was disturbed by an SMI */
diff --git a/arch/x86/lguest/Kconfig b/arch/x86/lguest/Kconfig
index 3871804..6e121a2 100644
--- a/arch/x86/lguest/Kconfig
+++ b/arch/x86/lguest/Kconfig
@@ -2,6 +2,7 @@ config LGUEST_GUEST
bool "Lguest guest support"
select PARAVIRT
depends on X86_32
+ select VIRTUALIZATION
select VIRTIO
select VIRTIO_RING
select VIRTIO_CONSOLE
diff --git a/arch/x86/lguest/boot.c b/arch/x86/lguest/boot.c
index 4996cf5..eba687f0 100644
--- a/arch/x86/lguest/boot.c
+++ b/arch/x86/lguest/boot.c
@@ -824,7 +824,7 @@ static void __init lguest_init_IRQ(void)
for (i = FIRST_EXTERNAL_VECTOR; i < NR_VECTORS; i++) {
/* Some systems map "vectors" to interrupts weirdly. Not us! */
- __get_cpu_var(vector_irq)[i] = i - FIRST_EXTERNAL_VECTOR;
+ __this_cpu_write(vector_irq[i], i - FIRST_EXTERNAL_VECTOR);
if (i != SYSCALL_VECTOR)
set_intr_gate(i, interrupt[i - FIRST_EXTERNAL_VECTOR]);
}
diff --git a/arch/x86/mm/numa.c b/arch/x86/mm/numa.c
index 787c52c..ebf6d78 100644
--- a/arch/x86/mm/numa.c
+++ b/arch/x86/mm/numa.c
@@ -2,6 +2,28 @@
#include <linux/topology.h>
#include <linux/module.h>
#include <linux/bootmem.h>
+#include <asm/numa.h>
+#include <asm/acpi.h>
+
+int __initdata numa_off;
+
+static __init int numa_setup(char *opt)
+{
+ if (!opt)
+ return -EINVAL;
+ if (!strncmp(opt, "off", 3))
+ numa_off = 1;
+#ifdef CONFIG_NUMA_EMU
+ if (!strncmp(opt, "fake=", 5))
+ numa_emu_cmdline(opt + 5);
+#endif
+#ifdef CONFIG_ACPI_NUMA
+ if (!strncmp(opt, "noacpi", 6))
+ acpi_numa = -1;
+#endif
+ return 0;
+}
+early_param("numa", numa_setup);
/*
* Which logical CPUs are on which nodes
diff --git a/arch/x86/mm/numa_64.c b/arch/x86/mm/numa_64.c
index 1e72102..95ea155 100644
--- a/arch/x86/mm/numa_64.c
+++ b/arch/x86/mm/numa_64.c
@@ -30,7 +30,6 @@ s16 apicid_to_node[MAX_LOCAL_APIC] __cpuinitdata = {
[0 ... MAX_LOCAL_APIC-1] = NUMA_NO_NODE
};
-int numa_off __initdata;
static unsigned long __initdata nodemap_addr;
static unsigned long __initdata nodemap_size;
@@ -263,6 +262,11 @@ static struct bootnode nodes[MAX_NUMNODES] __initdata;
static struct bootnode physnodes[MAX_NUMNODES] __cpuinitdata;
static char *cmdline __initdata;
+void __init numa_emu_cmdline(char *str)
+{
+ cmdline = str;
+}
+
static int __init setup_physnodes(unsigned long start, unsigned long end,
int acpi, int amd)
{
@@ -670,24 +674,6 @@ unsigned long __init numa_free_all_bootmem(void)
return pages;
}
-static __init int numa_setup(char *opt)
-{
- if (!opt)
- return -EINVAL;
- if (!strncmp(opt, "off", 3))
- numa_off = 1;
-#ifdef CONFIG_NUMA_EMU
- if (!strncmp(opt, "fake=", 5))
- cmdline = opt + 5;
-#endif
-#ifdef CONFIG_ACPI_NUMA
- if (!strncmp(opt, "noacpi", 6))
- acpi_numa = -1;
-#endif
- return 0;
-}
-early_param("numa", numa_setup);
-
#ifdef CONFIG_NUMA
static __init int find_near_online_node(int node)
diff --git a/arch/x86/mm/srat_32.c b/arch/x86/mm/srat_32.c
index f164345..ae96e7b8 100644
--- a/arch/x86/mm/srat_32.c
+++ b/arch/x86/mm/srat_32.c
@@ -59,7 +59,6 @@ static struct node_memory_chunk_s __initdata node_memory_chunk[MAXCHUNKS];
static int __initdata num_memory_chunks; /* total number of memory chunks */
static u8 __initdata apicid_to_pxm[MAX_APICID];
-int numa_off __initdata;
int acpi_numa __initdata;
static __init void bad_srat(void)
diff --git a/arch/x86/pci/broadcom_bus.c b/arch/x86/pci/broadcom_bus.c
index 0846a5b..ab8269b 100644
--- a/arch/x86/pci/broadcom_bus.c
+++ b/arch/x86/pci/broadcom_bus.c
@@ -9,6 +9,7 @@
* option) any later version.
*/
+#include <linux/acpi.h>
#include <linux/delay.h>
#include <linux/dmi.h>
#include <linux/pci.h>
@@ -25,12 +26,14 @@ static void __devinit cnb20le_res(struct pci_dev *dev)
u8 fbus, lbus;
int i;
+#ifdef CONFIG_ACPI
/*
- * The x86_pci_root_bus_res_quirks() function already refuses to use
- * this information if ACPI _CRS was used. Therefore, we don't bother
- * checking if ACPI is enabled, and just generate the information
- * for both the ACPI _CRS and no ACPI cases.
+ * We should get host bridge information from ACPI unless the BIOS
+ * doesn't support it.
*/
+ if (acpi_os_get_root_pointer())
+ return;
+#endif
info = &pci_root_info[pci_root_num];
pci_root_num++;
diff --git a/arch/x86/pci/common.c b/arch/x86/pci/common.c
index f7c8a39..5fe7502 100644
--- a/arch/x86/pci/common.c
+++ b/arch/x86/pci/common.c
@@ -22,6 +22,7 @@ unsigned int pci_probe = PCI_PROBE_BIOS | PCI_PROBE_CONF1 | PCI_PROBE_CONF2 |
unsigned int pci_early_dump_regs;
static int pci_bf_sort;
+static int smbios_type_b1_flag;
int pci_routeirq;
int noioapicquirk;
#ifdef CONFIG_X86_REROUTE_FOR_BROKEN_BOOT_IRQS
@@ -185,6 +186,39 @@ static int __devinit set_bf_sort(const struct dmi_system_id *d)
return 0;
}
+static void __devinit read_dmi_type_b1(const struct dmi_header *dm,
+ void *private_data)
+{
+ u8 *d = (u8 *)dm + 4;
+
+ if (dm->type != 0xB1)
+ return;
+ switch (((*(u32 *)d) >> 9) & 0x03) {
+ case 0x00:
+ printk(KERN_INFO "dmi type 0xB1 record - unknown flag\n");
+ break;
+ case 0x01: /* set pci=bfsort */
+ smbios_type_b1_flag = 1;
+ break;
+ case 0x02: /* do not set pci=bfsort */
+ smbios_type_b1_flag = 2;
+ break;
+ default:
+ break;
+ }
+}
+
+static int __devinit find_sort_method(const struct dmi_system_id *d)
+{
+ dmi_walk(read_dmi_type_b1, NULL);
+
+ if (smbios_type_b1_flag == 1) {
+ set_bf_sort(d);
+ return 0;
+ }
+ return -1;
+}
+
/*
* Enable renumbering of PCI bus# ranges to reach all PCI busses (Cardbus)
*/
@@ -213,6 +247,13 @@ static const struct dmi_system_id __devinitconst pciprobe_dmi_table[] = {
},
#endif /* __i386__ */
{
+ .callback = find_sort_method,
+ .ident = "Dell System",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
+ },
+ },
+ {
.callback = set_bf_sort,
.ident = "Dell PowerEdge 1950",
.matches = {
diff --git a/arch/x86/pci/irq.c b/arch/x86/pci/irq.c
index 9f9bfb7..87e6c83 100644
--- a/arch/x86/pci/irq.c
+++ b/arch/x86/pci/irq.c
@@ -589,7 +589,8 @@ static __init int intel_router_probe(struct irq_router *r, struct pci_dev *route
case PCI_DEVICE_ID_INTEL_ICH10_1:
case PCI_DEVICE_ID_INTEL_ICH10_2:
case PCI_DEVICE_ID_INTEL_ICH10_3:
- case PCI_DEVICE_ID_INTEL_PATSBURG_LPC:
+ case PCI_DEVICE_ID_INTEL_PATSBURG_LPC_0:
+ case PCI_DEVICE_ID_INTEL_PATSBURG_LPC_1:
r->name = "PIIX/ICH";
r->get = pirq_piix_get;
r->set = pirq_piix_set;
diff --git a/arch/x86/platform/olpc/olpc-xo1.c b/arch/x86/platform/olpc/olpc-xo1.c
index f5442c0..1277756 100644
--- a/arch/x86/platform/olpc/olpc-xo1.c
+++ b/arch/x86/platform/olpc/olpc-xo1.c
@@ -1,6 +1,7 @@
/*
* Support for features of the OLPC XO-1 laptop
*
+ * Copyright (C) 2010 Andres Salomon <dilinger@queued.net>
* Copyright (C) 2010 One Laptop per Child
* Copyright (C) 2006 Red Hat, Inc.
* Copyright (C) 2006 Advanced Micro Devices, Inc.
@@ -12,8 +13,6 @@
*/
#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/pci_ids.h>
#include <linux/platform_device.h>
#include <linux/pm.h>
@@ -22,9 +21,6 @@
#define DRV_NAME "olpc-xo1"
-#define PMS_BAR 4
-#define ACPI_BAR 5
-
/* PMC registers (PMS block) */
#define PM_SCLK 0x10
#define PM_IN_SLPCTL 0x20
@@ -57,65 +53,67 @@ static void xo1_power_off(void)
outl(0x00002000, acpi_base + PM1_CNT);
}
-/* Read the base addresses from the PCI BAR info */
-static int __devinit setup_bases(struct pci_dev *pdev)
+static int __devinit olpc_xo1_probe(struct platform_device *pdev)
{
- int r;
+ struct resource *res;
- r = pci_enable_device_io(pdev);
- if (r) {
- dev_err(&pdev->dev, "can't enable device IO\n");
- return r;
- }
+ /* don't run on non-XOs */
+ if (!machine_is_olpc())
+ return -ENODEV;
- r = pci_request_region(pdev, ACPI_BAR, DRV_NAME);
- if (r) {
- dev_err(&pdev->dev, "can't alloc PCI BAR #%d\n", ACPI_BAR);
- return r;
+ res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "can't fetch device resource info\n");
+ return -EIO;
}
- r = pci_request_region(pdev, PMS_BAR, DRV_NAME);
- if (r) {
- dev_err(&pdev->dev, "can't alloc PCI BAR #%d\n", PMS_BAR);
- pci_release_region(pdev, ACPI_BAR);
- return r;
+ if (!request_region(res->start, resource_size(res), DRV_NAME)) {
+ dev_err(&pdev->dev, "can't request region\n");
+ return -EIO;
}
- acpi_base = pci_resource_start(pdev, ACPI_BAR);
- pms_base = pci_resource_start(pdev, PMS_BAR);
+ if (strcmp(pdev->name, "cs5535-pms") == 0)
+ pms_base = res->start;
+ else if (strcmp(pdev->name, "cs5535-acpi") == 0)
+ acpi_base = res->start;
+
+ /* If we have both addresses, we can override the poweroff hook */
+ if (pms_base && acpi_base) {
+ pm_power_off = xo1_power_off;
+ printk(KERN_INFO "OLPC XO-1 support registered\n");
+ }
return 0;
}
-static int __devinit olpc_xo1_probe(struct platform_device *pdev)
+static int __devexit olpc_xo1_remove(struct platform_device *pdev)
{
- struct pci_dev *pcidev;
- int r;
-
- pcidev = pci_get_device(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_ISA,
- NULL);
- if (!pdev)
- return -ENODEV;
-
- r = setup_bases(pcidev);
- if (r)
- return r;
+ struct resource *r;
- pm_power_off = xo1_power_off;
+ r = platform_get_resource(pdev, IORESOURCE_IO, 0);
+ release_region(r->start, resource_size(r));
- printk(KERN_INFO "OLPC XO-1 support registered\n");
- return 0;
-}
+ if (strcmp(pdev->name, "cs5535-pms") == 0)
+ pms_base = 0;
+ else if (strcmp(pdev->name, "cs5535-acpi") == 0)
+ acpi_base = 0;
-static int __devexit olpc_xo1_remove(struct platform_device *pdev)
-{
pm_power_off = NULL;
return 0;
}
-static struct platform_driver olpc_xo1_driver = {
+static struct platform_driver cs5535_pms_drv = {
+ .driver = {
+ .name = "cs5535-pms",
+ .owner = THIS_MODULE,
+ },
+ .probe = olpc_xo1_probe,
+ .remove = __devexit_p(olpc_xo1_remove),
+};
+
+static struct platform_driver cs5535_acpi_drv = {
.driver = {
- .name = DRV_NAME,
+ .name = "cs5535-acpi",
.owner = THIS_MODULE,
},
.probe = olpc_xo1_probe,
@@ -124,12 +122,23 @@ static struct platform_driver olpc_xo1_driver = {
static int __init olpc_xo1_init(void)
{
- return platform_driver_register(&olpc_xo1_driver);
+ int r;
+
+ r = platform_driver_register(&cs5535_pms_drv);
+ if (r)
+ return r;
+
+ r = platform_driver_register(&cs5535_acpi_drv);
+ if (r)
+ platform_driver_unregister(&cs5535_pms_drv);
+
+ return r;
}
static void __exit olpc_xo1_exit(void)
{
- platform_driver_unregister(&olpc_xo1_driver);
+ platform_driver_unregister(&cs5535_acpi_drv);
+ platform_driver_unregister(&cs5535_pms_drv);
}
MODULE_AUTHOR("Daniel Drake <dsd@laptop.org>");
diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c
index 7e8d3bc..50542ef 100644
--- a/arch/x86/xen/enlighten.c
+++ b/arch/x86/xen/enlighten.c
@@ -1194,7 +1194,7 @@ asmlinkage void __init xen_start_kernel(void)
per_cpu(xen_vcpu, 0) = &HYPERVISOR_shared_info->vcpu_info[0];
local_irq_disable();
- early_boot_irqs_off();
+ early_boot_irqs_disabled = true;
memblock_init();
diff --git a/arch/x86/xen/irq.c b/arch/x86/xen/irq.c
index 9d30105..6a6fe89 100644
--- a/arch/x86/xen/irq.c
+++ b/arch/x86/xen/irq.c
@@ -126,7 +126,7 @@ static const struct pv_irq_ops xen_irq_ops __initdata = {
#endif
};
-void __init xen_init_irq_ops()
+void __init xen_init_irq_ops(void)
{
pv_irq_ops = xen_irq_ops;
x86_init.irqs.intr_init = xen_init_IRQ;
diff --git a/arch/x86/xen/mmu.c b/arch/x86/xen/mmu.c
index 7575e55..5e92b61 100644
--- a/arch/x86/xen/mmu.c
+++ b/arch/x86/xen/mmu.c
@@ -201,6 +201,7 @@ xmaddr_t arbitrary_virt_to_machine(void *vaddr)
offset = address & ~PAGE_MASK;
return XMADDR(((phys_addr_t)pte_mfn(*pte) << PAGE_SHIFT) + offset);
}
+EXPORT_SYMBOL_GPL(arbitrary_virt_to_machine);
void make_lowmem_page_readonly(void *vaddr)
{
diff --git a/arch/x86/xen/p2m.c b/arch/x86/xen/p2m.c
index 8f2251d..ddc81a0 100644
--- a/arch/x86/xen/p2m.c
+++ b/arch/x86/xen/p2m.c
@@ -237,7 +237,25 @@ void __init xen_build_dynamic_phys_to_machine(void)
p2m_top[topidx] = mid;
}
- p2m_top[topidx][mididx] = &mfn_list[pfn];
+ /*
+ * As long as the mfn_list has enough entries to completely
+ * fill a p2m page, pointing into the array is ok. But if
+ * not the entries beyond the last pfn will be undefined.
+ * And guessing that the 'what-ever-there-is' does not take it
+ * too kindly when changing it to invalid markers, a new page
+ * is allocated, initialized and filled with the valid part.
+ */
+ if (unlikely(pfn + P2M_PER_PAGE > max_pfn)) {
+ unsigned long p2midx;
+ unsigned long *p2m = extend_brk(PAGE_SIZE, PAGE_SIZE);
+ p2m_init(p2m);
+
+ for (p2midx = 0; pfn + p2midx < max_pfn; p2midx++) {
+ p2m[p2midx] = mfn_list[pfn + p2midx];
+ }
+ p2m_top[topidx][mididx] = p2m;
+ } else
+ p2m_top[topidx][mididx] = &mfn_list[pfn];
}
m2p_override_init();
diff --git a/arch/xtensa/configs/common_defconfig b/arch/xtensa/configs/common_defconfig
index 1d230ee..b90038e 100644
--- a/arch/xtensa/configs/common_defconfig
+++ b/arch/xtensa/configs/common_defconfig
@@ -32,7 +32,7 @@ CONFIG_LOG_BUF_SHIFT=14
# CONFIG_HOTPLUG is not set
CONFIG_KOBJECT_UEVENT=y
# CONFIG_IKCONFIG is not set
-# CONFIG_EMBEDDED is not set
+# CONFIG_EXPERT is not set
CONFIG_KALLSYMS=y
# CONFIG_KALLSYMS_ALL is not set
# CONFIG_KALLSYMS_EXTRA_PASS is not set
diff --git a/arch/xtensa/configs/iss_defconfig b/arch/xtensa/configs/iss_defconfig
index 7368164..0234cd1 100644
--- a/arch/xtensa/configs/iss_defconfig
+++ b/arch/xtensa/configs/iss_defconfig
@@ -55,7 +55,7 @@ CONFIG_LOG_BUF_SHIFT=14
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
CONFIG_SYSCTL=y
CONFIG_ANON_INODES=y
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
CONFIG_SYSCTL_SYSCALL=y
CONFIG_KALLSYMS=y
# CONFIG_KALLSYMS_ALL is not set
diff --git a/arch/xtensa/configs/s6105_defconfig b/arch/xtensa/configs/s6105_defconfig
index bb84fbc..095cd80 100644
--- a/arch/xtensa/configs/s6105_defconfig
+++ b/arch/xtensa/configs/s6105_defconfig
@@ -55,7 +55,7 @@ CONFIG_BLK_DEV_INITRD=y
CONFIG_INITRAMFS_SOURCE=""
CONFIG_CC_OPTIMIZE_FOR_SIZE=y
CONFIG_SYSCTL=y
-CONFIG_EMBEDDED=y
+CONFIG_EXPERT=y
CONFIG_SYSCTL_SYSCALL=y
CONFIG_KALLSYMS=y
# CONFIG_KALLSYMS_ALL is not set
diff --git a/block/Kconfig b/block/Kconfig
index 6c9213e..60be1e0 100644
--- a/block/Kconfig
+++ b/block/Kconfig
@@ -2,7 +2,7 @@
# Block layer core configuration
#
menuconfig BLOCK
- bool "Enable the block layer" if EMBEDDED
+ bool "Enable the block layer" if EXPERT
default y
help
Provide block layer support for the kernel.
diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c
index 8427697..501ffdf 100644
--- a/block/cfq-iosched.c
+++ b/block/cfq-iosched.c
@@ -598,8 +598,8 @@ cfq_group_slice(struct cfq_data *cfqd, struct cfq_group *cfqg)
return cfq_target_latency * cfqg->weight / st->total_weight;
}
-static inline void
-cfq_set_prio_slice(struct cfq_data *cfqd, struct cfq_queue *cfqq)
+static inline unsigned
+cfq_scaled_group_slice(struct cfq_data *cfqd, struct cfq_queue *cfqq)
{
unsigned slice = cfq_prio_to_slice(cfqd, cfqq);
if (cfqd->cfq_latency) {
@@ -625,6 +625,14 @@ cfq_set_prio_slice(struct cfq_data *cfqd, struct cfq_queue *cfqq)
low_slice);
}
}
+ return slice;
+}
+
+static inline void
+cfq_set_prio_slice(struct cfq_data *cfqd, struct cfq_queue *cfqq)
+{
+ unsigned slice = cfq_scaled_group_slice(cfqd, cfqq);
+
cfqq->slice_start = jiffies;
cfqq->slice_end = jiffies + slice;
cfqq->allocated_slice = slice;
@@ -1661,8 +1669,11 @@ __cfq_slice_expired(struct cfq_data *cfqd, struct cfq_queue *cfqq,
/*
* store what was left of this slice, if the queue idled/timed out
*/
- if (timed_out && !cfq_cfqq_slice_new(cfqq)) {
- cfqq->slice_resid = cfqq->slice_end - jiffies;
+ if (timed_out) {
+ if (cfq_cfqq_slice_new(cfqq))
+ cfqq->slice_resid = cfq_scaled_group_slice(cfqd, cfqq);
+ else
+ cfqq->slice_resid = cfqq->slice_end - jiffies;
cfq_log_cfqq(cfqd, cfqq, "resid=%ld", cfqq->slice_resid);
}
@@ -3284,10 +3295,19 @@ cfq_should_preempt(struct cfq_data *cfqd, struct cfq_queue *new_cfqq,
*/
static void cfq_preempt_queue(struct cfq_data *cfqd, struct cfq_queue *cfqq)
{
+ struct cfq_queue *old_cfqq = cfqd->active_queue;
+
cfq_log_cfqq(cfqd, cfqq, "preempt");
cfq_slice_expired(cfqd, 1);
/*
+ * workload type is changed, don't save slice, otherwise preempt
+ * doesn't happen
+ */
+ if (cfqq_type(old_cfqq) != cfqq_type(cfqq))
+ cfqq->cfqg->saved_workload_slice = 0;
+
+ /*
* Put the new queue at the front of the of the current list,
* so we know that it will be selected next.
*/
diff --git a/drivers/Kconfig b/drivers/Kconfig
index dd0a5b5..9bfb71f 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -26,6 +26,8 @@ source "drivers/ata/Kconfig"
source "drivers/md/Kconfig"
+source "drivers/target/Kconfig"
+
source "drivers/message/fusion/Kconfig"
source "drivers/firewire/Kconfig"
diff --git a/drivers/Makefile b/drivers/Makefile
index ef51324..b423bb1 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -24,7 +24,7 @@ obj-$(CONFIG_XEN) += xen/
# regulators early, since some subsystems rely on them to initialize
obj-$(CONFIG_REGULATOR) += regulator/
-# char/ comes before serial/ etc so that the VT console is the boot-time
+# tty/ comes before char/ so that the VT console is the boot-time
# default.
obj-y += tty/
obj-y += char/
@@ -38,7 +38,6 @@ obj-$(CONFIG_CONNECTOR) += connector/
obj-$(CONFIG_FB_I810) += video/i810/
obj-$(CONFIG_FB_INTEL) += video/intelfb/
-obj-y += serial/
obj-$(CONFIG_PARPORT) += parport/
obj-y += base/ block/ misc/ mfd/ nfc/
obj-$(CONFIG_NUBUS) += nubus/
@@ -46,6 +45,7 @@ obj-y += macintosh/
obj-$(CONFIG_IDE) += ide/
obj-$(CONFIG_SCSI) += scsi/
obj-$(CONFIG_ATA) += ata/
+obj-$(CONFIG_TARGET_CORE) += target/
obj-$(CONFIG_MTD) += mtd/
obj-$(CONFIG_SPI) += spi/
obj-y += net/
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index 3f3489c..2aa042a 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -51,12 +51,7 @@ config ACPI_PROCFS
For backwards compatibility, this option allows
deprecated /proc/acpi/ files to exist, even when
they have been replaced by functions in /sys.
- The deprecated files (and their replacements) include:
- /proc/acpi/processor/*/throttling (/sys/class/thermal/
- cooling_device*/*)
- /proc/acpi/video/*/brightness (/sys/class/backlight/)
- /proc/acpi/thermal_zone/*/* (/sys/class/thermal/)
This option has no effect on /proc/acpi/ files
and functions which do not yet exist in /sys.
@@ -74,6 +69,8 @@ config ACPI_PROCFS_POWER
/proc/acpi/ac_adapter/* (sys/class/power_supply/*)
This option has no effect on /proc/acpi/ directories
and functions, which do not yet exist in /sys
+ This option, together with the proc directories, will be
+ deleted in 2.6.39.
Say N to delete power /proc/acpi/ directories that have moved to /sys/
@@ -209,6 +206,17 @@ config ACPI_PROCESSOR
To compile this driver as a module, choose M here:
the module will be called processor.
+config ACPI_IPMI
+ tristate "IPMI"
+ depends on EXPERIMENTAL && IPMI_SI && IPMI_HANDLER
+ default n
+ help
+ This driver enables the ACPI to access the BMC controller. And it
+ uses the IPMI request/response message to communicate with BMC
+ controller, which can be found on on the server.
+
+ To compile this driver as a module, choose M here:
+ the module will be called as acpi_ipmi.
config ACPI_HOTPLUG_CPU
bool
@@ -310,7 +318,7 @@ config ACPI_PCI_SLOT
the module will be called pci_slot.
config X86_PM_TIMER
- bool "Power Management Timer Support" if EMBEDDED
+ bool "Power Management Timer Support" if EXPERT
depends on X86
default y
help
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index 3d031d0..d113fa5 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -24,7 +24,7 @@ acpi-y += atomicio.o
# sleep related files
acpi-y += wakeup.o
acpi-y += sleep.o
-acpi-$(CONFIG_ACPI_SLEEP) += proc.o
+acpi-$(CONFIG_ACPI_SLEEP) += proc.o nvs.o
#
@@ -69,5 +69,6 @@ processor-y += processor_idle.o processor_thermal.o
processor-$(CONFIG_CPU_FREQ) += processor_perflib.o
obj-$(CONFIG_ACPI_PROCESSOR_AGGREGATOR) += acpi_pad.o
+obj-$(CONFIG_ACPI_IPMI) += acpi_ipmi.o
obj-$(CONFIG_ACPI_APEI) += apei/
diff --git a/drivers/acpi/ac.c b/drivers/acpi/ac.c
index 25d3aae..58c3f74 100644
--- a/drivers/acpi/ac.c
+++ b/drivers/acpi/ac.c
@@ -197,7 +197,8 @@ static int acpi_ac_add_fs(struct acpi_device *device)
{
struct proc_dir_entry *entry = NULL;
-
+ printk(KERN_WARNING PREFIX "Deprecated procfs I/F for AC is loaded,"
+ " please retry with CONFIG_ACPI_PROCFS_POWER cleared\n");
if (!acpi_device_dir(device)) {
acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device),
acpi_ac_dir);
diff --git a/drivers/acpi/acpi_ipmi.c b/drivers/acpi/acpi_ipmi.c
new file mode 100644
index 0000000..f40acef
--- /dev/null
+++ b/drivers/acpi/acpi_ipmi.c
@@ -0,0 +1,525 @@
+/*
+ * acpi_ipmi.c - ACPI IPMI opregion
+ *
+ * Copyright (C) 2010 Intel Corporation
+ * Copyright (C) 2010 Zhao Yakui <yakui.zhao@intel.com>
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/io.h>
+#include <acpi/acpi_bus.h>
+#include <acpi/acpi_drivers.h>
+#include <linux/ipmi.h>
+#include <linux/device.h>
+#include <linux/pnp.h>
+
+MODULE_AUTHOR("Zhao Yakui");
+MODULE_DESCRIPTION("ACPI IPMI Opregion driver");
+MODULE_LICENSE("GPL");
+
+#define IPMI_FLAGS_HANDLER_INSTALL 0
+
+#define ACPI_IPMI_OK 0
+#define ACPI_IPMI_TIMEOUT 0x10
+#define ACPI_IPMI_UNKNOWN 0x07
+/* the IPMI timeout is 5s */
+#define IPMI_TIMEOUT (5 * HZ)
+
+struct acpi_ipmi_device {
+ /* the device list attached to driver_data.ipmi_devices */
+ struct list_head head;
+ /* the IPMI request message list */
+ struct list_head tx_msg_list;
+ struct mutex tx_msg_lock;
+ acpi_handle handle;
+ struct pnp_dev *pnp_dev;
+ ipmi_user_t user_interface;
+ int ipmi_ifnum; /* IPMI interface number */
+ long curr_msgid;
+ unsigned long flags;
+ struct ipmi_smi_info smi_data;
+};
+
+struct ipmi_driver_data {
+ struct list_head ipmi_devices;
+ struct ipmi_smi_watcher bmc_events;
+ struct ipmi_user_hndl ipmi_hndlrs;
+ struct mutex ipmi_lock;
+};
+
+struct acpi_ipmi_msg {
+ struct list_head head;
+ /*
+ * General speaking the addr type should be SI_ADDR_TYPE. And
+ * the addr channel should be BMC.
+ * In fact it can also be IPMB type. But we will have to
+ * parse it from the Netfn command buffer. It is so complex
+ * that it is skipped.
+ */
+ struct ipmi_addr addr;
+ long tx_msgid;
+ /* it is used to track whether the IPMI message is finished */
+ struct completion tx_complete;
+ struct kernel_ipmi_msg tx_message;
+ int msg_done;
+ /* tx data . And copy it from ACPI object buffer */
+ u8 tx_data[64];
+ int tx_len;
+ u8 rx_data[64];
+ int rx_len;
+ struct acpi_ipmi_device *device;
+};
+
+/* IPMI request/response buffer per ACPI 4.0, sec 5.5.2.4.3.2 */
+struct acpi_ipmi_buffer {
+ u8 status;
+ u8 length;
+ u8 data[64];
+};
+
+static void ipmi_register_bmc(int iface, struct device *dev);
+static void ipmi_bmc_gone(int iface);
+static void ipmi_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data);
+static void acpi_add_ipmi_device(struct acpi_ipmi_device *ipmi_device);
+static void acpi_remove_ipmi_device(struct acpi_ipmi_device *ipmi_device);
+
+static struct ipmi_driver_data driver_data = {
+ .ipmi_devices = LIST_HEAD_INIT(driver_data.ipmi_devices),
+ .bmc_events = {
+ .owner = THIS_MODULE,
+ .new_smi = ipmi_register_bmc,
+ .smi_gone = ipmi_bmc_gone,
+ },
+ .ipmi_hndlrs = {
+ .ipmi_recv_hndl = ipmi_msg_handler,
+ },
+};
+
+static struct acpi_ipmi_msg *acpi_alloc_ipmi_msg(struct acpi_ipmi_device *ipmi)
+{
+ struct acpi_ipmi_msg *ipmi_msg;
+ struct pnp_dev *pnp_dev = ipmi->pnp_dev;
+
+ ipmi_msg = kzalloc(sizeof(struct acpi_ipmi_msg), GFP_KERNEL);
+ if (!ipmi_msg) {
+ dev_warn(&pnp_dev->dev, "Can't allocate memory for ipmi_msg\n");
+ return NULL;
+ }
+ init_completion(&ipmi_msg->tx_complete);
+ INIT_LIST_HEAD(&ipmi_msg->head);
+ ipmi_msg->device = ipmi;
+ return ipmi_msg;
+}
+
+#define IPMI_OP_RGN_NETFN(offset) ((offset >> 8) & 0xff)
+#define IPMI_OP_RGN_CMD(offset) (offset & 0xff)
+static void acpi_format_ipmi_msg(struct acpi_ipmi_msg *tx_msg,
+ acpi_physical_address address,
+ acpi_integer *value)
+{
+ struct kernel_ipmi_msg *msg;
+ struct acpi_ipmi_buffer *buffer;
+ struct acpi_ipmi_device *device;
+
+ msg = &tx_msg->tx_message;
+ /*
+ * IPMI network function and command are encoded in the address
+ * within the IPMI OpRegion; see ACPI 4.0, sec 5.5.2.4.3.
+ */
+ msg->netfn = IPMI_OP_RGN_NETFN(address);
+ msg->cmd = IPMI_OP_RGN_CMD(address);
+ msg->data = tx_msg->tx_data;
+ /*
+ * value is the parameter passed by the IPMI opregion space handler.
+ * It points to the IPMI request message buffer
+ */
+ buffer = (struct acpi_ipmi_buffer *)value;
+ /* copy the tx message data */
+ msg->data_len = buffer->length;
+ memcpy(tx_msg->tx_data, buffer->data, msg->data_len);
+ /*
+ * now the default type is SYSTEM_INTERFACE and channel type is BMC.
+ * If the netfn is APP_REQUEST and the cmd is SEND_MESSAGE,
+ * the addr type should be changed to IPMB. Then we will have to parse
+ * the IPMI request message buffer to get the IPMB address.
+ * If so, please fix me.
+ */
+ tx_msg->addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
+ tx_msg->addr.channel = IPMI_BMC_CHANNEL;
+ tx_msg->addr.data[0] = 0;
+
+ /* Get the msgid */
+ device = tx_msg->device;
+ mutex_lock(&device->tx_msg_lock);
+ device->curr_msgid++;
+ tx_msg->tx_msgid = device->curr_msgid;
+ mutex_unlock(&device->tx_msg_lock);
+}
+
+static void acpi_format_ipmi_response(struct acpi_ipmi_msg *msg,
+ acpi_integer *value, int rem_time)
+{
+ struct acpi_ipmi_buffer *buffer;
+
+ /*
+ * value is also used as output parameter. It represents the response
+ * IPMI message returned by IPMI command.
+ */
+ buffer = (struct acpi_ipmi_buffer *)value;
+ if (!rem_time && !msg->msg_done) {
+ buffer->status = ACPI_IPMI_TIMEOUT;
+ return;
+ }
+ /*
+ * If the flag of msg_done is not set or the recv length is zero, it
+ * means that the IPMI command is not executed correctly.
+ * The status code will be ACPI_IPMI_UNKNOWN.
+ */
+ if (!msg->msg_done || !msg->rx_len) {
+ buffer->status = ACPI_IPMI_UNKNOWN;
+ return;
+ }
+ /*
+ * If the IPMI response message is obtained correctly, the status code
+ * will be ACPI_IPMI_OK
+ */
+ buffer->status = ACPI_IPMI_OK;
+ buffer->length = msg->rx_len;
+ memcpy(buffer->data, msg->rx_data, msg->rx_len);
+}
+
+static void ipmi_flush_tx_msg(struct acpi_ipmi_device *ipmi)
+{
+ struct acpi_ipmi_msg *tx_msg, *temp;
+ int count = HZ / 10;
+ struct pnp_dev *pnp_dev = ipmi->pnp_dev;
+
+ list_for_each_entry_safe(tx_msg, temp, &ipmi->tx_msg_list, head) {
+ /* wake up the sleep thread on the Tx msg */
+ complete(&tx_msg->tx_complete);
+ }
+
+ /* wait for about 100ms to flush the tx message list */
+ while (count--) {
+ if (list_empty(&ipmi->tx_msg_list))
+ break;
+ schedule_timeout(1);
+ }
+ if (!list_empty(&ipmi->tx_msg_list))
+ dev_warn(&pnp_dev->dev, "tx msg list is not NULL\n");
+}
+
+static void ipmi_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data)
+{
+ struct acpi_ipmi_device *ipmi_device = user_msg_data;
+ int msg_found = 0;
+ struct acpi_ipmi_msg *tx_msg;
+ struct pnp_dev *pnp_dev = ipmi_device->pnp_dev;
+
+ if (msg->user != ipmi_device->user_interface) {
+ dev_warn(&pnp_dev->dev, "Unexpected response is returned. "
+ "returned user %p, expected user %p\n",
+ msg->user, ipmi_device->user_interface);
+ ipmi_free_recv_msg(msg);
+ return;
+ }
+ mutex_lock(&ipmi_device->tx_msg_lock);
+ list_for_each_entry(tx_msg, &ipmi_device->tx_msg_list, head) {
+ if (msg->msgid == tx_msg->tx_msgid) {
+ msg_found = 1;
+ break;
+ }
+ }
+
+ mutex_unlock(&ipmi_device->tx_msg_lock);
+ if (!msg_found) {
+ dev_warn(&pnp_dev->dev, "Unexpected response (msg id %ld) is "
+ "returned.\n", msg->msgid);
+ ipmi_free_recv_msg(msg);
+ return;
+ }
+
+ if (msg->msg.data_len) {
+ /* copy the response data to Rx_data buffer */
+ memcpy(tx_msg->rx_data, msg->msg_data, msg->msg.data_len);
+ tx_msg->rx_len = msg->msg.data_len;
+ tx_msg->msg_done = 1;
+ }
+ complete(&tx_msg->tx_complete);
+ ipmi_free_recv_msg(msg);
+};
+
+static void ipmi_register_bmc(int iface, struct device *dev)
+{
+ struct acpi_ipmi_device *ipmi_device, *temp;
+ struct pnp_dev *pnp_dev;
+ ipmi_user_t user;
+ int err;
+ struct ipmi_smi_info smi_data;
+ acpi_handle handle;
+
+ err = ipmi_get_smi_info(iface, &smi_data);
+
+ if (err)
+ return;
+
+ if (smi_data.addr_src != SI_ACPI) {
+ put_device(smi_data.dev);
+ return;
+ }
+
+ handle = smi_data.addr_info.acpi_info.acpi_handle;
+
+ mutex_lock(&driver_data.ipmi_lock);
+ list_for_each_entry(temp, &driver_data.ipmi_devices, head) {
+ /*
+ * if the corresponding ACPI handle is already added
+ * to the device list, don't add it again.
+ */
+ if (temp->handle == handle)
+ goto out;
+ }
+
+ ipmi_device = kzalloc(sizeof(*ipmi_device), GFP_KERNEL);
+
+ if (!ipmi_device)
+ goto out;
+
+ pnp_dev = to_pnp_dev(smi_data.dev);
+ ipmi_device->handle = handle;
+ ipmi_device->pnp_dev = pnp_dev;
+
+ err = ipmi_create_user(iface, &driver_data.ipmi_hndlrs,
+ ipmi_device, &user);
+ if (err) {
+ dev_warn(&pnp_dev->dev, "Can't create IPMI user interface\n");
+ kfree(ipmi_device);
+ goto out;
+ }
+ acpi_add_ipmi_device(ipmi_device);
+ ipmi_device->user_interface = user;
+ ipmi_device->ipmi_ifnum = iface;
+ mutex_unlock(&driver_data.ipmi_lock);
+ memcpy(&ipmi_device->smi_data, &smi_data, sizeof(struct ipmi_smi_info));
+ return;
+
+out:
+ mutex_unlock(&driver_data.ipmi_lock);
+ put_device(smi_data.dev);
+ return;
+}
+
+static void ipmi_bmc_gone(int iface)
+{
+ struct acpi_ipmi_device *ipmi_device, *temp;
+
+ mutex_lock(&driver_data.ipmi_lock);
+ list_for_each_entry_safe(ipmi_device, temp,
+ &driver_data.ipmi_devices, head) {
+ if (ipmi_device->ipmi_ifnum != iface)
+ continue;
+
+ acpi_remove_ipmi_device(ipmi_device);
+ put_device(ipmi_device->smi_data.dev);
+ kfree(ipmi_device);
+ break;
+ }
+ mutex_unlock(&driver_data.ipmi_lock);
+}
+/* --------------------------------------------------------------------------
+ * Address Space Management
+ * -------------------------------------------------------------------------- */
+/*
+ * This is the IPMI opregion space handler.
+ * @function: indicates the read/write. In fact as the IPMI message is driven
+ * by command, only write is meaningful.
+ * @address: This contains the netfn/command of IPMI request message.
+ * @bits : not used.
+ * @value : it is an in/out parameter. It points to the IPMI message buffer.
+ * Before the IPMI message is sent, it represents the actual request
+ * IPMI message. After the IPMI message is finished, it represents
+ * the response IPMI message returned by IPMI command.
+ * @handler_context: IPMI device context.
+ */
+
+static acpi_status
+acpi_ipmi_space_handler(u32 function, acpi_physical_address address,
+ u32 bits, acpi_integer *value,
+ void *handler_context, void *region_context)
+{
+ struct acpi_ipmi_msg *tx_msg;
+ struct acpi_ipmi_device *ipmi_device = handler_context;
+ int err, rem_time;
+ acpi_status status;
+ /*
+ * IPMI opregion message.
+ * IPMI message is firstly written to the BMC and system software
+ * can get the respsonse. So it is unmeaningful for the read access
+ * of IPMI opregion.
+ */
+ if ((function & ACPI_IO_MASK) == ACPI_READ)
+ return AE_TYPE;
+
+ if (!ipmi_device->user_interface)
+ return AE_NOT_EXIST;
+
+ tx_msg = acpi_alloc_ipmi_msg(ipmi_device);
+ if (!tx_msg)
+ return AE_NO_MEMORY;
+
+ acpi_format_ipmi_msg(tx_msg, address, value);
+ mutex_lock(&ipmi_device->tx_msg_lock);
+ list_add_tail(&tx_msg->head, &ipmi_device->tx_msg_list);
+ mutex_unlock(&ipmi_device->tx_msg_lock);
+ err = ipmi_request_settime(ipmi_device->user_interface,
+ &tx_msg->addr,
+ tx_msg->tx_msgid,
+ &tx_msg->tx_message,
+ NULL, 0, 0, 0);
+ if (err) {
+ status = AE_ERROR;
+ goto end_label;
+ }
+ rem_time = wait_for_completion_timeout(&tx_msg->tx_complete,
+ IPMI_TIMEOUT);
+ acpi_format_ipmi_response(tx_msg, value, rem_time);
+ status = AE_OK;
+
+end_label:
+ mutex_lock(&ipmi_device->tx_msg_lock);
+ list_del(&tx_msg->head);
+ mutex_unlock(&ipmi_device->tx_msg_lock);
+ kfree(tx_msg);
+ return status;
+}
+
+static void ipmi_remove_space_handler(struct acpi_ipmi_device *ipmi)
+{
+ if (!test_bit(IPMI_FLAGS_HANDLER_INSTALL, &ipmi->flags))
+ return;
+
+ acpi_remove_address_space_handler(ipmi->handle,
+ ACPI_ADR_SPACE_IPMI, &acpi_ipmi_space_handler);
+
+ clear_bit(IPMI_FLAGS_HANDLER_INSTALL, &ipmi->flags);
+}
+
+static int ipmi_install_space_handler(struct acpi_ipmi_device *ipmi)
+{
+ acpi_status status;
+
+ if (test_bit(IPMI_FLAGS_HANDLER_INSTALL, &ipmi->flags))
+ return 0;
+
+ status = acpi_install_address_space_handler(ipmi->handle,
+ ACPI_ADR_SPACE_IPMI,
+ &acpi_ipmi_space_handler,
+ NULL, ipmi);
+ if (ACPI_FAILURE(status)) {
+ struct pnp_dev *pnp_dev = ipmi->pnp_dev;
+ dev_warn(&pnp_dev->dev, "Can't register IPMI opregion space "
+ "handle\n");
+ return -EINVAL;
+ }
+ set_bit(IPMI_FLAGS_HANDLER_INSTALL, &ipmi->flags);
+ return 0;
+}
+
+static void acpi_add_ipmi_device(struct acpi_ipmi_device *ipmi_device)
+{
+
+ INIT_LIST_HEAD(&ipmi_device->head);
+
+ mutex_init(&ipmi_device->tx_msg_lock);
+ INIT_LIST_HEAD(&ipmi_device->tx_msg_list);
+ ipmi_install_space_handler(ipmi_device);
+
+ list_add_tail(&ipmi_device->head, &driver_data.ipmi_devices);
+}
+
+static void acpi_remove_ipmi_device(struct acpi_ipmi_device *ipmi_device)
+{
+ /*
+ * If the IPMI user interface is created, it should be
+ * destroyed.
+ */
+ if (ipmi_device->user_interface) {
+ ipmi_destroy_user(ipmi_device->user_interface);
+ ipmi_device->user_interface = NULL;
+ }
+ /* flush the Tx_msg list */
+ if (!list_empty(&ipmi_device->tx_msg_list))
+ ipmi_flush_tx_msg(ipmi_device);
+
+ list_del(&ipmi_device->head);
+ ipmi_remove_space_handler(ipmi_device);
+}
+
+static int __init acpi_ipmi_init(void)
+{
+ int result = 0;
+
+ if (acpi_disabled)
+ return result;
+
+ mutex_init(&driver_data.ipmi_lock);
+
+ result = ipmi_smi_watcher_register(&driver_data.bmc_events);
+
+ return result;
+}
+
+static void __exit acpi_ipmi_exit(void)
+{
+ struct acpi_ipmi_device *ipmi_device, *temp;
+
+ if (acpi_disabled)
+ return;
+
+ ipmi_smi_watcher_unregister(&driver_data.bmc_events);
+
+ /*
+ * When one smi_watcher is unregistered, it is only deleted
+ * from the smi_watcher list. But the smi_gone callback function
+ * is not called. So explicitly uninstall the ACPI IPMI oregion
+ * handler and free it.
+ */
+ mutex_lock(&driver_data.ipmi_lock);
+ list_for_each_entry_safe(ipmi_device, temp,
+ &driver_data.ipmi_devices, head) {
+ acpi_remove_ipmi_device(ipmi_device);
+ put_device(ipmi_device->smi_data.dev);
+ kfree(ipmi_device);
+ }
+ mutex_unlock(&driver_data.ipmi_lock);
+}
+
+module_init(acpi_ipmi_init);
+module_exit(acpi_ipmi_exit);
diff --git a/drivers/acpi/acpica/Makefile b/drivers/acpi/acpica/Makefile
index a7e1d1a..eec2ead 100644
--- a/drivers/acpi/acpica/Makefile
+++ b/drivers/acpi/acpica/Makefile
@@ -14,7 +14,7 @@ acpi-y := dsfield.o dsmthdat.o dsopcode.o dswexec.o dswscope.o \
acpi-y += evevent.o evregion.o evsci.o evxfevnt.o \
evmisc.o evrgnini.o evxface.o evxfregn.o \
- evgpe.o evgpeblk.o evgpeinit.o evgpeutil.o
+ evgpe.o evgpeblk.o evgpeinit.o evgpeutil.o evxfgpe.o
acpi-y += exconfig.o exfield.o exnames.o exoparg6.o exresolv.o exstorob.o\
exconvrt.o exfldio.o exoparg1.o exprep.o exresop.o exsystem.o\
diff --git a/drivers/acpi/acpica/accommon.h b/drivers/acpi/acpica/accommon.h
index 3e50c74..e0ba17f 100644
--- a/drivers/acpi/acpica/accommon.h
+++ b/drivers/acpi/acpica/accommon.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/acconfig.h b/drivers/acpi/acpica/acconfig.h
index b17d8de..ab87396 100644
--- a/drivers/acpi/acpica/acconfig.h
+++ b/drivers/acpi/acpica/acconfig.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/acdebug.h b/drivers/acpi/acpica/acdebug.h
index 72e9d5e..eb0b1f8 100644
--- a/drivers/acpi/acpica/acdebug.h
+++ b/drivers/acpi/acpica/acdebug.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/acdispat.h b/drivers/acpi/acpica/acdispat.h
index 894a0ff..666271b 100644
--- a/drivers/acpi/acpica/acdispat.h
+++ b/drivers/acpi/acpica/acdispat.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/acevents.h b/drivers/acpi/acpica/acevents.h
index a6f99cc..41d247d 100644
--- a/drivers/acpi/acpica/acevents.h
+++ b/drivers/acpi/acpica/acevents.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -51,8 +51,6 @@ acpi_status acpi_ev_initialize_events(void);
acpi_status acpi_ev_install_xrupt_handlers(void);
-acpi_status acpi_ev_install_fadt_gpes(void);
-
u32 acpi_ev_fixed_event_detect(void);
/*
@@ -82,9 +80,9 @@ acpi_ev_update_gpe_enable_mask(struct acpi_gpe_event_info *gpe_event_info);
acpi_status acpi_ev_enable_gpe(struct acpi_gpe_event_info *gpe_event_info);
-acpi_status acpi_raw_enable_gpe(struct acpi_gpe_event_info *gpe_event_info);
+acpi_status acpi_ev_add_gpe_reference(struct acpi_gpe_event_info *gpe_event_info);
-acpi_status acpi_raw_disable_gpe(struct acpi_gpe_event_info *gpe_event_info);
+acpi_status acpi_ev_remove_gpe_reference(struct acpi_gpe_event_info *gpe_event_info);
struct acpi_gpe_event_info *acpi_ev_get_gpe_event_info(acpi_handle gpe_device,
u32 gpe_number);
@@ -93,6 +91,8 @@ struct acpi_gpe_event_info *acpi_ev_low_get_gpe_info(u32 gpe_number,
struct acpi_gpe_block_info
*gpe_block);
+acpi_status acpi_ev_finish_gpe(struct acpi_gpe_event_info *gpe_event_info);
+
/*
* evgpeblk - Upper-level GPE block support
*/
@@ -107,12 +107,13 @@ acpi_ev_create_gpe_block(struct acpi_namespace_node *gpe_device,
acpi_status
acpi_ev_initialize_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
struct acpi_gpe_block_info *gpe_block,
- void *ignored);
+ void *context);
acpi_status acpi_ev_delete_gpe_block(struct acpi_gpe_block_info *gpe_block);
u32
-acpi_ev_gpe_dispatch(struct acpi_gpe_event_info *gpe_event_info,
+acpi_ev_gpe_dispatch(struct acpi_namespace_node *gpe_device,
+ struct acpi_gpe_event_info *gpe_event_info,
u32 gpe_number);
/*
@@ -126,10 +127,6 @@ acpi_status
acpi_ev_match_gpe_method(acpi_handle obj_handle,
u32 level, void *context, void **return_value);
-acpi_status
-acpi_ev_match_prw_and_gpe(acpi_handle obj_handle,
- u32 level, void *context, void **return_value);
-
/*
* evgpeutil - GPE utilities
*/
@@ -138,6 +135,10 @@ acpi_ev_walk_gpe_list(acpi_gpe_callback gpe_walk_callback, void *context);
u8 acpi_ev_valid_gpe_event(struct acpi_gpe_event_info *gpe_event_info);
+acpi_status
+acpi_ev_get_gpe_device(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
+ struct acpi_gpe_block_info *gpe_block, void *context);
+
struct acpi_gpe_xrupt_info *acpi_ev_get_gpe_xrupt_block(u32 interrupt_number);
acpi_status acpi_ev_delete_gpe_xrupt(struct acpi_gpe_xrupt_info *gpe_xrupt);
diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h
index ad88fca..82a1bd2 100644
--- a/drivers/acpi/acpica/acglobal.h
+++ b/drivers/acpi/acpica/acglobal.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -146,6 +146,9 @@ u8 acpi_gbl_system_awake_and_running;
extern u32 acpi_gbl_nesting_level;
+ACPI_EXTERN u32 acpi_gpe_count;
+ACPI_EXTERN u32 acpi_fixed_event_count[ACPI_NUM_FIXED_EVENTS];
+
/* Support for dynamic control method tracing mechanism */
ACPI_EXTERN u32 acpi_gbl_original_dbg_level;
@@ -225,8 +228,10 @@ ACPI_EXTERN u8 acpi_gbl_global_lock_present;
*/
ACPI_EXTERN spinlock_t _acpi_gbl_gpe_lock; /* For GPE data structs and registers */
ACPI_EXTERN spinlock_t _acpi_gbl_hardware_lock; /* For ACPI H/W except GPE registers */
+ACPI_EXTERN spinlock_t _acpi_ev_global_lock_pending_lock; /* For global lock */
#define acpi_gbl_gpe_lock &_acpi_gbl_gpe_lock
#define acpi_gbl_hardware_lock &_acpi_gbl_hardware_lock
+#define acpi_ev_global_lock_pending_lock &_acpi_ev_global_lock_pending_lock
/*****************************************************************************
*
@@ -370,7 +375,9 @@ ACPI_EXTERN struct acpi_fixed_event_handler
ACPI_EXTERN struct acpi_gpe_xrupt_info *acpi_gbl_gpe_xrupt_list_head;
ACPI_EXTERN struct acpi_gpe_block_info
*acpi_gbl_gpe_fadt_blocks[ACPI_MAX_GPE_BLOCKS];
-ACPI_EXTERN u8 acpi_all_gpes_initialized;
+ACPI_EXTERN u8 acpi_gbl_all_gpes_initialized;
+ACPI_EXTERN ACPI_GBL_EVENT_HANDLER acpi_gbl_global_event_handler;
+ACPI_EXTERN void *acpi_gbl_global_event_handler_context;
/*****************************************************************************
*
diff --git a/drivers/acpi/acpica/achware.h b/drivers/acpi/acpica/achware.h
index 167470a..e7213be 100644
--- a/drivers/acpi/acpica/achware.h
+++ b/drivers/acpi/acpica/achware.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -94,7 +94,7 @@ u32 acpi_hw_get_gpe_register_bit(struct acpi_gpe_event_info *gpe_event_info,
struct acpi_gpe_register_info *gpe_register_info);
acpi_status
-acpi_hw_low_set_gpe(struct acpi_gpe_event_info *gpe_event_info, u8 action);
+acpi_hw_low_set_gpe(struct acpi_gpe_event_info *gpe_event_info, u32 action);
acpi_status
acpi_hw_disable_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
diff --git a/drivers/acpi/acpica/acinterp.h b/drivers/acpi/acpica/acinterp.h
index 049e203..3731e1c 100644
--- a/drivers/acpi/acpica/acinterp.h
+++ b/drivers/acpi/acpica/acinterp.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h
index 2ceb0c0..54784bb 100644
--- a/drivers/acpi/acpica/aclocal.h
+++ b/drivers/acpi/acpica/aclocal.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -408,17 +408,18 @@ struct acpi_predefined_data {
/* Dispatch info for each GPE -- either a method or handler, cannot be both */
-struct acpi_handler_info {
- acpi_event_handler address; /* Address of handler, if any */
+struct acpi_gpe_handler_info {
+ acpi_gpe_handler address; /* Address of handler, if any */
void *context; /* Context to be passed to handler */
struct acpi_namespace_node *method_node; /* Method node for this GPE level (saved) */
- u8 orig_flags; /* Original misc info about this GPE */
- u8 orig_enabled; /* Set if the GPE was originally enabled */
+ u8 original_flags; /* Original (pre-handler) GPE info */
+ u8 originally_enabled; /* True if GPE was originally enabled */
};
union acpi_gpe_dispatch_info {
struct acpi_namespace_node *method_node; /* Method node for this GPE level */
- struct acpi_handler_info *handler;
+ struct acpi_gpe_handler_info *handler; /* Installed GPE handler */
+ struct acpi_namespace_node *device_node; /* Parent _PRW device for implicit notify */
};
/*
@@ -458,7 +459,7 @@ struct acpi_gpe_block_info {
u32 register_count; /* Number of register pairs in block */
u16 gpe_count; /* Number of individual GPEs in block */
u8 block_base_number; /* Base GPE number for this block */
- u8 initialized; /* If set, the GPE block has been initialized */
+ u8 initialized; /* TRUE if this block is initialized */
};
/* Information about GPE interrupt handlers, one per each interrupt level used for GPEs */
diff --git a/drivers/acpi/acpica/acmacros.h b/drivers/acpi/acpica/acmacros.h
index 8d5c9e0..b7491ee 100644
--- a/drivers/acpi/acpica/acmacros.h
+++ b/drivers/acpi/acpica/acmacros.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/acnamesp.h b/drivers/acpi/acpica/acnamesp.h
index d44d3bc..79a598c 100644
--- a/drivers/acpi/acpica/acnamesp.h
+++ b/drivers/acpi/acpica/acnamesp.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/acobject.h b/drivers/acpi/acpica/acobject.h
index 962a3cc..1055769 100644
--- a/drivers/acpi/acpica/acobject.h
+++ b/drivers/acpi/acpica/acobject.h
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -97,8 +97,6 @@
#define AOPOBJ_OBJECT_INITIALIZED 0x08 /* Region is initialized, _REG was run */
#define AOPOBJ_SETUP_COMPLETE 0x10 /* Region setup is complete */
#define AOPOBJ_INVALID 0x20 /* Host OS won't allow a Region address */
-#define AOPOBJ_MODULE_LEVEL 0x40 /* Method is actually module-level code */
-#define AOPOBJ_MODIFIED_NAMESPACE 0x80 /* Method modified the namespace */
/******************************************************************************
*
@@ -175,7 +173,7 @@ struct acpi_object_region {
};
struct acpi_object_method {
- ACPI_OBJECT_COMMON_HEADER u8 method_flags;
+ ACPI_OBJECT_COMMON_HEADER u8 info_flags;
u8 param_count;
u8 sync_level;
union acpi_operand_object *mutex;
@@ -183,13 +181,21 @@ struct acpi_object_method {
union {
ACPI_INTERNAL_METHOD implementation;
union acpi_operand_object *handler;
- } extra;
+ } dispatch;
u32 aml_length;
u8 thread_count;
acpi_owner_id owner_id;
};
+/* Flags for info_flags field above */
+
+#define ACPI_METHOD_MODULE_LEVEL 0x01 /* Method is actually module-level code */
+#define ACPI_METHOD_INTERNAL_ONLY 0x02 /* Method is implemented internally (_OSI) */
+#define ACPI_METHOD_SERIALIZED 0x04 /* Method is serialized */
+#define ACPI_METHOD_SERIALIZED_PENDING 0x08 /* Method is to be marked serialized */
+#define ACPI_METHOD_MODIFIED_NAMESPACE 0x10 /* Method modified the namespace */
+
/******************************************************************************
*
* Objects that can be notified. All share a common notify_info area.
diff --git a/drivers/acpi/acpica/acopcode.h b/drivers/acpi/acpica/acopcode.h
index 8c15ff4..bb2ccfa 100644
--- a/drivers/acpi/acpica/acopcode.h
+++ b/drivers/acpi/acpica/acopcode.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/acparser.h b/drivers/acpi/acpica/acparser.h
index d0bb0fd..5ea1e06 100644
--- a/drivers/acpi/acpica/acparser.h
+++ b/drivers/acpi/acpica/acparser.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/acpredef.h b/drivers/acpi/acpica/acpredef.h
index 10998d3..94e73c9 100644
--- a/drivers/acpi/acpica/acpredef.h
+++ b/drivers/acpi/acpica/acpredef.h
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/acresrc.h b/drivers/acpi/acpica/acresrc.h
index 528bcba..f08b55b 100644
--- a/drivers/acpi/acpica/acresrc.h
+++ b/drivers/acpi/acpica/acresrc.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/acstruct.h b/drivers/acpi/acpica/acstruct.h
index 6e5dd97..1623b24 100644
--- a/drivers/acpi/acpica/acstruct.h
+++ b/drivers/acpi/acpica/acstruct.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/actables.h b/drivers/acpi/acpica/actables.h
index 62a576e..967f081 100644
--- a/drivers/acpi/acpica/actables.h
+++ b/drivers/acpi/acpica/actables.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/acutils.h b/drivers/acpi/acpica/acutils.h
index 72e4183..99c140d 100644
--- a/drivers/acpi/acpica/acutils.h
+++ b/drivers/acpi/acpica/acutils.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/amlcode.h b/drivers/acpi/acpica/amlcode.h
index 1f484ba..f4f0998 100644
--- a/drivers/acpi/acpica/amlcode.h
+++ b/drivers/acpi/acpica/amlcode.h
@@ -7,7 +7,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -480,16 +480,10 @@ typedef enum {
AML_FIELD_ATTRIB_SMB_BLOCK_CALL = 0x0D
} AML_ACCESS_ATTRIBUTE;
-/* Bit fields in method_flags byte */
+/* Bit fields in the AML method_flags byte */
#define AML_METHOD_ARG_COUNT 0x07
#define AML_METHOD_SERIALIZED 0x08
#define AML_METHOD_SYNC_LEVEL 0xF0
-/* METHOD_FLAGS_ARG_COUNT is not used internally, define additional flags */
-
-#define AML_METHOD_INTERNAL_ONLY 0x01
-#define AML_METHOD_RESERVED1 0x02
-#define AML_METHOD_RESERVED2 0x04
-
#endif /* __AMLCODE_H__ */
diff --git a/drivers/acpi/acpica/amlresrc.h b/drivers/acpi/acpica/amlresrc.h
index 0e5798f..59122cd 100644
--- a/drivers/acpi/acpica/amlresrc.h
+++ b/drivers/acpi/acpica/amlresrc.h
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/dsfield.c b/drivers/acpi/acpica/dsfield.c
index 347bee1..34be60c 100644
--- a/drivers/acpi/acpica/dsfield.c
+++ b/drivers/acpi/acpica/dsfield.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/dsinit.c b/drivers/acpi/acpica/dsinit.c
index cc4a38c..a7718bf 100644
--- a/drivers/acpi/acpica/dsinit.c
+++ b/drivers/acpi/acpica/dsinit.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/dsmethod.c b/drivers/acpi/acpica/dsmethod.c
index d94dd89..5d79775 100644
--- a/drivers/acpi/acpica/dsmethod.c
+++ b/drivers/acpi/acpica/dsmethod.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -43,7 +43,6 @@
#include <acpi/acpi.h>
#include "accommon.h"
-#include "amlcode.h"
#include "acdispat.h"
#include "acinterp.h"
#include "acnamesp.h"
@@ -201,7 +200,7 @@ acpi_ds_begin_method_execution(struct acpi_namespace_node *method_node,
/*
* If this method is serialized, we need to acquire the method mutex.
*/
- if (obj_desc->method.method_flags & AML_METHOD_SERIALIZED) {
+ if (obj_desc->method.info_flags & ACPI_METHOD_SERIALIZED) {
/*
* Create a mutex for the method if it is defined to be Serialized
* and a mutex has not already been created. We defer the mutex creation
@@ -413,8 +412,9 @@ acpi_ds_call_control_method(struct acpi_thread_state *thread,
/* Invoke an internal method if necessary */
- if (obj_desc->method.method_flags & AML_METHOD_INTERNAL_ONLY) {
- status = obj_desc->method.extra.implementation(next_walk_state);
+ if (obj_desc->method.info_flags & ACPI_METHOD_INTERNAL_ONLY) {
+ status =
+ obj_desc->method.dispatch.implementation(next_walk_state);
if (status == AE_OK) {
status = AE_CTRL_TERMINATE;
}
@@ -579,11 +579,14 @@ acpi_ds_terminate_control_method(union acpi_operand_object *method_desc,
/*
* Delete any namespace objects created anywhere within the
- * namespace by the execution of this method. Unless this method
- * is a module-level executable code method, in which case we
- * want make the objects permanent.
+ * namespace by the execution of this method. Unless:
+ * 1) This method is a module-level executable code method, in which
+ * case we want make the objects permanent.
+ * 2) There are other threads executing the method, in which case we
+ * will wait until the last thread has completed.
*/
- if (!(method_desc->method.flags & AOPOBJ_MODULE_LEVEL)) {
+ if (!(method_desc->method.info_flags & ACPI_METHOD_MODULE_LEVEL)
+ && (method_desc->method.thread_count == 1)) {
/* Delete any direct children of (created by) this method */
@@ -593,12 +596,17 @@ acpi_ds_terminate_control_method(union acpi_operand_object *method_desc,
/*
* Delete any objects that were created by this method
* elsewhere in the namespace (if any were created).
+ * Use of the ACPI_METHOD_MODIFIED_NAMESPACE optimizes the
+ * deletion such that we don't have to perform an entire
+ * namespace walk for every control method execution.
*/
if (method_desc->method.
- flags & AOPOBJ_MODIFIED_NAMESPACE) {
+ info_flags & ACPI_METHOD_MODIFIED_NAMESPACE) {
acpi_ns_delete_namespace_by_owner(method_desc->
method.
owner_id);
+ method_desc->method.info_flags &=
+ ~ACPI_METHOD_MODIFIED_NAMESPACE;
}
}
}
@@ -629,19 +637,43 @@ acpi_ds_terminate_control_method(union acpi_operand_object *method_desc,
* Serialized if it appears that the method is incorrectly written and
* does not support multiple thread execution. The best example of this
* is if such a method creates namespace objects and blocks. A second
- * thread will fail with an AE_ALREADY_EXISTS exception
+ * thread will fail with an AE_ALREADY_EXISTS exception.
*
* This code is here because we must wait until the last thread exits
- * before creating the synchronization semaphore.
+ * before marking the method as serialized.
*/
- if ((method_desc->method.method_flags & AML_METHOD_SERIALIZED)
- && (!method_desc->method.mutex)) {
- (void)acpi_ds_create_method_mutex(method_desc);
+ if (method_desc->method.
+ info_flags & ACPI_METHOD_SERIALIZED_PENDING) {
+ if (walk_state) {
+ ACPI_INFO((AE_INFO,
+ "Marking method %4.4s as Serialized because of AE_ALREADY_EXISTS error",
+ walk_state->method_node->name.
+ ascii));
+ }
+
+ /*
+ * Method tried to create an object twice and was marked as
+ * "pending serialized". The probable cause is that the method
+ * cannot handle reentrancy.
+ *
+ * The method was created as not_serialized, but it tried to create
+ * a named object and then blocked, causing the second thread
+ * entrance to begin and then fail. Workaround this problem by
+ * marking the method permanently as Serialized when the last
+ * thread exits here.
+ */
+ method_desc->method.info_flags &=
+ ~ACPI_METHOD_SERIALIZED_PENDING;
+ method_desc->method.info_flags |=
+ ACPI_METHOD_SERIALIZED;
+ method_desc->method.sync_level = 0;
}
/* No more threads, we can free the owner_id */
- if (!(method_desc->method.flags & AOPOBJ_MODULE_LEVEL)) {
+ if (!
+ (method_desc->method.
+ info_flags & ACPI_METHOD_MODULE_LEVEL)) {
acpi_ut_release_owner_id(&method_desc->method.owner_id);
}
}
diff --git a/drivers/acpi/acpica/dsmthdat.c b/drivers/acpi/acpica/dsmthdat.c
index 8095306..905ce29 100644
--- a/drivers/acpi/acpica/dsmthdat.c
+++ b/drivers/acpi/acpica/dsmthdat.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/dsobject.c b/drivers/acpi/acpica/dsobject.c
index 8e85f54..f42e17e 100644
--- a/drivers/acpi/acpica/dsobject.c
+++ b/drivers/acpi/acpica/dsobject.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/dsopcode.c b/drivers/acpi/acpica/dsopcode.c
index 7c0e742..bbecf29 100644
--- a/drivers/acpi/acpica/dsopcode.c
+++ b/drivers/acpi/acpica/dsopcode.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/dsutils.c b/drivers/acpi/acpica/dsutils.c
index 15135c2..2c477ce 100644
--- a/drivers/acpi/acpica/dsutils.c
+++ b/drivers/acpi/acpica/dsutils.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/dswexec.c b/drivers/acpi/acpica/dswexec.c
index 6b0b5d0..fe40e4c 100644
--- a/drivers/acpi/acpica/dswexec.c
+++ b/drivers/acpi/acpica/dswexec.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/dswload.c b/drivers/acpi/acpica/dswload.c
index 140a9d0..52566ff 100644
--- a/drivers/acpi/acpica/dswload.c
+++ b/drivers/acpi/acpica/dswload.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/dswscope.c b/drivers/acpi/acpica/dswscope.c
index d1e7017..76a661f 100644
--- a/drivers/acpi/acpica/dswscope.c
+++ b/drivers/acpi/acpica/dswscope.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/dswstate.c b/drivers/acpi/acpica/dswstate.c
index 83155dd..a6c374e 100644
--- a/drivers/acpi/acpica/dswstate.c
+++ b/drivers/acpi/acpica/dswstate.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/evevent.c b/drivers/acpi/acpica/evevent.c
index c61c303..d458b04 100644
--- a/drivers/acpi/acpica/evevent.c
+++ b/drivers/acpi/acpica/evevent.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -217,9 +217,17 @@ u32 acpi_ev_fixed_event_detect(void)
status_bit_mask)
&& (fixed_enable & acpi_gbl_fixed_event_info[i].
enable_bit_mask)) {
+ /*
+ * Found an active (signalled) event. Invoke global event
+ * handler if present.
+ */
+ acpi_fixed_event_count[i]++;
+ if (acpi_gbl_global_event_handler) {
+ acpi_gbl_global_event_handler
+ (ACPI_EVENT_TYPE_FIXED, NULL, i,
+ acpi_gbl_global_event_handler_context);
+ }
- /* Found an active (signalled) event */
- acpi_os_fixed_event_count(i);
int_status |= acpi_ev_fixed_event_dispatch(i);
}
}
diff --git a/drivers/acpi/acpica/evgpe.c b/drivers/acpi/acpica/evgpe.c
index f226eac..14988a8 100644
--- a/drivers/acpi/acpica/evgpe.c
+++ b/drivers/acpi/acpica/evgpe.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -52,6 +52,8 @@ ACPI_MODULE_NAME("evgpe")
/* Local prototypes */
static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context);
+static void ACPI_SYSTEM_XFACE acpi_ev_asynch_enable_gpe(void *context);
+
/*******************************************************************************
*
* FUNCTION: acpi_ev_update_gpe_enable_mask
@@ -102,7 +104,7 @@ acpi_ev_update_gpe_enable_mask(struct acpi_gpe_event_info *gpe_event_info)
*
* RETURN: Status
*
- * DESCRIPTION: Clear the given GPE from stale events and enable it.
+ * DESCRIPTION: Clear a GPE of stale events and enable it.
*
******************************************************************************/
acpi_status
@@ -113,12 +115,13 @@ acpi_ev_enable_gpe(struct acpi_gpe_event_info *gpe_event_info)
ACPI_FUNCTION_TRACE(ev_enable_gpe);
/*
- * We will only allow a GPE to be enabled if it has either an
- * associated method (_Lxx/_Exx) or a handler. Otherwise, the
- * GPE will be immediately disabled by acpi_ev_gpe_dispatch the
- * first time it fires.
+ * We will only allow a GPE to be enabled if it has either an associated
+ * method (_Lxx/_Exx) or a handler, or is using the implicit notify
+ * feature. Otherwise, the GPE will be immediately disabled by
+ * acpi_ev_gpe_dispatch the first time it fires.
*/
- if (!(gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK)) {
+ if ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) ==
+ ACPI_GPE_DISPATCH_NONE) {
return_ACPI_STATUS(AE_NO_HANDLER);
}
@@ -137,9 +140,9 @@ acpi_ev_enable_gpe(struct acpi_gpe_event_info *gpe_event_info)
/*******************************************************************************
*
- * FUNCTION: acpi_raw_enable_gpe
+ * FUNCTION: acpi_ev_add_gpe_reference
*
- * PARAMETERS: gpe_event_info - GPE to enable
+ * PARAMETERS: gpe_event_info - Add a reference to this GPE
*
* RETURN: Status
*
@@ -148,16 +151,21 @@ acpi_ev_enable_gpe(struct acpi_gpe_event_info *gpe_event_info)
*
******************************************************************************/
-acpi_status acpi_raw_enable_gpe(struct acpi_gpe_event_info *gpe_event_info)
+acpi_status acpi_ev_add_gpe_reference(struct acpi_gpe_event_info *gpe_event_info)
{
acpi_status status = AE_OK;
+ ACPI_FUNCTION_TRACE(ev_add_gpe_reference);
+
if (gpe_event_info->runtime_count == ACPI_UINT8_MAX) {
return_ACPI_STATUS(AE_LIMIT);
}
gpe_event_info->runtime_count++;
if (gpe_event_info->runtime_count == 1) {
+
+ /* Enable on first reference */
+
status = acpi_ev_update_gpe_enable_mask(gpe_event_info);
if (ACPI_SUCCESS(status)) {
status = acpi_ev_enable_gpe(gpe_event_info);
@@ -173,9 +181,9 @@ acpi_status acpi_raw_enable_gpe(struct acpi_gpe_event_info *gpe_event_info)
/*******************************************************************************
*
- * FUNCTION: acpi_raw_disable_gpe
+ * FUNCTION: acpi_ev_remove_gpe_reference
*
- * PARAMETERS: gpe_event_info - GPE to disable
+ * PARAMETERS: gpe_event_info - Remove a reference to this GPE
*
* RETURN: Status
*
@@ -184,16 +192,21 @@ acpi_status acpi_raw_enable_gpe(struct acpi_gpe_event_info *gpe_event_info)
*
******************************************************************************/
-acpi_status acpi_raw_disable_gpe(struct acpi_gpe_event_info *gpe_event_info)
+acpi_status acpi_ev_remove_gpe_reference(struct acpi_gpe_event_info *gpe_event_info)
{
acpi_status status = AE_OK;
+ ACPI_FUNCTION_TRACE(ev_remove_gpe_reference);
+
if (!gpe_event_info->runtime_count) {
return_ACPI_STATUS(AE_LIMIT);
}
gpe_event_info->runtime_count--;
if (!gpe_event_info->runtime_count) {
+
+ /* Disable on last reference */
+
status = acpi_ev_update_gpe_enable_mask(gpe_event_info);
if (ACPI_SUCCESS(status)) {
status = acpi_hw_low_set_gpe(gpe_event_info,
@@ -379,7 +392,7 @@ u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info * gpe_xrupt_list)
}
ACPI_DEBUG_PRINT((ACPI_DB_INTERRUPTS,
- "Read GPE Register at GPE%X: Status=%02X, Enable=%02X\n",
+ "Read GPE Register at GPE%02X: Status=%02X, Enable=%02X\n",
gpe_register_info->base_gpe_number,
status_reg, enable_reg));
@@ -405,7 +418,9 @@ u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info * gpe_xrupt_list)
* or method.
*/
int_status |=
- acpi_ev_gpe_dispatch(&gpe_block->
+ acpi_ev_gpe_dispatch(gpe_block->
+ node,
+ &gpe_block->
event_info[((acpi_size) i * ACPI_GPE_REGISTER_WIDTH) + j], j + gpe_register_info->base_gpe_number);
}
}
@@ -435,19 +450,28 @@ u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info * gpe_xrupt_list)
* an interrupt handler.
*
******************************************************************************/
-static void acpi_ev_asynch_enable_gpe(void *context);
static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context)
{
- struct acpi_gpe_event_info *gpe_event_info = (void *)context;
+ struct acpi_gpe_event_info *gpe_event_info = context;
acpi_status status;
- struct acpi_gpe_event_info local_gpe_event_info;
+ struct acpi_gpe_event_info *local_gpe_event_info;
struct acpi_evaluate_info *info;
ACPI_FUNCTION_TRACE(ev_asynch_execute_gpe_method);
+ /* Allocate a local GPE block */
+
+ local_gpe_event_info =
+ ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_gpe_event_info));
+ if (!local_gpe_event_info) {
+ ACPI_EXCEPTION((AE_INFO, AE_NO_MEMORY, "while handling a GPE"));
+ return_VOID;
+ }
+
status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
if (ACPI_FAILURE(status)) {
+ ACPI_FREE(local_gpe_event_info);
return_VOID;
}
@@ -455,6 +479,7 @@ static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context)
if (!acpi_ev_valid_gpe_event(gpe_event_info)) {
status = acpi_ut_release_mutex(ACPI_MTX_EVENTS);
+ ACPI_FREE(local_gpe_event_info);
return_VOID;
}
@@ -462,7 +487,7 @@ static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context)
* Take a snapshot of the GPE info for this level - we copy the info to
* prevent a race condition with remove_handler/remove_block.
*/
- ACPI_MEMCPY(&local_gpe_event_info, gpe_event_info,
+ ACPI_MEMCPY(local_gpe_event_info, gpe_event_info,
sizeof(struct acpi_gpe_event_info));
status = acpi_ut_release_mutex(ACPI_MTX_EVENTS);
@@ -470,12 +495,26 @@ static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context)
return_VOID;
}
- /*
- * Must check for control method type dispatch one more time to avoid a
- * race with ev_gpe_install_handler
- */
- if ((local_gpe_event_info.flags & ACPI_GPE_DISPATCH_MASK) ==
- ACPI_GPE_DISPATCH_METHOD) {
+ /* Do the correct dispatch - normal method or implicit notify */
+
+ switch (local_gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) {
+ case ACPI_GPE_DISPATCH_NOTIFY:
+
+ /*
+ * Implicit notify.
+ * Dispatch a DEVICE_WAKE notify to the appropriate handler.
+ * NOTE: the request is queued for execution after this method
+ * completes. The notify handlers are NOT invoked synchronously
+ * from this thread -- because handlers may in turn run other
+ * control methods.
+ */
+ status =
+ acpi_ev_queue_notify_request(local_gpe_event_info->dispatch.
+ device_node,
+ ACPI_NOTIFY_DEVICE_WAKE);
+ break;
+
+ case ACPI_GPE_DISPATCH_METHOD:
/* Allocate the evaluation information block */
@@ -488,7 +527,7 @@ static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context)
* control method that corresponds to this GPE
*/
info->prefix_node =
- local_gpe_event_info.dispatch.method_node;
+ local_gpe_event_info->dispatch.method_node;
info->flags = ACPI_IGNORE_RETURN_VALUE;
status = acpi_ns_evaluate(info);
@@ -499,46 +538,98 @@ static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context)
ACPI_EXCEPTION((AE_INFO, status,
"while evaluating GPE method [%4.4s]",
acpi_ut_get_node_name
- (local_gpe_event_info.dispatch.
+ (local_gpe_event_info->dispatch.
method_node)));
}
+
+ break;
+
+ default:
+ return_VOID; /* Should never happen */
}
+
/* Defer enabling of GPE until all notify handlers are done */
- acpi_os_execute(OSL_NOTIFY_HANDLER, acpi_ev_asynch_enable_gpe,
- gpe_event_info);
+
+ status = acpi_os_execute(OSL_NOTIFY_HANDLER,
+ acpi_ev_asynch_enable_gpe,
+ local_gpe_event_info);
+ if (ACPI_FAILURE(status)) {
+ ACPI_FREE(local_gpe_event_info);
+ }
return_VOID;
}
-static void acpi_ev_asynch_enable_gpe(void *context)
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ev_asynch_enable_gpe
+ *
+ * PARAMETERS: Context (gpe_event_info) - Info for this GPE
+ * Callback from acpi_os_execute
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Asynchronous clear/enable for GPE. This allows the GPE to
+ * complete (i.e., finish execution of Notify)
+ *
+ ******************************************************************************/
+
+static void ACPI_SYSTEM_XFACE acpi_ev_asynch_enable_gpe(void *context)
{
struct acpi_gpe_event_info *gpe_event_info = context;
+
+ (void)acpi_ev_finish_gpe(gpe_event_info);
+
+ ACPI_FREE(gpe_event_info);
+ return;
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ev_finish_gpe
+ *
+ * PARAMETERS: gpe_event_info - Info for this GPE
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Clear/Enable a GPE. Common code that is used after execution
+ * of a GPE method or a synchronous or asynchronous GPE handler.
+ *
+ ******************************************************************************/
+
+acpi_status acpi_ev_finish_gpe(struct acpi_gpe_event_info *gpe_event_info)
+{
acpi_status status;
+
if ((gpe_event_info->flags & ACPI_GPE_XRUPT_TYPE_MASK) ==
ACPI_GPE_LEVEL_TRIGGERED) {
/*
- * GPE is level-triggered, we clear the GPE status bit after handling
- * the event.
+ * GPE is level-triggered, we clear the GPE status bit after
+ * handling the event.
*/
status = acpi_hw_clear_gpe(gpe_event_info);
if (ACPI_FAILURE(status)) {
- return_VOID;
+ return (status);
}
}
/*
- * Enable this GPE, conditionally. This means that the GPE will only be
- * physically enabled if the enable_for_run bit is set in the event_info
+ * Enable this GPE, conditionally. This means that the GPE will
+ * only be physically enabled if the enable_for_run bit is set
+ * in the event_info.
*/
- (void)acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_COND_ENABLE);
-
- return_VOID;
+ (void)acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_CONDITIONAL_ENABLE);
+ return (AE_OK);
}
+
/*******************************************************************************
*
* FUNCTION: acpi_ev_gpe_dispatch
*
- * PARAMETERS: gpe_event_info - Info for this GPE
+ * PARAMETERS: gpe_device - Device node. NULL for GPE0/GPE1
+ * gpe_event_info - Info for this GPE
* gpe_number - Number relative to the parent GPE block
*
* RETURN: INTERRUPT_HANDLED or INTERRUPT_NOT_HANDLED
@@ -551,13 +642,22 @@ static void acpi_ev_asynch_enable_gpe(void *context)
******************************************************************************/
u32
-acpi_ev_gpe_dispatch(struct acpi_gpe_event_info *gpe_event_info, u32 gpe_number)
+acpi_ev_gpe_dispatch(struct acpi_namespace_node *gpe_device,
+ struct acpi_gpe_event_info *gpe_event_info, u32 gpe_number)
{
acpi_status status;
+ u32 return_value;
ACPI_FUNCTION_TRACE(ev_gpe_dispatch);
- acpi_os_gpe_count(gpe_number);
+ /* Invoke global event handler if present */
+
+ acpi_gpe_count++;
+ if (acpi_gbl_global_event_handler) {
+ acpi_gbl_global_event_handler(ACPI_EVENT_TYPE_GPE, gpe_device,
+ gpe_number,
+ acpi_gbl_global_event_handler_context);
+ }
/*
* If edge-triggered, clear the GPE status bit now. Note that
@@ -568,59 +668,55 @@ acpi_ev_gpe_dispatch(struct acpi_gpe_event_info *gpe_event_info, u32 gpe_number)
status = acpi_hw_clear_gpe(gpe_event_info);
if (ACPI_FAILURE(status)) {
ACPI_EXCEPTION((AE_INFO, status,
- "Unable to clear GPE[0x%2X]",
- gpe_number));
+ "Unable to clear GPE%02X", gpe_number));
return_UINT32(ACPI_INTERRUPT_NOT_HANDLED);
}
}
/*
- * Dispatch the GPE to either an installed handler, or the control method
- * associated with this GPE (_Lxx or _Exx). If a handler exists, we invoke
- * it and do not attempt to run the method. If there is neither a handler
- * nor a method, we disable this GPE to prevent further such pointless
- * events from firing.
+ * Always disable the GPE so that it does not keep firing before
+ * any asynchronous activity completes (either from the execution
+ * of a GPE method or an asynchronous GPE handler.)
+ *
+ * If there is no handler or method to run, just disable the
+ * GPE and leave it disabled permanently to prevent further such
+ * pointless events from firing.
+ */
+ status = acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_DISABLE);
+ if (ACPI_FAILURE(status)) {
+ ACPI_EXCEPTION((AE_INFO, status,
+ "Unable to disable GPE%02X", gpe_number));
+ return_UINT32(ACPI_INTERRUPT_NOT_HANDLED);
+ }
+
+ /*
+ * Dispatch the GPE to either an installed handler or the control
+ * method associated with this GPE (_Lxx or _Exx). If a handler
+ * exists, we invoke it and do not attempt to run the method.
+ * If there is neither a handler nor a method, leave the GPE
+ * disabled.
*/
switch (gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) {
case ACPI_GPE_DISPATCH_HANDLER:
- /*
- * Invoke the installed handler (at interrupt level)
- * Ignore return status for now.
- * TBD: leave GPE disabled on error?
- */
- (void)gpe_event_info->dispatch.handler->address(gpe_event_info->
- dispatch.
- handler->
- context);
+ /* Invoke the installed handler (at interrupt level) */
- /* It is now safe to clear level-triggered events. */
+ return_value =
+ gpe_event_info->dispatch.handler->address(gpe_device,
+ gpe_number,
+ gpe_event_info->
+ dispatch.handler->
+ context);
- if ((gpe_event_info->flags & ACPI_GPE_XRUPT_TYPE_MASK) ==
- ACPI_GPE_LEVEL_TRIGGERED) {
- status = acpi_hw_clear_gpe(gpe_event_info);
- if (ACPI_FAILURE(status)) {
- ACPI_EXCEPTION((AE_INFO, status,
- "Unable to clear GPE[0x%2X]",
- gpe_number));
- return_UINT32(ACPI_INTERRUPT_NOT_HANDLED);
- }
+ /* If requested, clear (if level-triggered) and reenable the GPE */
+
+ if (return_value & ACPI_REENABLE_GPE) {
+ (void)acpi_ev_finish_gpe(gpe_event_info);
}
break;
case ACPI_GPE_DISPATCH_METHOD:
-
- /*
- * Disable the GPE, so it doesn't keep firing before the method has a
- * chance to run (it runs asynchronously with interrupts enabled).
- */
- status = acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_DISABLE);
- if (ACPI_FAILURE(status)) {
- ACPI_EXCEPTION((AE_INFO, status,
- "Unable to disable GPE[0x%2X]",
- gpe_number));
- return_UINT32(ACPI_INTERRUPT_NOT_HANDLED);
- }
+ case ACPI_GPE_DISPATCH_NOTIFY:
/*
* Execute the method associated with the GPE
@@ -631,7 +727,7 @@ acpi_ev_gpe_dispatch(struct acpi_gpe_event_info *gpe_event_info, u32 gpe_number)
gpe_event_info);
if (ACPI_FAILURE(status)) {
ACPI_EXCEPTION((AE_INFO, status,
- "Unable to queue handler for GPE[0x%2X] - event disabled",
+ "Unable to queue handler for GPE%2X - event disabled",
gpe_number));
}
break;
@@ -644,20 +740,9 @@ acpi_ev_gpe_dispatch(struct acpi_gpe_event_info *gpe_event_info, u32 gpe_number)
* a GPE to be enabled if it has no handler or method.
*/
ACPI_ERROR((AE_INFO,
- "No handler or method for GPE[0x%2X], disabling event",
+ "No handler or method for GPE%02X, disabling event",
gpe_number));
- /*
- * Disable the GPE. The GPE will remain disabled a handler
- * is installed or ACPICA is restarted.
- */
- status = acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_DISABLE);
- if (ACPI_FAILURE(status)) {
- ACPI_EXCEPTION((AE_INFO, status,
- "Unable to disable GPE[0x%2X]",
- gpe_number));
- return_UINT32(ACPI_INTERRUPT_NOT_HANDLED);
- }
break;
}
diff --git a/drivers/acpi/acpica/evgpeblk.c b/drivers/acpi/acpica/evgpeblk.c
index 020add3..ca2c41a 100644
--- a/drivers/acpi/acpica/evgpeblk.c
+++ b/drivers/acpi/acpica/evgpeblk.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -361,9 +361,9 @@ acpi_ev_create_gpe_block(struct acpi_namespace_node *gpe_device,
gpe_block->node = gpe_device;
gpe_block->gpe_count = (u16)(register_count * ACPI_GPE_REGISTER_WIDTH);
+ gpe_block->initialized = FALSE;
gpe_block->register_count = register_count;
gpe_block->block_base_number = gpe_block_base_number;
- gpe_block->initialized = FALSE;
ACPI_MEMCPY(&gpe_block->block_address, gpe_block_address,
sizeof(struct acpi_generic_address));
@@ -386,7 +386,7 @@ acpi_ev_create_gpe_block(struct acpi_namespace_node *gpe_device,
return_ACPI_STATUS(status);
}
- acpi_all_gpes_initialized = FALSE;
+ acpi_gbl_all_gpes_initialized = FALSE;
/* Find all GPE methods (_Lxx or_Exx) for this block */
@@ -423,14 +423,12 @@ acpi_ev_create_gpe_block(struct acpi_namespace_node *gpe_device,
*
* FUNCTION: acpi_ev_initialize_gpe_block
*
- * PARAMETERS: gpe_device - Handle to the parent GPE block
- * gpe_block - Gpe Block info
+ * PARAMETERS: acpi_gpe_callback
*
* RETURN: Status
*
- * DESCRIPTION: Initialize and enable a GPE block. First find and run any
- * _PRT methods associated with the block, then enable the
- * appropriate GPEs.
+ * DESCRIPTION: Initialize and enable a GPE block. Enable GPEs that have
+ * associated methods.
* Note: Assumes namespace is locked.
*
******************************************************************************/
@@ -450,8 +448,8 @@ acpi_ev_initialize_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
ACPI_FUNCTION_TRACE(ev_initialize_gpe_block);
/*
- * Ignore a null GPE block (e.g., if no GPE block 1 exists) and
- * GPE blocks that have been initialized already.
+ * Ignore a null GPE block (e.g., if no GPE block 1 exists), and
+ * any GPE blocks that have been initialized already.
*/
if (!gpe_block || gpe_block->initialized) {
return_ACPI_STATUS(AE_OK);
@@ -459,8 +457,8 @@ acpi_ev_initialize_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
/*
* Enable all GPEs that have a corresponding method and have the
- * ACPI_GPE_CAN_WAKE flag unset. Any other GPEs within this block must
- * be enabled via the acpi_enable_gpe() interface.
+ * ACPI_GPE_CAN_WAKE flag unset. Any other GPEs within this block
+ * must be enabled via the acpi_enable_gpe() interface.
*/
gpe_enabled_count = 0;
@@ -472,14 +470,19 @@ acpi_ev_initialize_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
gpe_index = (i * ACPI_GPE_REGISTER_WIDTH) + j;
gpe_event_info = &gpe_block->event_info[gpe_index];
- /* Ignore GPEs that have no corresponding _Lxx/_Exx method */
-
- if (!(gpe_event_info->flags & ACPI_GPE_DISPATCH_METHOD)
+ /*
+ * Ignore GPEs that have no corresponding _Lxx/_Exx method
+ * and GPEs that are used to wake the system
+ */
+ if (((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) ==
+ ACPI_GPE_DISPATCH_NONE)
+ || ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK)
+ == ACPI_GPE_DISPATCH_HANDLER)
|| (gpe_event_info->flags & ACPI_GPE_CAN_WAKE)) {
continue;
}
- status = acpi_raw_enable_gpe(gpe_event_info);
+ status = acpi_ev_add_gpe_reference(gpe_event_info);
if (ACPI_FAILURE(status)) {
ACPI_EXCEPTION((AE_INFO, status,
"Could not enable GPE 0x%02X",
diff --git a/drivers/acpi/acpica/evgpeinit.c b/drivers/acpi/acpica/evgpeinit.c
index 4c8dea5..ce9aa9f 100644
--- a/drivers/acpi/acpica/evgpeinit.c
+++ b/drivers/acpi/acpica/evgpeinit.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -45,11 +45,27 @@
#include "accommon.h"
#include "acevents.h"
#include "acnamesp.h"
-#include "acinterp.h"
#define _COMPONENT ACPI_EVENTS
ACPI_MODULE_NAME("evgpeinit")
+/*
+ * Note: History of _PRW support in ACPICA
+ *
+ * Originally (2000 - 2010), the GPE initialization code performed a walk of
+ * the entire namespace to execute the _PRW methods and detect all GPEs
+ * capable of waking the system.
+ *
+ * As of 10/2010, the _PRW method execution has been removed since it is
+ * actually unnecessary. The host OS must in fact execute all _PRW methods
+ * in order to identify the device/power-resource dependencies. We now put
+ * the onus on the host OS to identify the wake GPEs as part of this process
+ * and to inform ACPICA of these GPEs via the acpi_setup_gpe_for_wake interface. This
+ * not only reduces the complexity of the ACPICA initialization code, but in
+ * some cases (on systems with very large namespaces) it should reduce the
+ * kernel boot time as well.
+ */
+
/*******************************************************************************
*
* FUNCTION: acpi_ev_gpe_initialize
@@ -222,7 +238,7 @@ void acpi_ev_update_gpes(acpi_owner_id table_owner_id)
acpi_status status = AE_OK;
/*
- * 2) Find any _Lxx/_Exx GPE methods that have just been loaded.
+ * Find any _Lxx/_Exx GPE methods that have just been loaded.
*
* Any GPEs that correspond to new _Lxx/_Exx methods are immediately
* enabled.
@@ -235,9 +251,9 @@ void acpi_ev_update_gpes(acpi_owner_id table_owner_id)
return;
}
+ walk_info.count = 0;
walk_info.owner_id = table_owner_id;
walk_info.execute_by_owner_id = TRUE;
- walk_info.count = 0;
/* Walk the interrupt level descriptor list */
@@ -298,7 +314,7 @@ void acpi_ev_update_gpes(acpi_owner_id table_owner_id)
* xx - is the GPE number [in HEX]
*
* If walk_info->execute_by_owner_id is TRUE, we only execute examine GPE methods
- * with that owner.
+ * with that owner.
*
******************************************************************************/
@@ -415,6 +431,7 @@ acpi_ev_match_gpe_method(acpi_handle obj_handle,
* Add the GPE information from above to the gpe_event_info block for
* use during dispatch of this GPE.
*/
+ gpe_event_info->flags &= ~(ACPI_GPE_DISPATCH_MASK);
gpe_event_info->flags |= (u8)(type | ACPI_GPE_DISPATCH_METHOD);
gpe_event_info->dispatch.method_node = method_node;
diff --git a/drivers/acpi/acpica/evgpeutil.c b/drivers/acpi/acpica/evgpeutil.c
index 19a0e51..80a81d0 100644
--- a/drivers/acpi/acpica/evgpeutil.c
+++ b/drivers/acpi/acpica/evgpeutil.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -154,6 +154,45 @@ u8 acpi_ev_valid_gpe_event(struct acpi_gpe_event_info *gpe_event_info)
/*******************************************************************************
*
+ * FUNCTION: acpi_ev_get_gpe_device
+ *
+ * PARAMETERS: GPE_WALK_CALLBACK
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Matches the input GPE index (0-current_gpe_count) with a GPE
+ * block device. NULL if the GPE is one of the FADT-defined GPEs.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ev_get_gpe_device(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
+ struct acpi_gpe_block_info *gpe_block, void *context)
+{
+ struct acpi_gpe_device_info *info = context;
+
+ /* Increment Index by the number of GPEs in this block */
+
+ info->next_block_base_index += gpe_block->gpe_count;
+
+ if (info->index < info->next_block_base_index) {
+ /*
+ * The GPE index is within this block, get the node. Leave the node
+ * NULL for the FADT-defined GPEs
+ */
+ if ((gpe_block->node)->type == ACPI_TYPE_DEVICE) {
+ info->gpe_device = gpe_block->node;
+ }
+
+ info->status = AE_OK;
+ return (AE_CTRL_END);
+ }
+
+ return (AE_OK);
+}
+
+/*******************************************************************************
+ *
* FUNCTION: acpi_ev_get_gpe_xrupt_block
*
* PARAMETERS: interrupt_number - Interrupt for a GPE block
diff --git a/drivers/acpi/acpica/evmisc.c b/drivers/acpi/acpica/evmisc.c
index fcaed9f..7dc8094 100644
--- a/drivers/acpi/acpica/evmisc.c
+++ b/drivers/acpi/acpica/evmisc.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -284,41 +284,39 @@ static void ACPI_SYSTEM_XFACE acpi_ev_notify_dispatch(void *context)
* RETURN: ACPI_INTERRUPT_HANDLED
*
* DESCRIPTION: Invoked directly from the SCI handler when a global lock
- * release interrupt occurs. Attempt to acquire the global lock,
- * if successful, signal the thread waiting for the lock.
+ * release interrupt occurs. If there's a thread waiting for
+ * the global lock, signal it.
*
* NOTE: Assumes that the semaphore can be signaled from interrupt level. If
* this is not possible for some reason, a separate thread will have to be
* scheduled to do this.
*
******************************************************************************/
+static u8 acpi_ev_global_lock_pending;
static u32 acpi_ev_global_lock_handler(void *context)
{
- u8 acquired = FALSE;
+ acpi_status status;
+ acpi_cpu_flags flags;
- /*
- * Attempt to get the lock.
- *
- * If we don't get it now, it will be marked pending and we will
- * take another interrupt when it becomes free.
- */
- ACPI_ACQUIRE_GLOBAL_LOCK(acpi_gbl_FACS, acquired);
- if (acquired) {
+ flags = acpi_os_acquire_lock(acpi_ev_global_lock_pending_lock);
- /* Got the lock, now wake all threads waiting for it */
+ if (!acpi_ev_global_lock_pending) {
+ goto out;
+ }
- acpi_gbl_global_lock_acquired = TRUE;
- /* Send a unit to the semaphore */
+ /* Send a unit to the semaphore */
- if (ACPI_FAILURE
- (acpi_os_signal_semaphore
- (acpi_gbl_global_lock_semaphore, 1))) {
- ACPI_ERROR((AE_INFO,
- "Could not signal Global Lock semaphore"));
- }
+ status = acpi_os_signal_semaphore(acpi_gbl_global_lock_semaphore, 1);
+ if (ACPI_FAILURE(status)) {
+ ACPI_ERROR((AE_INFO, "Could not signal Global Lock semaphore"));
}
+ acpi_ev_global_lock_pending = FALSE;
+
+ out:
+ acpi_os_release_lock(acpi_ev_global_lock_pending_lock, flags);
+
return (ACPI_INTERRUPT_HANDLED);
}
@@ -415,6 +413,7 @@ static int acpi_ev_global_lock_acquired;
acpi_status acpi_ev_acquire_global_lock(u16 timeout)
{
+ acpi_cpu_flags flags;
acpi_status status = AE_OK;
u8 acquired = FALSE;
@@ -467,32 +466,47 @@ acpi_status acpi_ev_acquire_global_lock(u16 timeout)
return_ACPI_STATUS(AE_OK);
}
- /* Attempt to acquire the actual hardware lock */
+ flags = acpi_os_acquire_lock(acpi_ev_global_lock_pending_lock);
+
+ do {
+
+ /* Attempt to acquire the actual hardware lock */
+
+ ACPI_ACQUIRE_GLOBAL_LOCK(acpi_gbl_FACS, acquired);
+ if (acquired) {
+ acpi_gbl_global_lock_acquired = TRUE;
+
+ ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
+ "Acquired hardware Global Lock\n"));
+ break;
+ }
- ACPI_ACQUIRE_GLOBAL_LOCK(acpi_gbl_FACS, acquired);
- if (acquired) {
+ acpi_ev_global_lock_pending = TRUE;
- /* We got the lock */
+ acpi_os_release_lock(acpi_ev_global_lock_pending_lock, flags);
+ /*
+ * Did not get the lock. The pending bit was set above, and we
+ * must wait until we get the global lock released interrupt.
+ */
ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
- "Acquired hardware Global Lock\n"));
+ "Waiting for hardware Global Lock\n"));
- acpi_gbl_global_lock_acquired = TRUE;
- return_ACPI_STATUS(AE_OK);
- }
+ /*
+ * Wait for handshake with the global lock interrupt handler.
+ * This interface releases the interpreter if we must wait.
+ */
+ status = acpi_ex_system_wait_semaphore(
+ acpi_gbl_global_lock_semaphore,
+ ACPI_WAIT_FOREVER);
- /*
- * Did not get the lock. The pending bit was set above, and we must now
- * wait until we get the global lock released interrupt.
- */
- ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Waiting for hardware Global Lock\n"));
+ flags = acpi_os_acquire_lock(acpi_ev_global_lock_pending_lock);
- /*
- * Wait for handshake with the global lock interrupt handler.
- * This interface releases the interpreter if we must wait.
- */
- status = acpi_ex_system_wait_semaphore(acpi_gbl_global_lock_semaphore,
- ACPI_WAIT_FOREVER);
+ } while (ACPI_SUCCESS(status));
+
+ acpi_ev_global_lock_pending = FALSE;
+
+ acpi_os_release_lock(acpi_ev_global_lock_pending_lock, flags);
return_ACPI_STATUS(status);
}
diff --git a/drivers/acpi/acpica/evregion.c b/drivers/acpi/acpica/evregion.c
index 98fd210..785a5ee 100644
--- a/drivers/acpi/acpica/evregion.c
+++ b/drivers/acpi/acpica/evregion.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/evrgnini.c b/drivers/acpi/acpica/evrgnini.c
index 0b47a6d..9659cee 100644
--- a/drivers/acpi/acpica/evrgnini.c
+++ b/drivers/acpi/acpica/evrgnini.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -590,9 +590,9 @@ acpi_ev_initialize_region(union acpi_operand_object *region_obj,
* See acpi_ns_exec_module_code
*/
if (obj_desc->method.
- flags & AOPOBJ_MODULE_LEVEL) {
+ info_flags & ACPI_METHOD_MODULE_LEVEL) {
handler_obj =
- obj_desc->method.extra.handler;
+ obj_desc->method.dispatch.handler;
}
break;
diff --git a/drivers/acpi/acpica/evsci.c b/drivers/acpi/acpica/evsci.c
index 8dfbaa9..2ebd40e 100644
--- a/drivers/acpi/acpica/evsci.c
+++ b/drivers/acpi/acpica/evsci.c
@@ -6,7 +6,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/evxface.c b/drivers/acpi/acpica/evxface.c
index 36af222..e114140 100644
--- a/drivers/acpi/acpica/evxface.c
+++ b/drivers/acpi/acpica/evxface.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -92,6 +92,57 @@ acpi_status acpi_install_exception_handler(acpi_exception_handler handler)
ACPI_EXPORT_SYMBOL(acpi_install_exception_handler)
#endif /* ACPI_FUTURE_USAGE */
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_install_global_event_handler
+ *
+ * PARAMETERS: Handler - Pointer to the global event handler function
+ * Context - Value passed to the handler on each event
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Saves the pointer to the handler function. The global handler
+ * is invoked upon each incoming GPE and Fixed Event. It is
+ * invoked at interrupt level at the time of the event dispatch.
+ * Can be used to update event counters, etc.
+ *
+ ******************************************************************************/
+acpi_status
+acpi_install_global_event_handler(ACPI_GBL_EVENT_HANDLER handler, void *context)
+{
+ acpi_status status;
+
+ ACPI_FUNCTION_TRACE(acpi_install_global_event_handler);
+
+ /* Parameter validation */
+
+ if (!handler) {
+ return_ACPI_STATUS(AE_BAD_PARAMETER);
+ }
+
+ status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ /* Don't allow two handlers. */
+
+ if (acpi_gbl_global_event_handler) {
+ status = AE_ALREADY_EXISTS;
+ goto cleanup;
+ }
+
+ acpi_gbl_global_event_handler = handler;
+ acpi_gbl_global_event_handler_context = context;
+
+ cleanup:
+ (void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
+ return_ACPI_STATUS(status);
+}
+
+ACPI_EXPORT_SYMBOL(acpi_install_global_event_handler)
+
/*******************************************************************************
*
* FUNCTION: acpi_install_fixed_event_handler
@@ -671,10 +722,10 @@ ACPI_EXPORT_SYMBOL(acpi_remove_notify_handler)
acpi_status
acpi_install_gpe_handler(acpi_handle gpe_device,
u32 gpe_number,
- u32 type, acpi_event_handler address, void *context)
+ u32 type, acpi_gpe_handler address, void *context)
{
struct acpi_gpe_event_info *gpe_event_info;
- struct acpi_handler_info *handler;
+ struct acpi_gpe_handler_info *handler;
acpi_status status;
acpi_cpu_flags flags;
@@ -693,7 +744,7 @@ acpi_install_gpe_handler(acpi_handle gpe_device,
/* Allocate memory for the handler object */
- handler = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_handler_info));
+ handler = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_gpe_handler_info));
if (!handler) {
status = AE_NO_MEMORY;
goto unlock_and_exit;
@@ -722,7 +773,7 @@ acpi_install_gpe_handler(acpi_handle gpe_device,
handler->address = address;
handler->context = context;
handler->method_node = gpe_event_info->dispatch.method_node;
- handler->orig_flags = gpe_event_info->flags &
+ handler->original_flags = gpe_event_info->flags &
(ACPI_GPE_XRUPT_TYPE_MASK | ACPI_GPE_DISPATCH_MASK);
/*
@@ -731,10 +782,10 @@ acpi_install_gpe_handler(acpi_handle gpe_device,
* disabled now to avoid spurious execution of the handler.
*/
- if ((handler->orig_flags & ACPI_GPE_DISPATCH_METHOD)
+ if ((handler->original_flags & ACPI_GPE_DISPATCH_METHOD)
&& gpe_event_info->runtime_count) {
- handler->orig_enabled = 1;
- (void)acpi_raw_disable_gpe(gpe_event_info);
+ handler->originally_enabled = 1;
+ (void)acpi_ev_remove_gpe_reference(gpe_event_info);
}
/* Install the handler */
@@ -777,10 +828,10 @@ ACPI_EXPORT_SYMBOL(acpi_install_gpe_handler)
******************************************************************************/
acpi_status
acpi_remove_gpe_handler(acpi_handle gpe_device,
- u32 gpe_number, acpi_event_handler address)
+ u32 gpe_number, acpi_gpe_handler address)
{
struct acpi_gpe_event_info *gpe_event_info;
- struct acpi_handler_info *handler;
+ struct acpi_gpe_handler_info *handler;
acpi_status status;
acpi_cpu_flags flags;
@@ -835,7 +886,7 @@ acpi_remove_gpe_handler(acpi_handle gpe_device,
gpe_event_info->dispatch.method_node = handler->method_node;
gpe_event_info->flags &=
~(ACPI_GPE_XRUPT_TYPE_MASK | ACPI_GPE_DISPATCH_MASK);
- gpe_event_info->flags |= handler->orig_flags;
+ gpe_event_info->flags |= handler->original_flags;
/*
* If the GPE was previously associated with a method and it was
@@ -843,9 +894,9 @@ acpi_remove_gpe_handler(acpi_handle gpe_device,
* post-initialization configuration.
*/
- if ((handler->orig_flags & ACPI_GPE_DISPATCH_METHOD)
- && handler->orig_enabled)
- (void)acpi_raw_enable_gpe(gpe_event_info);
+ if ((handler->original_flags & ACPI_GPE_DISPATCH_METHOD)
+ && handler->originally_enabled)
+ (void)acpi_ev_add_gpe_reference(gpe_event_info);
/* Now we can free the handler object */
diff --git a/drivers/acpi/acpica/evxfevnt.c b/drivers/acpi/acpica/evxfevnt.c
index a1dabe3..c57b5c7 100644
--- a/drivers/acpi/acpica/evxfevnt.c
+++ b/drivers/acpi/acpica/evxfevnt.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -43,18 +43,11 @@
#include <acpi/acpi.h>
#include "accommon.h"
-#include "acevents.h"
-#include "acnamesp.h"
#include "actables.h"
#define _COMPONENT ACPI_EVENTS
ACPI_MODULE_NAME("evxfevnt")
-/* Local prototypes */
-static acpi_status
-acpi_ev_get_gpe_device(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
- struct acpi_gpe_block_info *gpe_block, void *context);
-
/*******************************************************************************
*
* FUNCTION: acpi_enable
@@ -213,185 +206,6 @@ ACPI_EXPORT_SYMBOL(acpi_enable_event)
/*******************************************************************************
*
- * FUNCTION: acpi_gpe_wakeup
- *
- * PARAMETERS: gpe_device - Parent GPE Device. NULL for GPE0/GPE1
- * gpe_number - GPE level within the GPE block
- * Action - Enable or Disable
- *
- * RETURN: Status
- *
- * DESCRIPTION: Set or clear the GPE's wakeup enable mask bit.
- *
- ******************************************************************************/
-acpi_status acpi_gpe_wakeup(acpi_handle gpe_device, u32 gpe_number, u8 action)
-{
- acpi_status status = AE_OK;
- struct acpi_gpe_event_info *gpe_event_info;
- struct acpi_gpe_register_info *gpe_register_info;
- acpi_cpu_flags flags;
- u32 register_bit;
-
- ACPI_FUNCTION_TRACE(acpi_gpe_wakeup);
-
- flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
-
- /* Ensure that we have a valid GPE number */
-
- gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number);
- if (!gpe_event_info || !(gpe_event_info->flags & ACPI_GPE_CAN_WAKE)) {
- status = AE_BAD_PARAMETER;
- goto unlock_and_exit;
- }
-
- gpe_register_info = gpe_event_info->register_info;
- if (!gpe_register_info) {
- status = AE_NOT_EXIST;
- goto unlock_and_exit;
- }
-
- register_bit =
- acpi_hw_get_gpe_register_bit(gpe_event_info, gpe_register_info);
-
- /* Perform the action */
-
- switch (action) {
- case ACPI_GPE_ENABLE:
- ACPI_SET_BIT(gpe_register_info->enable_for_wake,
- (u8)register_bit);
- break;
-
- case ACPI_GPE_DISABLE:
- ACPI_CLEAR_BIT(gpe_register_info->enable_for_wake,
- (u8)register_bit);
- break;
-
- default:
- ACPI_ERROR((AE_INFO, "%u, Invalid action", action));
- status = AE_BAD_PARAMETER;
- break;
- }
-
-unlock_and_exit:
- acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
- return_ACPI_STATUS(status);
-}
-
-ACPI_EXPORT_SYMBOL(acpi_gpe_wakeup)
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_enable_gpe
- *
- * PARAMETERS: gpe_device - Parent GPE Device. NULL for GPE0/GPE1
- * gpe_number - GPE level within the GPE block
- *
- * RETURN: Status
- *
- * DESCRIPTION: Add a reference to a GPE. On the first reference, the GPE is
- * hardware-enabled.
- *
- ******************************************************************************/
-acpi_status acpi_enable_gpe(acpi_handle gpe_device, u32 gpe_number)
-{
- acpi_status status = AE_BAD_PARAMETER;
- struct acpi_gpe_event_info *gpe_event_info;
- acpi_cpu_flags flags;
-
- ACPI_FUNCTION_TRACE(acpi_enable_gpe);
-
- flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
-
- /* Ensure that we have a valid GPE number */
-
- gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number);
- if (gpe_event_info) {
- status = acpi_raw_enable_gpe(gpe_event_info);
- }
-
- acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
- return_ACPI_STATUS(status);
-}
-ACPI_EXPORT_SYMBOL(acpi_enable_gpe)
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_disable_gpe
- *
- * PARAMETERS: gpe_device - Parent GPE Device. NULL for GPE0/GPE1
- * gpe_number - GPE level within the GPE block
- *
- * RETURN: Status
- *
- * DESCRIPTION: Remove a reference to a GPE. When the last reference is
- * removed, only then is the GPE disabled (for runtime GPEs), or
- * the GPE mask bit disabled (for wake GPEs)
- *
- ******************************************************************************/
-acpi_status acpi_disable_gpe(acpi_handle gpe_device, u32 gpe_number)
-{
- acpi_status status = AE_BAD_PARAMETER;
- struct acpi_gpe_event_info *gpe_event_info;
- acpi_cpu_flags flags;
-
- ACPI_FUNCTION_TRACE(acpi_disable_gpe);
-
- flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
-
- /* Ensure that we have a valid GPE number */
-
- gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number);
- if (gpe_event_info) {
- status = acpi_raw_disable_gpe(gpe_event_info) ;
- }
-
- acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
- return_ACPI_STATUS(status);
-}
-ACPI_EXPORT_SYMBOL(acpi_disable_gpe)
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_gpe_can_wake
- *
- * PARAMETERS: gpe_device - Parent GPE Device. NULL for GPE0/GPE1
- * gpe_number - GPE level within the GPE block
- *
- * RETURN: Status
- *
- * DESCRIPTION: Set the ACPI_GPE_CAN_WAKE flag for the given GPE. If the GPE
- * has a corresponding method and is currently enabled, disable it
- * (GPEs with corresponding methods are enabled unconditionally
- * during initialization, but GPEs that can wake up are expected
- * to be initially disabled).
- *
- ******************************************************************************/
-acpi_status acpi_gpe_can_wake(acpi_handle gpe_device, u32 gpe_number)
-{
- acpi_status status = AE_OK;
- struct acpi_gpe_event_info *gpe_event_info;
- acpi_cpu_flags flags;
-
- ACPI_FUNCTION_TRACE(acpi_gpe_can_wake);
-
- flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
-
- /* Ensure that we have a valid GPE number */
-
- gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number);
- if (gpe_event_info) {
- gpe_event_info->flags |= ACPI_GPE_CAN_WAKE;
- } else {
- status = AE_BAD_PARAMETER;
- }
-
- acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
- return_ACPI_STATUS(status);
-}
-ACPI_EXPORT_SYMBOL(acpi_gpe_can_wake)
-
-/*******************************************************************************
- *
* FUNCTION: acpi_disable_event
*
* PARAMETERS: Event - The fixed eventto be enabled
@@ -483,44 +297,6 @@ ACPI_EXPORT_SYMBOL(acpi_clear_event)
/*******************************************************************************
*
- * FUNCTION: acpi_clear_gpe
- *
- * PARAMETERS: gpe_device - Parent GPE Device. NULL for GPE0/GPE1
- * gpe_number - GPE level within the GPE block
- *
- * RETURN: Status
- *
- * DESCRIPTION: Clear an ACPI event (general purpose)
- *
- ******************************************************************************/
-acpi_status acpi_clear_gpe(acpi_handle gpe_device, u32 gpe_number)
-{
- acpi_status status = AE_OK;
- struct acpi_gpe_event_info *gpe_event_info;
- acpi_cpu_flags flags;
-
- ACPI_FUNCTION_TRACE(acpi_clear_gpe);
-
- flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
-
- /* Ensure that we have a valid GPE number */
-
- gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number);
- if (!gpe_event_info) {
- status = AE_BAD_PARAMETER;
- goto unlock_and_exit;
- }
-
- status = acpi_hw_clear_gpe(gpe_event_info);
-
- unlock_and_exit:
- acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
- return_ACPI_STATUS(status);
-}
-
-ACPI_EXPORT_SYMBOL(acpi_clear_gpe)
-/*******************************************************************************
- *
* FUNCTION: acpi_get_event_status
*
* PARAMETERS: Event - The fixed event
@@ -575,379 +351,3 @@ acpi_status acpi_get_event_status(u32 event, acpi_event_status * event_status)
}
ACPI_EXPORT_SYMBOL(acpi_get_event_status)
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_get_gpe_status
- *
- * PARAMETERS: gpe_device - Parent GPE Device. NULL for GPE0/GPE1
- * gpe_number - GPE level within the GPE block
- * event_status - Where the current status of the event will
- * be returned
- *
- * RETURN: Status
- *
- * DESCRIPTION: Get status of an event (general purpose)
- *
- ******************************************************************************/
-acpi_status
-acpi_get_gpe_status(acpi_handle gpe_device,
- u32 gpe_number, acpi_event_status *event_status)
-{
- acpi_status status = AE_OK;
- struct acpi_gpe_event_info *gpe_event_info;
- acpi_cpu_flags flags;
-
- ACPI_FUNCTION_TRACE(acpi_get_gpe_status);
-
- flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
-
- /* Ensure that we have a valid GPE number */
-
- gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number);
- if (!gpe_event_info) {
- status = AE_BAD_PARAMETER;
- goto unlock_and_exit;
- }
-
- /* Obtain status on the requested GPE number */
-
- status = acpi_hw_get_gpe_status(gpe_event_info, event_status);
-
- if (gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK)
- *event_status |= ACPI_EVENT_FLAG_HANDLE;
-
- unlock_and_exit:
- acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
- return_ACPI_STATUS(status);
-}
-
-ACPI_EXPORT_SYMBOL(acpi_get_gpe_status)
-/*******************************************************************************
- *
- * FUNCTION: acpi_install_gpe_block
- *
- * PARAMETERS: gpe_device - Handle to the parent GPE Block Device
- * gpe_block_address - Address and space_iD
- * register_count - Number of GPE register pairs in the block
- * interrupt_number - H/W interrupt for the block
- *
- * RETURN: Status
- *
- * DESCRIPTION: Create and Install a block of GPE registers
- *
- ******************************************************************************/
-acpi_status
-acpi_install_gpe_block(acpi_handle gpe_device,
- struct acpi_generic_address *gpe_block_address,
- u32 register_count, u32 interrupt_number)
-{
- acpi_status status = AE_OK;
- union acpi_operand_object *obj_desc;
- struct acpi_namespace_node *node;
- struct acpi_gpe_block_info *gpe_block;
-
- ACPI_FUNCTION_TRACE(acpi_install_gpe_block);
-
- if ((!gpe_device) || (!gpe_block_address) || (!register_count)) {
- return_ACPI_STATUS(AE_BAD_PARAMETER);
- }
-
- status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
- if (ACPI_FAILURE(status)) {
- return (status);
- }
-
- node = acpi_ns_validate_handle(gpe_device);
- if (!node) {
- status = AE_BAD_PARAMETER;
- goto unlock_and_exit;
- }
-
- /*
- * For user-installed GPE Block Devices, the gpe_block_base_number
- * is always zero
- */
- status =
- acpi_ev_create_gpe_block(node, gpe_block_address, register_count, 0,
- interrupt_number, &gpe_block);
- if (ACPI_FAILURE(status)) {
- goto unlock_and_exit;
- }
-
- /* Install block in the device_object attached to the node */
-
- obj_desc = acpi_ns_get_attached_object(node);
- if (!obj_desc) {
-
- /*
- * No object, create a new one (Device nodes do not always have
- * an attached object)
- */
- obj_desc = acpi_ut_create_internal_object(ACPI_TYPE_DEVICE);
- if (!obj_desc) {
- status = AE_NO_MEMORY;
- goto unlock_and_exit;
- }
-
- status =
- acpi_ns_attach_object(node, obj_desc, ACPI_TYPE_DEVICE);
-
- /* Remove local reference to the object */
-
- acpi_ut_remove_reference(obj_desc);
-
- if (ACPI_FAILURE(status)) {
- goto unlock_and_exit;
- }
- }
-
- /* Now install the GPE block in the device_object */
-
- obj_desc->device.gpe_block = gpe_block;
-
- unlock_and_exit:
- (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
- return_ACPI_STATUS(status);
-}
-
-ACPI_EXPORT_SYMBOL(acpi_install_gpe_block)
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_remove_gpe_block
- *
- * PARAMETERS: gpe_device - Handle to the parent GPE Block Device
- *
- * RETURN: Status
- *
- * DESCRIPTION: Remove a previously installed block of GPE registers
- *
- ******************************************************************************/
-acpi_status acpi_remove_gpe_block(acpi_handle gpe_device)
-{
- union acpi_operand_object *obj_desc;
- acpi_status status;
- struct acpi_namespace_node *node;
-
- ACPI_FUNCTION_TRACE(acpi_remove_gpe_block);
-
- if (!gpe_device) {
- return_ACPI_STATUS(AE_BAD_PARAMETER);
- }
-
- status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
- if (ACPI_FAILURE(status)) {
- return (status);
- }
-
- node = acpi_ns_validate_handle(gpe_device);
- if (!node) {
- status = AE_BAD_PARAMETER;
- goto unlock_and_exit;
- }
-
- /* Get the device_object attached to the node */
-
- obj_desc = acpi_ns_get_attached_object(node);
- if (!obj_desc || !obj_desc->device.gpe_block) {
- return_ACPI_STATUS(AE_NULL_OBJECT);
- }
-
- /* Delete the GPE block (but not the device_object) */
-
- status = acpi_ev_delete_gpe_block(obj_desc->device.gpe_block);
- if (ACPI_SUCCESS(status)) {
- obj_desc->device.gpe_block = NULL;
- }
-
- unlock_and_exit:
- (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
- return_ACPI_STATUS(status);
-}
-
-ACPI_EXPORT_SYMBOL(acpi_remove_gpe_block)
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_get_gpe_device
- *
- * PARAMETERS: Index - System GPE index (0-current_gpe_count)
- * gpe_device - Where the parent GPE Device is returned
- *
- * RETURN: Status
- *
- * DESCRIPTION: Obtain the GPE device associated with the input index. A NULL
- * gpe device indicates that the gpe number is contained in one of
- * the FADT-defined gpe blocks. Otherwise, the GPE block device.
- *
- ******************************************************************************/
-acpi_status
-acpi_get_gpe_device(u32 index, acpi_handle *gpe_device)
-{
- struct acpi_gpe_device_info info;
- acpi_status status;
-
- ACPI_FUNCTION_TRACE(acpi_get_gpe_device);
-
- if (!gpe_device) {
- return_ACPI_STATUS(AE_BAD_PARAMETER);
- }
-
- if (index >= acpi_current_gpe_count) {
- return_ACPI_STATUS(AE_NOT_EXIST);
- }
-
- /* Setup and walk the GPE list */
-
- info.index = index;
- info.status = AE_NOT_EXIST;
- info.gpe_device = NULL;
- info.next_block_base_index = 0;
-
- status = acpi_ev_walk_gpe_list(acpi_ev_get_gpe_device, &info);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- }
-
- *gpe_device = info.gpe_device;
- return_ACPI_STATUS(info.status);
-}
-
-ACPI_EXPORT_SYMBOL(acpi_get_gpe_device)
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_ev_get_gpe_device
- *
- * PARAMETERS: GPE_WALK_CALLBACK
- *
- * RETURN: Status
- *
- * DESCRIPTION: Matches the input GPE index (0-current_gpe_count) with a GPE
- * block device. NULL if the GPE is one of the FADT-defined GPEs.
- *
- ******************************************************************************/
-static acpi_status
-acpi_ev_get_gpe_device(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
- struct acpi_gpe_block_info *gpe_block, void *context)
-{
- struct acpi_gpe_device_info *info = context;
-
- /* Increment Index by the number of GPEs in this block */
-
- info->next_block_base_index += gpe_block->gpe_count;
-
- if (info->index < info->next_block_base_index) {
- /*
- * The GPE index is within this block, get the node. Leave the node
- * NULL for the FADT-defined GPEs
- */
- if ((gpe_block->node)->type == ACPI_TYPE_DEVICE) {
- info->gpe_device = gpe_block->node;
- }
-
- info->status = AE_OK;
- return (AE_CTRL_END);
- }
-
- return (AE_OK);
-}
-
-/******************************************************************************
- *
- * FUNCTION: acpi_disable_all_gpes
- *
- * PARAMETERS: None
- *
- * RETURN: Status
- *
- * DESCRIPTION: Disable and clear all GPEs in all GPE blocks
- *
- ******************************************************************************/
-
-acpi_status acpi_disable_all_gpes(void)
-{
- acpi_status status;
-
- ACPI_FUNCTION_TRACE(acpi_disable_all_gpes);
-
- status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- }
-
- status = acpi_hw_disable_all_gpes();
- (void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
-
- return_ACPI_STATUS(status);
-}
-
-/******************************************************************************
- *
- * FUNCTION: acpi_enable_all_runtime_gpes
- *
- * PARAMETERS: None
- *
- * RETURN: Status
- *
- * DESCRIPTION: Enable all "runtime" GPEs, in all GPE blocks
- *
- ******************************************************************************/
-
-acpi_status acpi_enable_all_runtime_gpes(void)
-{
- acpi_status status;
-
- ACPI_FUNCTION_TRACE(acpi_enable_all_runtime_gpes);
-
- status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- }
-
- status = acpi_hw_enable_all_runtime_gpes();
- (void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
-
- return_ACPI_STATUS(status);
-}
-
-/******************************************************************************
- *
- * FUNCTION: acpi_update_gpes
- *
- * PARAMETERS: None
- *
- * RETURN: None
- *
- * DESCRIPTION: Enable all GPEs that have associated _Lxx or _Exx methods and
- * are not pointed to by any device _PRW methods indicating that
- * these GPEs are generally intended for system or device wakeup
- * (such GPEs have to be enabled directly when the devices whose
- * _PRW methods point to them are set up for wakeup signaling).
- *
- ******************************************************************************/
-
-acpi_status acpi_update_gpes(void)
-{
- acpi_status status;
-
- ACPI_FUNCTION_TRACE(acpi_update_gpes);
-
- status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- } else if (acpi_all_gpes_initialized) {
- goto unlock;
- }
-
- status = acpi_ev_walk_gpe_list(acpi_ev_initialize_gpe_block, NULL);
- if (ACPI_SUCCESS(status)) {
- acpi_all_gpes_initialized = TRUE;
- }
-
-unlock:
- (void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
-
- return_ACPI_STATUS(status);
-}
diff --git a/drivers/acpi/acpica/evxfgpe.c b/drivers/acpi/acpica/evxfgpe.c
new file mode 100644
index 0000000..e9562a7
--- /dev/null
+++ b/drivers/acpi/acpica/evxfgpe.c
@@ -0,0 +1,669 @@
+/******************************************************************************
+ *
+ * Module Name: evxfgpe - External Interfaces for General Purpose Events (GPEs)
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2011, Intel Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ * substantially similar to the "NO WARRANTY" disclaimer below
+ * ("Disclaimer") and any redistribution must be conditioned upon
+ * including a substantially similar Disclaimer requirement for further
+ * binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ * of any contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * 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 OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+#include "accommon.h"
+#include "acevents.h"
+#include "acnamesp.h"
+
+#define _COMPONENT ACPI_EVENTS
+ACPI_MODULE_NAME("evxfgpe")
+
+/******************************************************************************
+ *
+ * FUNCTION: acpi_update_all_gpes
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Complete GPE initialization and enable all GPEs that have
+ * associated _Lxx or _Exx methods and are not pointed to by any
+ * device _PRW methods (this indicates that these GPEs are
+ * generally intended for system or device wakeup. Such GPEs
+ * have to be enabled directly when the devices whose _PRW
+ * methods point to them are set up for wakeup signaling.)
+ *
+ * NOTE: Should be called after any GPEs are added to the system. Primarily,
+ * after the system _PRW methods have been run, but also after a GPE Block
+ * Device has been added or if any new GPE methods have been added via a
+ * dynamic table load.
+ *
+ ******************************************************************************/
+
+acpi_status acpi_update_all_gpes(void)
+{
+ acpi_status status;
+
+ ACPI_FUNCTION_TRACE(acpi_update_all_gpes);
+
+ status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ if (acpi_gbl_all_gpes_initialized) {
+ goto unlock_and_exit;
+ }
+
+ status = acpi_ev_walk_gpe_list(acpi_ev_initialize_gpe_block, NULL);
+ if (ACPI_SUCCESS(status)) {
+ acpi_gbl_all_gpes_initialized = TRUE;
+ }
+
+unlock_and_exit:
+ (void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
+
+ return_ACPI_STATUS(status);
+}
+
+ACPI_EXPORT_SYMBOL(acpi_update_all_gpes)
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_enable_gpe
+ *
+ * PARAMETERS: gpe_device - Parent GPE Device. NULL for GPE0/GPE1
+ * gpe_number - GPE level within the GPE block
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Add a reference to a GPE. On the first reference, the GPE is
+ * hardware-enabled.
+ *
+ ******************************************************************************/
+
+acpi_status acpi_enable_gpe(acpi_handle gpe_device, u32 gpe_number)
+{
+ acpi_status status = AE_BAD_PARAMETER;
+ struct acpi_gpe_event_info *gpe_event_info;
+ acpi_cpu_flags flags;
+
+ ACPI_FUNCTION_TRACE(acpi_enable_gpe);
+
+ flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
+
+ /* Ensure that we have a valid GPE number */
+
+ gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number);
+ if (gpe_event_info) {
+ status = acpi_ev_add_gpe_reference(gpe_event_info);
+ }
+
+ acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
+ return_ACPI_STATUS(status);
+}
+ACPI_EXPORT_SYMBOL(acpi_enable_gpe)
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_disable_gpe
+ *
+ * PARAMETERS: gpe_device - Parent GPE Device. NULL for GPE0/GPE1
+ * gpe_number - GPE level within the GPE block
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Remove a reference to a GPE. When the last reference is
+ * removed, only then is the GPE disabled (for runtime GPEs), or
+ * the GPE mask bit disabled (for wake GPEs)
+ *
+ ******************************************************************************/
+
+acpi_status acpi_disable_gpe(acpi_handle gpe_device, u32 gpe_number)
+{
+ acpi_status status = AE_BAD_PARAMETER;
+ struct acpi_gpe_event_info *gpe_event_info;
+ acpi_cpu_flags flags;
+
+ ACPI_FUNCTION_TRACE(acpi_disable_gpe);
+
+ flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
+
+ /* Ensure that we have a valid GPE number */
+
+ gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number);
+ if (gpe_event_info) {
+ status = acpi_ev_remove_gpe_reference(gpe_event_info) ;
+ }
+
+ acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
+ return_ACPI_STATUS(status);
+}
+ACPI_EXPORT_SYMBOL(acpi_disable_gpe)
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_setup_gpe_for_wake
+ *
+ * PARAMETERS: wake_device - Device associated with the GPE (via _PRW)
+ * gpe_device - Parent GPE Device. NULL for GPE0/GPE1
+ * gpe_number - GPE level within the GPE block
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Mark a GPE as having the ability to wake the system. This
+ * interface is intended to be used as the host executes the
+ * _PRW methods (Power Resources for Wake) in the system tables.
+ * Each _PRW appears under a Device Object (The wake_device), and
+ * contains the info for the wake GPE associated with the
+ * wake_device.
+ *
+ ******************************************************************************/
+acpi_status
+acpi_setup_gpe_for_wake(acpi_handle wake_device,
+ acpi_handle gpe_device, u32 gpe_number)
+{
+ acpi_status status = AE_BAD_PARAMETER;
+ struct acpi_gpe_event_info *gpe_event_info;
+ struct acpi_namespace_node *device_node;
+ acpi_cpu_flags flags;
+
+ ACPI_FUNCTION_TRACE(acpi_setup_gpe_for_wake);
+
+ /* Parameter Validation */
+
+ if (!wake_device) {
+ /*
+ * By forcing wake_device to be valid, we automatically enable the
+ * implicit notify feature on all hosts.
+ */
+ return_ACPI_STATUS(AE_BAD_PARAMETER);
+ }
+
+ /* Validate wake_device is of type Device */
+
+ device_node = ACPI_CAST_PTR(struct acpi_namespace_node, wake_device);
+ if (device_node->type != ACPI_TYPE_DEVICE) {
+ return_ACPI_STATUS(AE_BAD_PARAMETER);
+ }
+
+ flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
+
+ /* Ensure that we have a valid GPE number */
+
+ gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number);
+ if (gpe_event_info) {
+ /*
+ * If there is no method or handler for this GPE, then the
+ * wake_device will be notified whenever this GPE fires (aka
+ * "implicit notify") Note: The GPE is assumed to be
+ * level-triggered (for windows compatibility).
+ */
+ if ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) ==
+ ACPI_GPE_DISPATCH_NONE) {
+ gpe_event_info->flags =
+ (ACPI_GPE_DISPATCH_NOTIFY |
+ ACPI_GPE_LEVEL_TRIGGERED);
+ gpe_event_info->dispatch.device_node = device_node;
+ }
+
+ gpe_event_info->flags |= ACPI_GPE_CAN_WAKE;
+ status = AE_OK;
+ }
+
+ acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
+ return_ACPI_STATUS(status);
+}
+ACPI_EXPORT_SYMBOL(acpi_setup_gpe_for_wake)
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_set_gpe_wake_mask
+ *
+ * PARAMETERS: gpe_device - Parent GPE Device. NULL for GPE0/GPE1
+ * gpe_number - GPE level within the GPE block
+ * Action - Enable or Disable
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Set or clear the GPE's wakeup enable mask bit. The GPE must
+ * already be marked as a WAKE GPE.
+ *
+ ******************************************************************************/
+
+acpi_status acpi_set_gpe_wake_mask(acpi_handle gpe_device, u32 gpe_number, u8 action)
+{
+ acpi_status status = AE_OK;
+ struct acpi_gpe_event_info *gpe_event_info;
+ struct acpi_gpe_register_info *gpe_register_info;
+ acpi_cpu_flags flags;
+ u32 register_bit;
+
+ ACPI_FUNCTION_TRACE(acpi_set_gpe_wake_mask);
+
+ flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
+
+ /*
+ * Ensure that we have a valid GPE number and that this GPE is in
+ * fact a wake GPE
+ */
+ gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number);
+ if (!gpe_event_info) {
+ status = AE_BAD_PARAMETER;
+ goto unlock_and_exit;
+ }
+
+ if (!(gpe_event_info->flags & ACPI_GPE_CAN_WAKE)) {
+ status = AE_TYPE;
+ goto unlock_and_exit;
+ }
+
+ gpe_register_info = gpe_event_info->register_info;
+ if (!gpe_register_info) {
+ status = AE_NOT_EXIST;
+ goto unlock_and_exit;
+ }
+
+ register_bit =
+ acpi_hw_get_gpe_register_bit(gpe_event_info, gpe_register_info);
+
+ /* Perform the action */
+
+ switch (action) {
+ case ACPI_GPE_ENABLE:
+ ACPI_SET_BIT(gpe_register_info->enable_for_wake,
+ (u8)register_bit);
+ break;
+
+ case ACPI_GPE_DISABLE:
+ ACPI_CLEAR_BIT(gpe_register_info->enable_for_wake,
+ (u8)register_bit);
+ break;
+
+ default:
+ ACPI_ERROR((AE_INFO, "%u, Invalid action", action));
+ status = AE_BAD_PARAMETER;
+ break;
+ }
+
+unlock_and_exit:
+ acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
+ return_ACPI_STATUS(status);
+}
+
+ACPI_EXPORT_SYMBOL(acpi_set_gpe_wake_mask)
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_clear_gpe
+ *
+ * PARAMETERS: gpe_device - Parent GPE Device. NULL for GPE0/GPE1
+ * gpe_number - GPE level within the GPE block
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Clear an ACPI event (general purpose)
+ *
+ ******************************************************************************/
+acpi_status acpi_clear_gpe(acpi_handle gpe_device, u32 gpe_number)
+{
+ acpi_status status = AE_OK;
+ struct acpi_gpe_event_info *gpe_event_info;
+ acpi_cpu_flags flags;
+
+ ACPI_FUNCTION_TRACE(acpi_clear_gpe);
+
+ flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
+
+ /* Ensure that we have a valid GPE number */
+
+ gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number);
+ if (!gpe_event_info) {
+ status = AE_BAD_PARAMETER;
+ goto unlock_and_exit;
+ }
+
+ status = acpi_hw_clear_gpe(gpe_event_info);
+
+ unlock_and_exit:
+ acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
+ return_ACPI_STATUS(status);
+}
+
+ACPI_EXPORT_SYMBOL(acpi_clear_gpe)
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_get_gpe_status
+ *
+ * PARAMETERS: gpe_device - Parent GPE Device. NULL for GPE0/GPE1
+ * gpe_number - GPE level within the GPE block
+ * event_status - Where the current status of the event will
+ * be returned
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Get the current status of a GPE (signalled/not_signalled)
+ *
+ ******************************************************************************/
+acpi_status
+acpi_get_gpe_status(acpi_handle gpe_device,
+ u32 gpe_number, acpi_event_status *event_status)
+{
+ acpi_status status = AE_OK;
+ struct acpi_gpe_event_info *gpe_event_info;
+ acpi_cpu_flags flags;
+
+ ACPI_FUNCTION_TRACE(acpi_get_gpe_status);
+
+ flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
+
+ /* Ensure that we have a valid GPE number */
+
+ gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number);
+ if (!gpe_event_info) {
+ status = AE_BAD_PARAMETER;
+ goto unlock_and_exit;
+ }
+
+ /* Obtain status on the requested GPE number */
+
+ status = acpi_hw_get_gpe_status(gpe_event_info, event_status);
+
+ if (gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK)
+ *event_status |= ACPI_EVENT_FLAG_HANDLE;
+
+ unlock_and_exit:
+ acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
+ return_ACPI_STATUS(status);
+}
+
+ACPI_EXPORT_SYMBOL(acpi_get_gpe_status)
+
+/******************************************************************************
+ *
+ * FUNCTION: acpi_disable_all_gpes
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Disable and clear all GPEs in all GPE blocks
+ *
+ ******************************************************************************/
+
+acpi_status acpi_disable_all_gpes(void)
+{
+ acpi_status status;
+
+ ACPI_FUNCTION_TRACE(acpi_disable_all_gpes);
+
+ status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ status = acpi_hw_disable_all_gpes();
+ (void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
+
+ return_ACPI_STATUS(status);
+}
+
+ACPI_EXPORT_SYMBOL(acpi_disable_all_gpes)
+
+/******************************************************************************
+ *
+ * FUNCTION: acpi_enable_all_runtime_gpes
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Enable all "runtime" GPEs, in all GPE blocks
+ *
+ ******************************************************************************/
+
+acpi_status acpi_enable_all_runtime_gpes(void)
+{
+ acpi_status status;
+
+ ACPI_FUNCTION_TRACE(acpi_enable_all_runtime_gpes);
+
+ status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ status = acpi_hw_enable_all_runtime_gpes();
+ (void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
+
+ return_ACPI_STATUS(status);
+}
+
+ACPI_EXPORT_SYMBOL(acpi_enable_all_runtime_gpes)
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_install_gpe_block
+ *
+ * PARAMETERS: gpe_device - Handle to the parent GPE Block Device
+ * gpe_block_address - Address and space_iD
+ * register_count - Number of GPE register pairs in the block
+ * interrupt_number - H/W interrupt for the block
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Create and Install a block of GPE registers. The GPEs are not
+ * enabled here.
+ *
+ ******************************************************************************/
+acpi_status
+acpi_install_gpe_block(acpi_handle gpe_device,
+ struct acpi_generic_address *gpe_block_address,
+ u32 register_count, u32 interrupt_number)
+{
+ acpi_status status;
+ union acpi_operand_object *obj_desc;
+ struct acpi_namespace_node *node;
+ struct acpi_gpe_block_info *gpe_block;
+
+ ACPI_FUNCTION_TRACE(acpi_install_gpe_block);
+
+ if ((!gpe_device) || (!gpe_block_address) || (!register_count)) {
+ return_ACPI_STATUS(AE_BAD_PARAMETER);
+ }
+
+ status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
+ if (ACPI_FAILURE(status)) {
+ return (status);
+ }
+
+ node = acpi_ns_validate_handle(gpe_device);
+ if (!node) {
+ status = AE_BAD_PARAMETER;
+ goto unlock_and_exit;
+ }
+
+ /*
+ * For user-installed GPE Block Devices, the gpe_block_base_number
+ * is always zero
+ */
+ status =
+ acpi_ev_create_gpe_block(node, gpe_block_address, register_count, 0,
+ interrupt_number, &gpe_block);
+ if (ACPI_FAILURE(status)) {
+ goto unlock_and_exit;
+ }
+
+ /* Install block in the device_object attached to the node */
+
+ obj_desc = acpi_ns_get_attached_object(node);
+ if (!obj_desc) {
+
+ /*
+ * No object, create a new one (Device nodes do not always have
+ * an attached object)
+ */
+ obj_desc = acpi_ut_create_internal_object(ACPI_TYPE_DEVICE);
+ if (!obj_desc) {
+ status = AE_NO_MEMORY;
+ goto unlock_and_exit;
+ }
+
+ status =
+ acpi_ns_attach_object(node, obj_desc, ACPI_TYPE_DEVICE);
+
+ /* Remove local reference to the object */
+
+ acpi_ut_remove_reference(obj_desc);
+
+ if (ACPI_FAILURE(status)) {
+ goto unlock_and_exit;
+ }
+ }
+
+ /* Now install the GPE block in the device_object */
+
+ obj_desc->device.gpe_block = gpe_block;
+
+ unlock_and_exit:
+ (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
+ return_ACPI_STATUS(status);
+}
+
+ACPI_EXPORT_SYMBOL(acpi_install_gpe_block)
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_remove_gpe_block
+ *
+ * PARAMETERS: gpe_device - Handle to the parent GPE Block Device
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Remove a previously installed block of GPE registers
+ *
+ ******************************************************************************/
+acpi_status acpi_remove_gpe_block(acpi_handle gpe_device)
+{
+ union acpi_operand_object *obj_desc;
+ acpi_status status;
+ struct acpi_namespace_node *node;
+
+ ACPI_FUNCTION_TRACE(acpi_remove_gpe_block);
+
+ if (!gpe_device) {
+ return_ACPI_STATUS(AE_BAD_PARAMETER);
+ }
+
+ status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
+ if (ACPI_FAILURE(status)) {
+ return (status);
+ }
+
+ node = acpi_ns_validate_handle(gpe_device);
+ if (!node) {
+ status = AE_BAD_PARAMETER;
+ goto unlock_and_exit;
+ }
+
+ /* Get the device_object attached to the node */
+
+ obj_desc = acpi_ns_get_attached_object(node);
+ if (!obj_desc || !obj_desc->device.gpe_block) {
+ return_ACPI_STATUS(AE_NULL_OBJECT);
+ }
+
+ /* Delete the GPE block (but not the device_object) */
+
+ status = acpi_ev_delete_gpe_block(obj_desc->device.gpe_block);
+ if (ACPI_SUCCESS(status)) {
+ obj_desc->device.gpe_block = NULL;
+ }
+
+ unlock_and_exit:
+ (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
+ return_ACPI_STATUS(status);
+}
+
+ACPI_EXPORT_SYMBOL(acpi_remove_gpe_block)
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_get_gpe_device
+ *
+ * PARAMETERS: Index - System GPE index (0-current_gpe_count)
+ * gpe_device - Where the parent GPE Device is returned
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Obtain the GPE device associated with the input index. A NULL
+ * gpe device indicates that the gpe number is contained in one of
+ * the FADT-defined gpe blocks. Otherwise, the GPE block device.
+ *
+ ******************************************************************************/
+acpi_status
+acpi_get_gpe_device(u32 index, acpi_handle *gpe_device)
+{
+ struct acpi_gpe_device_info info;
+ acpi_status status;
+
+ ACPI_FUNCTION_TRACE(acpi_get_gpe_device);
+
+ if (!gpe_device) {
+ return_ACPI_STATUS(AE_BAD_PARAMETER);
+ }
+
+ if (index >= acpi_current_gpe_count) {
+ return_ACPI_STATUS(AE_NOT_EXIST);
+ }
+
+ /* Setup and walk the GPE list */
+
+ info.index = index;
+ info.status = AE_NOT_EXIST;
+ info.gpe_device = NULL;
+ info.next_block_base_index = 0;
+
+ status = acpi_ev_walk_gpe_list(acpi_ev_get_gpe_device, &info);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ *gpe_device = ACPI_CAST_PTR(acpi_handle, info.gpe_device);
+ return_ACPI_STATUS(info.status);
+}
+
+ACPI_EXPORT_SYMBOL(acpi_get_gpe_device)
diff --git a/drivers/acpi/acpica/evxfregn.c b/drivers/acpi/acpica/evxfregn.c
index ce9314f..eb73867 100644
--- a/drivers/acpi/acpica/evxfregn.c
+++ b/drivers/acpi/acpica/evxfregn.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exconfig.c b/drivers/acpi/acpica/exconfig.c
index 1883220..745a42b 100644
--- a/drivers/acpi/acpica/exconfig.c
+++ b/drivers/acpi/acpica/exconfig.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exconvrt.c b/drivers/acpi/acpica/exconvrt.c
index b73bc50..74162a1 100644
--- a/drivers/acpi/acpica/exconvrt.c
+++ b/drivers/acpi/acpica/exconvrt.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/excreate.c b/drivers/acpi/acpica/excreate.c
index 3c61b48..e7b372d 100644
--- a/drivers/acpi/acpica/excreate.c
+++ b/drivers/acpi/acpica/excreate.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -482,13 +482,11 @@ acpi_ex_create_method(u8 * aml_start,
obj_desc->method.aml_length = aml_length;
/*
- * Disassemble the method flags. Split off the Arg Count
- * for efficiency
+ * Disassemble the method flags. Split off the arg_count, Serialized
+ * flag, and sync_level for efficiency.
*/
method_flags = (u8) operand[1]->integer.value;
- obj_desc->method.method_flags =
- (u8) (method_flags & ~AML_METHOD_ARG_COUNT);
obj_desc->method.param_count =
(u8) (method_flags & AML_METHOD_ARG_COUNT);
@@ -497,6 +495,8 @@ acpi_ex_create_method(u8 * aml_start,
* created for this method when it is parsed.
*/
if (method_flags & AML_METHOD_SERIALIZED) {
+ obj_desc->method.info_flags = ACPI_METHOD_SERIALIZED;
+
/*
* ACPI 1.0: sync_level = 0
* ACPI 2.0: sync_level = sync_level in method declaration
diff --git a/drivers/acpi/acpica/exdebug.c b/drivers/acpi/acpica/exdebug.c
index be8c98b..c7a2f1e 100644
--- a/drivers/acpi/acpica/exdebug.c
+++ b/drivers/acpi/acpica/exdebug.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exdump.c b/drivers/acpi/acpica/exdump.c
index f067bbb..61b8c0e 100644
--- a/drivers/acpi/acpica/exdump.c
+++ b/drivers/acpi/acpica/exdump.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -122,7 +122,7 @@ static struct acpi_exdump_info acpi_ex_dump_event[2] = {
static struct acpi_exdump_info acpi_ex_dump_method[9] = {
{ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_method), NULL},
- {ACPI_EXD_UINT8, ACPI_EXD_OFFSET(method.method_flags), "Method Flags"},
+ {ACPI_EXD_UINT8, ACPI_EXD_OFFSET(method.info_flags), "Info Flags"},
{ACPI_EXD_UINT8, ACPI_EXD_OFFSET(method.param_count),
"Parameter Count"},
{ACPI_EXD_UINT8, ACPI_EXD_OFFSET(method.sync_level), "Sync Level"},
diff --git a/drivers/acpi/acpica/exfield.c b/drivers/acpi/acpica/exfield.c
index f17d2ff..0bde223 100644
--- a/drivers/acpi/acpica/exfield.c
+++ b/drivers/acpi/acpica/exfield.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exfldio.c b/drivers/acpi/acpica/exfldio.c
index 38293fd..6c79c29 100644
--- a/drivers/acpi/acpica/exfldio.c
+++ b/drivers/acpi/acpica/exfldio.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exmisc.c b/drivers/acpi/acpica/exmisc.c
index 95db4be0..703d88e 100644
--- a/drivers/acpi/acpica/exmisc.c
+++ b/drivers/acpi/acpica/exmisc.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exmutex.c b/drivers/acpi/acpica/exmutex.c
index 6af14e4..be1c56e 100644
--- a/drivers/acpi/acpica/exmutex.c
+++ b/drivers/acpi/acpica/exmutex.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exnames.c b/drivers/acpi/acpica/exnames.c
index d11e539..49ec049 100644
--- a/drivers/acpi/acpica/exnames.c
+++ b/drivers/acpi/acpica/exnames.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exoparg1.c b/drivers/acpi/acpica/exoparg1.c
index 84e4d18..236ead1 100644
--- a/drivers/acpi/acpica/exoparg1.c
+++ b/drivers/acpi/acpica/exoparg1.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exoparg2.c b/drivers/acpi/acpica/exoparg2.c
index 10e104c..2571b4a 100644
--- a/drivers/acpi/acpica/exoparg2.c
+++ b/drivers/acpi/acpica/exoparg2.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exoparg3.c b/drivers/acpi/acpica/exoparg3.c
index 7a08d23..1b48d9d 100644
--- a/drivers/acpi/acpica/exoparg3.c
+++ b/drivers/acpi/acpica/exoparg3.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exoparg6.c b/drivers/acpi/acpica/exoparg6.c
index 4b50730..f4a2787 100644
--- a/drivers/acpi/acpica/exoparg6.c
+++ b/drivers/acpi/acpica/exoparg6.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exprep.c b/drivers/acpi/acpica/exprep.c
index 7aae29f..cc95e20 100644
--- a/drivers/acpi/acpica/exprep.c
+++ b/drivers/acpi/acpica/exprep.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exregion.c b/drivers/acpi/acpica/exregion.c
index de17e10..f0d5e14 100644
--- a/drivers/acpi/acpica/exregion.c
+++ b/drivers/acpi/acpica/exregion.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exresnte.c b/drivers/acpi/acpica/exresnte.c
index 1fa4289..55997e4 100644
--- a/drivers/acpi/acpica/exresnte.c
+++ b/drivers/acpi/acpica/exresnte.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exresolv.c b/drivers/acpi/acpica/exresolv.c
index 7ca35ea..db502cd 100644
--- a/drivers/acpi/acpica/exresolv.c
+++ b/drivers/acpi/acpica/exresolv.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exresop.c b/drivers/acpi/acpica/exresop.c
index 8c97cfd..e3bb00c 100644
--- a/drivers/acpi/acpica/exresop.c
+++ b/drivers/acpi/acpica/exresop.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exstore.c b/drivers/acpi/acpica/exstore.c
index 1624436..c0c8842 100644
--- a/drivers/acpi/acpica/exstore.c
+++ b/drivers/acpi/acpica/exstore.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exstoren.c b/drivers/acpi/acpica/exstoren.c
index d4af684..a979017 100644
--- a/drivers/acpi/acpica/exstoren.c
+++ b/drivers/acpi/acpica/exstoren.c
@@ -7,7 +7,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exstorob.c b/drivers/acpi/acpica/exstorob.c
index e972b66..dc665cc 100644
--- a/drivers/acpi/acpica/exstorob.c
+++ b/drivers/acpi/acpica/exstorob.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exsystem.c b/drivers/acpi/acpica/exsystem.c
index 675aaa9..df66e7b 100644
--- a/drivers/acpi/acpica/exsystem.c
+++ b/drivers/acpi/acpica/exsystem.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exutils.c b/drivers/acpi/acpica/exutils.c
index 4093522..8ad9314 100644
--- a/drivers/acpi/acpica/exutils.c
+++ b/drivers/acpi/acpica/exutils.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/hwacpi.c b/drivers/acpi/acpica/hwacpi.c
index b44274a..fc380d3 100644
--- a/drivers/acpi/acpica/hwacpi.c
+++ b/drivers/acpi/acpica/hwacpi.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/hwgpe.c b/drivers/acpi/acpica/hwgpe.c
index 14750db..f610d88 100644
--- a/drivers/acpi/acpica/hwgpe.c
+++ b/drivers/acpi/acpica/hwgpe.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -62,10 +62,10 @@ acpi_hw_enable_wakeup_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
* PARAMETERS: gpe_event_info - Info block for the GPE
* gpe_register_info - Info block for the GPE register
*
- * RETURN: Status
+ * RETURN: Register mask with a one in the GPE bit position
*
- * DESCRIPTION: Compute GPE enable mask with one bit corresponding to the given
- * GPE set.
+ * DESCRIPTION: Compute the register mask for this GPE. One bit is set in the
+ * correct position for the input GPE.
*
******************************************************************************/
@@ -85,12 +85,12 @@ u32 acpi_hw_get_gpe_register_bit(struct acpi_gpe_event_info *gpe_event_info,
*
* RETURN: Status
*
- * DESCRIPTION: Enable or disable a single GPE in its enable register.
+ * DESCRIPTION: Enable or disable a single GPE in the parent enable register.
*
******************************************************************************/
acpi_status
-acpi_hw_low_set_gpe(struct acpi_gpe_event_info *gpe_event_info, u8 action)
+acpi_hw_low_set_gpe(struct acpi_gpe_event_info *gpe_event_info, u32 action)
{
struct acpi_gpe_register_info *gpe_register_info;
acpi_status status;
@@ -113,14 +113,20 @@ acpi_hw_low_set_gpe(struct acpi_gpe_event_info *gpe_event_info, u8 action)
return (status);
}
- /* Set ot clear just the bit that corresponds to this GPE */
+ /* Set or clear just the bit that corresponds to this GPE */
register_bit = acpi_hw_get_gpe_register_bit(gpe_event_info,
gpe_register_info);
switch (action) {
- case ACPI_GPE_COND_ENABLE:
- if (!(register_bit & gpe_register_info->enable_for_run))
+ case ACPI_GPE_CONDITIONAL_ENABLE:
+
+ /* Only enable if the enable_for_run bit is set */
+
+ if (!(register_bit & gpe_register_info->enable_for_run)) {
return (AE_BAD_PARAMETER);
+ }
+
+ /*lint -fallthrough */
case ACPI_GPE_ENABLE:
ACPI_SET_BIT(enable_mask, register_bit);
@@ -131,7 +137,7 @@ acpi_hw_low_set_gpe(struct acpi_gpe_event_info *gpe_event_info, u8 action)
break;
default:
- ACPI_ERROR((AE_INFO, "Invalid action\n"));
+ ACPI_ERROR((AE_INFO, "Invalid GPE Action, %u\n", action));
return (AE_BAD_PARAMETER);
}
@@ -168,13 +174,13 @@ acpi_status acpi_hw_clear_gpe(struct acpi_gpe_event_info * gpe_event_info)
return (AE_NOT_EXIST);
}
- register_bit = acpi_hw_get_gpe_register_bit(gpe_event_info,
- gpe_register_info);
-
/*
* Write a one to the appropriate bit in the status register to
* clear this GPE.
*/
+ register_bit =
+ acpi_hw_get_gpe_register_bit(gpe_event_info, gpe_register_info);
+
status = acpi_hw_write(register_bit,
&gpe_register_info->status_address);
@@ -201,8 +207,8 @@ acpi_hw_get_gpe_status(struct acpi_gpe_event_info * gpe_event_info,
u32 in_byte;
u32 register_bit;
struct acpi_gpe_register_info *gpe_register_info;
- acpi_status status;
acpi_event_status local_event_status = 0;
+ acpi_status status;
ACPI_FUNCTION_ENTRY();
diff --git a/drivers/acpi/acpica/hwpci.c b/drivers/acpi/acpica/hwpci.c
index ad21c7d..050fd22 100644
--- a/drivers/acpi/acpica/hwpci.c
+++ b/drivers/acpi/acpica/hwpci.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/hwregs.c b/drivers/acpi/acpica/hwregs.c
index 5d1273b..55accb7 100644
--- a/drivers/acpi/acpica/hwregs.c
+++ b/drivers/acpi/acpica/hwregs.c
@@ -7,7 +7,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/hwsleep.c b/drivers/acpi/acpica/hwsleep.c
index 3796811..2ac28bb 100644
--- a/drivers/acpi/acpica/hwsleep.c
+++ b/drivers/acpi/acpica/hwsleep.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/hwtimer.c b/drivers/acpi/acpica/hwtimer.c
index 1ef8e0b..9c8eb71 100644
--- a/drivers/acpi/acpica/hwtimer.c
+++ b/drivers/acpi/acpica/hwtimer.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/hwvalid.c b/drivers/acpi/acpica/hwvalid.c
index e1d9c77..5f16058 100644
--- a/drivers/acpi/acpica/hwvalid.c
+++ b/drivers/acpi/acpica/hwvalid.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/hwxface.c b/drivers/acpi/acpica/hwxface.c
index 50cc3be..6f98d21 100644
--- a/drivers/acpi/acpica/hwxface.c
+++ b/drivers/acpi/acpica/hwxface.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/nsaccess.c b/drivers/acpi/acpica/nsaccess.c
index 0cd925b..d93172f 100644
--- a/drivers/acpi/acpica/nsaccess.c
+++ b/drivers/acpi/acpica/nsaccess.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -163,9 +163,9 @@ acpi_status acpi_ns_root_initialize(void)
#else
/* Mark this as a very SPECIAL method */
- obj_desc->method.method_flags =
- AML_METHOD_INTERNAL_ONLY;
- obj_desc->method.extra.implementation =
+ obj_desc->method.info_flags =
+ ACPI_METHOD_INTERNAL_ONLY;
+ obj_desc->method.dispatch.implementation =
acpi_ut_osi_implementation;
#endif
break;
diff --git a/drivers/acpi/acpica/nsalloc.c b/drivers/acpi/acpica/nsalloc.c
index 1e5ff80..1d0ef15 100644
--- a/drivers/acpi/acpica/nsalloc.c
+++ b/drivers/acpi/acpica/nsalloc.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -234,8 +234,8 @@ void acpi_ns_install_node(struct acpi_walk_state *walk_state, struct acpi_namesp
* modified the namespace. This is used for cleanup when the
* method exits.
*/
- walk_state->method_desc->method.flags |=
- AOPOBJ_MODIFIED_NAMESPACE;
+ walk_state->method_desc->method.info_flags |=
+ ACPI_METHOD_MODIFIED_NAMESPACE;
}
}
@@ -341,6 +341,7 @@ void acpi_ns_delete_namespace_subtree(struct acpi_namespace_node *parent_node)
{
struct acpi_namespace_node *child_node = NULL;
u32 level = 1;
+ acpi_status status;
ACPI_FUNCTION_TRACE(ns_delete_namespace_subtree);
@@ -348,6 +349,13 @@ void acpi_ns_delete_namespace_subtree(struct acpi_namespace_node *parent_node)
return_VOID;
}
+ /* Lock namespace for possible update */
+
+ status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
+ if (ACPI_FAILURE(status)) {
+ return_VOID;
+ }
+
/*
* Traverse the tree of objects until we bubble back up
* to where we started.
@@ -397,6 +405,7 @@ void acpi_ns_delete_namespace_subtree(struct acpi_namespace_node *parent_node)
}
}
+ (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
return_VOID;
}
diff --git a/drivers/acpi/acpica/nsdump.c b/drivers/acpi/acpica/nsdump.c
index a54dc39..b683cc2 100644
--- a/drivers/acpi/acpica/nsdump.c
+++ b/drivers/acpi/acpica/nsdump.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -624,9 +624,22 @@ acpi_ns_dump_objects(acpi_object_type type,
acpi_owner_id owner_id, acpi_handle start_handle)
{
struct acpi_walk_info info;
+ acpi_status status;
ACPI_FUNCTION_ENTRY();
+ /*
+ * Just lock the entire namespace for the duration of the dump.
+ * We don't want any changes to the namespace during this time,
+ * especially the temporary nodes since we are going to display
+ * them also.
+ */
+ status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
+ if (ACPI_FAILURE(status)) {
+ acpi_os_printf("Could not acquire namespace mutex\n");
+ return;
+ }
+
info.debug_level = ACPI_LV_TABLES;
info.owner_id = owner_id;
info.display_type = display_type;
@@ -636,6 +649,8 @@ acpi_ns_dump_objects(acpi_object_type type,
ACPI_NS_WALK_TEMP_NODES,
acpi_ns_dump_one_object, NULL,
(void *)&info, NULL);
+
+ (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
}
#endif /* ACPI_FUTURE_USAGE */
diff --git a/drivers/acpi/acpica/nsdumpdv.c b/drivers/acpi/acpica/nsdumpdv.c
index d2a9792..2ed294b 100644
--- a/drivers/acpi/acpica/nsdumpdv.c
+++ b/drivers/acpi/acpica/nsdumpdv.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/nseval.c b/drivers/acpi/acpica/nseval.c
index f52829c..c1bd02b 100644
--- a/drivers/acpi/acpica/nseval.c
+++ b/drivers/acpi/acpica/nseval.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -389,7 +389,7 @@ acpi_ns_exec_module_code(union acpi_operand_object *method_obj,
* acpi_gbl_root_node->Object is NULL at PASS1.
*/
if ((type == ACPI_TYPE_DEVICE) && parent_node->object) {
- method_obj->method.extra.handler =
+ method_obj->method.dispatch.handler =
parent_node->object->device.handler;
}
diff --git a/drivers/acpi/acpica/nsinit.c b/drivers/acpi/acpica/nsinit.c
index 0cac7ec..fd7c638 100644
--- a/drivers/acpi/acpica/nsinit.c
+++ b/drivers/acpi/acpica/nsinit.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/nsload.c b/drivers/acpi/acpica/nsload.c
index df18be9..5f7dc69 100644
--- a/drivers/acpi/acpica/nsload.c
+++ b/drivers/acpi/acpica/nsload.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/nsnames.c b/drivers/acpi/acpica/nsnames.c
index d3104af..d5fa520 100644
--- a/drivers/acpi/acpica/nsnames.c
+++ b/drivers/acpi/acpica/nsnames.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/nsobject.c b/drivers/acpi/acpica/nsobject.c
index 41a9213..3bb8bf1 100644
--- a/drivers/acpi/acpica/nsobject.c
+++ b/drivers/acpi/acpica/nsobject.c
@@ -6,7 +6,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/nsparse.c b/drivers/acpi/acpica/nsparse.c
index 5808c89..b3234fa 100644
--- a/drivers/acpi/acpica/nsparse.c
+++ b/drivers/acpi/acpica/nsparse.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/nspredef.c b/drivers/acpi/acpica/nspredef.c
index 7096bcd..9fb03fa 100644
--- a/drivers/acpi/acpica/nspredef.c
+++ b/drivers/acpi/acpica/nspredef.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/nsrepair.c b/drivers/acpi/acpica/nsrepair.c
index d1c1366..1d76ac8 100644
--- a/drivers/acpi/acpica/nsrepair.c
+++ b/drivers/acpi/acpica/nsrepair.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/nsrepair2.c b/drivers/acpi/acpica/nsrepair2.c
index 4ef9f43..973883b 100644
--- a/drivers/acpi/acpica/nsrepair2.c
+++ b/drivers/acpi/acpica/nsrepair2.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/nssearch.c b/drivers/acpi/acpica/nssearch.c
index 41102a8..28b0d7a 100644
--- a/drivers/acpi/acpica/nssearch.c
+++ b/drivers/acpi/acpica/nssearch.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/nsutils.c b/drivers/acpi/acpica/nsutils.c
index a7d6ad9..cb1b104 100644
--- a/drivers/acpi/acpica/nsutils.c
+++ b/drivers/acpi/acpica/nsutils.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/nswalk.c b/drivers/acpi/acpica/nswalk.c
index 2cd5be8..345f0c3 100644
--- a/drivers/acpi/acpica/nswalk.c
+++ b/drivers/acpi/acpica/nswalk.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/nsxfeval.c b/drivers/acpi/acpica/nsxfeval.c
index ebef8a7..c53f004 100644
--- a/drivers/acpi/acpica/nsxfeval.c
+++ b/drivers/acpi/acpica/nsxfeval.c
@@ -6,7 +6,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/nsxfname.c b/drivers/acpi/acpica/nsxfname.c
index b01e45a..3fd4526 100644
--- a/drivers/acpi/acpica/nsxfname.c
+++ b/drivers/acpi/acpica/nsxfname.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -603,10 +603,9 @@ acpi_status acpi_install_method(u8 *buffer)
method_obj->method.param_count = (u8)
(method_flags & AML_METHOD_ARG_COUNT);
- method_obj->method.method_flags = (u8)
- (method_flags & ~AML_METHOD_ARG_COUNT);
-
if (method_flags & AML_METHOD_SERIALIZED) {
+ method_obj->method.info_flags = ACPI_METHOD_SERIALIZED;
+
method_obj->method.sync_level = (u8)
((method_flags & AML_METHOD_SYNC_LEVEL) >> 4);
}
diff --git a/drivers/acpi/acpica/nsxfobj.c b/drivers/acpi/acpica/nsxfobj.c
index a1f04e9..db7660f 100644
--- a/drivers/acpi/acpica/nsxfobj.c
+++ b/drivers/acpi/acpica/nsxfobj.c
@@ -6,7 +6,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/psargs.c b/drivers/acpi/acpica/psargs.c
index 7df1a4c..e1fad0e 100644
--- a/drivers/acpi/acpica/psargs.c
+++ b/drivers/acpi/acpica/psargs.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/psloop.c b/drivers/acpi/acpica/psloop.c
index 2f2e776..01dd70d 100644
--- a/drivers/acpi/acpica/psloop.c
+++ b/drivers/acpi/acpica/psloop.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -655,7 +655,7 @@ acpi_ps_link_module_code(union acpi_parse_object *parent_op,
method_obj->method.aml_start = aml_start;
method_obj->method.aml_length = aml_length;
method_obj->method.owner_id = owner_id;
- method_obj->method.flags |= AOPOBJ_MODULE_LEVEL;
+ method_obj->method.info_flags |= ACPI_METHOD_MODULE_LEVEL;
/*
* Save the parent node in next_object. This is cheating, but we
diff --git a/drivers/acpi/acpica/psopcode.c b/drivers/acpi/acpica/psopcode.c
index 2b0c3be..bed08de 100644
--- a/drivers/acpi/acpica/psopcode.c
+++ b/drivers/acpi/acpica/psopcode.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/psparse.c b/drivers/acpi/acpica/psparse.c
index 8d81542..9bb0cbd 100644
--- a/drivers/acpi/acpica/psparse.c
+++ b/drivers/acpi/acpica/psparse.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -55,7 +55,6 @@
#include "acparser.h"
#include "acdispat.h"
#include "amlcode.h"
-#include "acnamesp.h"
#include "acinterp.h"
#define _COMPONENT ACPI_PARSER
@@ -539,24 +538,16 @@ acpi_status acpi_ps_parse_aml(struct acpi_walk_state *walk_state)
/* Check for possible multi-thread reentrancy problem */
if ((status == AE_ALREADY_EXISTS) &&
- (!walk_state->method_desc->method.mutex)) {
- ACPI_INFO((AE_INFO,
- "Marking method %4.4s as Serialized because of AE_ALREADY_EXISTS error",
- walk_state->method_node->name.
- ascii));
-
+ (!(walk_state->method_desc->method.
+ info_flags & ACPI_METHOD_SERIALIZED))) {
/*
- * Method tried to create an object twice. The probable cause is
- * that the method cannot handle reentrancy.
- *
- * The method is marked not_serialized, but it tried to create
- * a named object, causing the second thread entrance to fail.
- * Workaround this problem by marking the method permanently
- * as Serialized.
+ * Method is not serialized and tried to create an object
+ * twice. The probable cause is that the method cannot
+ * handle reentrancy. Mark as "pending serialized" now, and
+ * then mark "serialized" when the last thread exits.
*/
- walk_state->method_desc->method.method_flags |=
- AML_METHOD_SERIALIZED;
- walk_state->method_desc->method.sync_level = 0;
+ walk_state->method_desc->method.info_flags |=
+ ACPI_METHOD_SERIALIZED_PENDING;
}
}
diff --git a/drivers/acpi/acpica/psscope.c b/drivers/acpi/acpica/psscope.c
index 40e2b27..a5faa13 100644
--- a/drivers/acpi/acpica/psscope.c
+++ b/drivers/acpi/acpica/psscope.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/pstree.c b/drivers/acpi/acpica/pstree.c
index d4b970c..f1464c0 100644
--- a/drivers/acpi/acpica/pstree.c
+++ b/drivers/acpi/acpica/pstree.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/psutils.c b/drivers/acpi/acpica/psutils.c
index fe29eee..7eda785 100644
--- a/drivers/acpi/acpica/psutils.c
+++ b/drivers/acpi/acpica/psutils.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/pswalk.c b/drivers/acpi/acpica/pswalk.c
index 8abb962..3312d63 100644
--- a/drivers/acpi/acpica/pswalk.c
+++ b/drivers/acpi/acpica/pswalk.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/psxface.c b/drivers/acpi/acpica/psxface.c
index c42f067..8086805 100644
--- a/drivers/acpi/acpica/psxface.c
+++ b/drivers/acpi/acpica/psxface.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -47,7 +47,6 @@
#include "acdispat.h"
#include "acinterp.h"
#include "actables.h"
-#include "amlcode.h"
#define _COMPONENT ACPI_PARSER
ACPI_MODULE_NAME("psxface")
@@ -285,15 +284,15 @@ acpi_status acpi_ps_execute_method(struct acpi_evaluate_info *info)
goto cleanup;
}
- if (info->obj_desc->method.flags & AOPOBJ_MODULE_LEVEL) {
+ if (info->obj_desc->method.info_flags & ACPI_METHOD_MODULE_LEVEL) {
walk_state->parse_flags |= ACPI_PARSE_MODULE_LEVEL;
}
/* Invoke an internal method if necessary */
- if (info->obj_desc->method.method_flags & AML_METHOD_INTERNAL_ONLY) {
+ if (info->obj_desc->method.info_flags & ACPI_METHOD_INTERNAL_ONLY) {
status =
- info->obj_desc->method.extra.implementation(walk_state);
+ info->obj_desc->method.dispatch.implementation(walk_state);
info->return_object = walk_state->return_desc;
/* Cleanup states */
diff --git a/drivers/acpi/acpica/rsaddr.c b/drivers/acpi/acpica/rsaddr.c
index 226c806..9e66f90 100644
--- a/drivers/acpi/acpica/rsaddr.c
+++ b/drivers/acpi/acpica/rsaddr.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/rscalc.c b/drivers/acpi/acpica/rscalc.c
index d6ebf7e..3a8a89e 100644
--- a/drivers/acpi/acpica/rscalc.c
+++ b/drivers/acpi/acpica/rscalc.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/rscreate.c b/drivers/acpi/acpica/rscreate.c
index c80a2ee..4ce6e11 100644
--- a/drivers/acpi/acpica/rscreate.c
+++ b/drivers/acpi/acpica/rscreate.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/rsdump.c b/drivers/acpi/acpica/rsdump.c
index f859b03..33db752 100644
--- a/drivers/acpi/acpica/rsdump.c
+++ b/drivers/acpi/acpica/rsdump.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/rsinfo.c b/drivers/acpi/acpica/rsinfo.c
index 1fd868b..f9ea608 100644
--- a/drivers/acpi/acpica/rsinfo.c
+++ b/drivers/acpi/acpica/rsinfo.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/rsio.c b/drivers/acpi/acpica/rsio.c
index 33bff17..0c7efef 100644
--- a/drivers/acpi/acpica/rsio.c
+++ b/drivers/acpi/acpica/rsio.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/rsirq.c b/drivers/acpi/acpica/rsirq.c
index 545da40..50b8ad2 100644
--- a/drivers/acpi/acpica/rsirq.c
+++ b/drivers/acpi/acpica/rsirq.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/rslist.c b/drivers/acpi/acpica/rslist.c
index 7335f22..1bfcef7 100644
--- a/drivers/acpi/acpica/rslist.c
+++ b/drivers/acpi/acpica/rslist.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/rsmemory.c b/drivers/acpi/acpica/rsmemory.c
index 887b8ba..7cc6d86 100644
--- a/drivers/acpi/acpica/rsmemory.c
+++ b/drivers/acpi/acpica/rsmemory.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/rsmisc.c b/drivers/acpi/acpica/rsmisc.c
index f8cd9e8..410264b 100644
--- a/drivers/acpi/acpica/rsmisc.c
+++ b/drivers/acpi/acpica/rsmisc.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/rsutils.c b/drivers/acpi/acpica/rsutils.c
index 491191e..231811e 100644
--- a/drivers/acpi/acpica/rsutils.c
+++ b/drivers/acpi/acpica/rsutils.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/rsxface.c b/drivers/acpi/acpica/rsxface.c
index 9f6a6e7..2ff657a 100644
--- a/drivers/acpi/acpica/rsxface.c
+++ b/drivers/acpi/acpica/rsxface.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/tbfadt.c b/drivers/acpi/acpica/tbfadt.c
index d2ff432..428d44e 100644
--- a/drivers/acpi/acpica/tbfadt.c
+++ b/drivers/acpi/acpica/tbfadt.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/tbfind.c b/drivers/acpi/acpica/tbfind.c
index 989d5c8..a55cb2b 100644
--- a/drivers/acpi/acpica/tbfind.c
+++ b/drivers/acpi/acpica/tbfind.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/tbinstal.c b/drivers/acpi/acpica/tbinstal.c
index 83d7af8..48db094 100644
--- a/drivers/acpi/acpica/tbinstal.c
+++ b/drivers/acpi/acpica/tbinstal.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/tbutils.c b/drivers/acpi/acpica/tbutils.c
index 34f9c2b..0f2d395 100644
--- a/drivers/acpi/acpica/tbutils.c
+++ b/drivers/acpi/acpica/tbutils.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/tbxface.c b/drivers/acpi/acpica/tbxface.c
index 4a8b9e6..4b7085d 100644
--- a/drivers/acpi/acpica/tbxface.c
+++ b/drivers/acpi/acpica/tbxface.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/tbxfroot.c b/drivers/acpi/acpica/tbxfroot.c
index fd2c07d..7eb6c6c 100644
--- a/drivers/acpi/acpica/tbxfroot.c
+++ b/drivers/acpi/acpica/tbxfroot.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utalloc.c b/drivers/acpi/acpica/utalloc.c
index 8f08962..0a69735 100644
--- a/drivers/acpi/acpica/utalloc.c
+++ b/drivers/acpi/acpica/utalloc.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utcopy.c b/drivers/acpi/acpica/utcopy.c
index 6fef83f..aded299 100644
--- a/drivers/acpi/acpica/utcopy.c
+++ b/drivers/acpi/acpica/utcopy.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utdebug.c b/drivers/acpi/acpica/utdebug.c
index f21c486..a9bcd81 100644
--- a/drivers/acpi/acpica/utdebug.c
+++ b/drivers/acpi/acpica/utdebug.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utdelete.c b/drivers/acpi/acpica/utdelete.c
index ed794cd..31f5a78 100644
--- a/drivers/acpi/acpica/utdelete.c
+++ b/drivers/acpi/acpica/utdelete.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/uteval.c b/drivers/acpi/acpica/uteval.c
index 22f59ef..18f73c9 100644
--- a/drivers/acpi/acpica/uteval.c
+++ b/drivers/acpi/acpica/uteval.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utglobal.c b/drivers/acpi/acpica/utglobal.c
index e87bc67..97dd9bb 100644
--- a/drivers/acpi/acpica/utglobal.c
+++ b/drivers/acpi/acpica/utglobal.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -768,7 +768,7 @@ acpi_status acpi_ut_init_globals(void)
acpi_gbl_gpe_fadt_blocks[0] = NULL;
acpi_gbl_gpe_fadt_blocks[1] = NULL;
acpi_current_gpe_count = 0;
- acpi_all_gpes_initialized = FALSE;
+ acpi_gbl_all_gpes_initialized = FALSE;
/* Global handlers */
@@ -778,6 +778,7 @@ acpi_status acpi_ut_init_globals(void)
acpi_gbl_init_handler = NULL;
acpi_gbl_table_handler = NULL;
acpi_gbl_interface_handler = NULL;
+ acpi_gbl_global_event_handler = NULL;
/* Global Lock support */
diff --git a/drivers/acpi/acpica/utids.c b/drivers/acpi/acpica/utids.c
index d290632..b679ea6 100644
--- a/drivers/acpi/acpica/utids.c
+++ b/drivers/acpi/acpica/utids.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utinit.c b/drivers/acpi/acpica/utinit.c
index c1b1c80..191b682 100644
--- a/drivers/acpi/acpica/utinit.c
+++ b/drivers/acpi/acpica/utinit.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utlock.c b/drivers/acpi/acpica/utlock.c
index b081cd4..f6bb75c6 100644
--- a/drivers/acpi/acpica/utlock.c
+++ b/drivers/acpi/acpica/utlock.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utmath.c b/drivers/acpi/acpica/utmath.c
index 49cf7b7..ce481da 100644
--- a/drivers/acpi/acpica/utmath.c
+++ b/drivers/acpi/acpica/utmath.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utmisc.c b/drivers/acpi/acpica/utmisc.c
index c7d0e05..c33a852 100644
--- a/drivers/acpi/acpica/utmisc.c
+++ b/drivers/acpi/acpica/utmisc.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utmutex.c b/drivers/acpi/acpica/utmutex.c
index d9efa49..a946c68 100644
--- a/drivers/acpi/acpica/utmutex.c
+++ b/drivers/acpi/acpica/utmutex.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -85,6 +85,7 @@ acpi_status acpi_ut_mutex_initialize(void)
spin_lock_init(acpi_gbl_gpe_lock);
spin_lock_init(acpi_gbl_hardware_lock);
+ spin_lock_init(acpi_ev_global_lock_pending_lock);
/* Mutex for _OSI support */
status = acpi_os_create_mutex(&acpi_gbl_osi_mutex);
diff --git a/drivers/acpi/acpica/utobject.c b/drivers/acpi/acpica/utobject.c
index fd1fa27..188340a 100644
--- a/drivers/acpi/acpica/utobject.c
+++ b/drivers/acpi/acpica/utobject.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utosi.c b/drivers/acpi/acpica/utosi.c
index 18c59a8..1fb10cb 100644
--- a/drivers/acpi/acpica/utosi.c
+++ b/drivers/acpi/acpica/utosi.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utresrc.c b/drivers/acpi/acpica/utresrc.c
index 7965919..84e0518 100644
--- a/drivers/acpi/acpica/utresrc.c
+++ b/drivers/acpi/acpica/utresrc.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utstate.c b/drivers/acpi/acpica/utstate.c
index d35d109..30c21e1 100644
--- a/drivers/acpi/acpica/utstate.c
+++ b/drivers/acpi/acpica/utstate.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utxface.c b/drivers/acpi/acpica/utxface.c
index 1f484c9..98ad125 100644
--- a/drivers/acpi/acpica/utxface.c
+++ b/drivers/acpi/acpica/utxface.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utxferror.c b/drivers/acpi/acpica/utxferror.c
index 6f12e31..916ae09 100644
--- a/drivers/acpi/acpica/utxferror.c
+++ b/drivers/acpi/acpica/utxferror.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/apei/apei-internal.h b/drivers/acpi/apei/apei-internal.h
index 18df1e9..ef0581f 100644
--- a/drivers/acpi/apei/apei-internal.h
+++ b/drivers/acpi/apei/apei-internal.h
@@ -109,6 +109,8 @@ static inline u32 apei_estatus_len(struct acpi_hest_generic_status *estatus)
return sizeof(*estatus) + estatus->data_length;
}
+void apei_estatus_print(const char *pfx,
+ const struct acpi_hest_generic_status *estatus);
int apei_estatus_check_header(const struct acpi_hest_generic_status *estatus);
int apei_estatus_check(const struct acpi_hest_generic_status *estatus);
#endif
diff --git a/drivers/acpi/apei/cper.c b/drivers/acpi/apei/cper.c
index f4cf2fc..31464a0 100644
--- a/drivers/acpi/apei/cper.c
+++ b/drivers/acpi/apei/cper.c
@@ -46,6 +46,317 @@ u64 cper_next_record_id(void)
}
EXPORT_SYMBOL_GPL(cper_next_record_id);
+static const char *cper_severity_strs[] = {
+ "recoverable",
+ "fatal",
+ "corrected",
+ "info",
+};
+
+static const char *cper_severity_str(unsigned int severity)
+{
+ return severity < ARRAY_SIZE(cper_severity_strs) ?
+ cper_severity_strs[severity] : "unknown";
+}
+
+/*
+ * cper_print_bits - print strings for set bits
+ * @pfx: prefix for each line, including log level and prefix string
+ * @bits: bit mask
+ * @strs: string array, indexed by bit position
+ * @strs_size: size of the string array: @strs
+ *
+ * For each set bit in @bits, print the corresponding string in @strs.
+ * If the output length is longer than 80, multiple line will be
+ * printed, with @pfx is printed at the beginning of each line.
+ */
+static void cper_print_bits(const char *pfx, unsigned int bits,
+ const char *strs[], unsigned int strs_size)
+{
+ int i, len = 0;
+ const char *str;
+ char buf[84];
+
+ for (i = 0; i < strs_size; i++) {
+ if (!(bits & (1U << i)))
+ continue;
+ str = strs[i];
+ if (len && len + strlen(str) + 2 > 80) {
+ printk("%s\n", buf);
+ len = 0;
+ }
+ if (!len)
+ len = snprintf(buf, sizeof(buf), "%s%s", pfx, str);
+ else
+ len += snprintf(buf+len, sizeof(buf)-len, ", %s", str);
+ }
+ if (len)
+ printk("%s\n", buf);
+}
+
+static const char *cper_proc_type_strs[] = {
+ "IA32/X64",
+ "IA64",
+};
+
+static const char *cper_proc_isa_strs[] = {
+ "IA32",
+ "IA64",
+ "X64",
+};
+
+static const char *cper_proc_error_type_strs[] = {
+ "cache error",
+ "TLB error",
+ "bus error",
+ "micro-architectural error",
+};
+
+static const char *cper_proc_op_strs[] = {
+ "unknown or generic",
+ "data read",
+ "data write",
+ "instruction execution",
+};
+
+static const char *cper_proc_flag_strs[] = {
+ "restartable",
+ "precise IP",
+ "overflow",
+ "corrected",
+};
+
+static void cper_print_proc_generic(const char *pfx,
+ const struct cper_sec_proc_generic *proc)
+{
+ if (proc->validation_bits & CPER_PROC_VALID_TYPE)
+ printk("%s""processor_type: %d, %s\n", pfx, proc->proc_type,
+ proc->proc_type < ARRAY_SIZE(cper_proc_type_strs) ?
+ cper_proc_type_strs[proc->proc_type] : "unknown");
+ if (proc->validation_bits & CPER_PROC_VALID_ISA)
+ printk("%s""processor_isa: %d, %s\n", pfx, proc->proc_isa,
+ proc->proc_isa < ARRAY_SIZE(cper_proc_isa_strs) ?
+ cper_proc_isa_strs[proc->proc_isa] : "unknown");
+ if (proc->validation_bits & CPER_PROC_VALID_ERROR_TYPE) {
+ printk("%s""error_type: 0x%02x\n", pfx, proc->proc_error_type);
+ cper_print_bits(pfx, proc->proc_error_type,
+ cper_proc_error_type_strs,
+ ARRAY_SIZE(cper_proc_error_type_strs));
+ }
+ if (proc->validation_bits & CPER_PROC_VALID_OPERATION)
+ printk("%s""operation: %d, %s\n", pfx, proc->operation,
+ proc->operation < ARRAY_SIZE(cper_proc_op_strs) ?
+ cper_proc_op_strs[proc->operation] : "unknown");
+ if (proc->validation_bits & CPER_PROC_VALID_FLAGS) {
+ printk("%s""flags: 0x%02x\n", pfx, proc->flags);
+ cper_print_bits(pfx, proc->flags, cper_proc_flag_strs,
+ ARRAY_SIZE(cper_proc_flag_strs));
+ }
+ if (proc->validation_bits & CPER_PROC_VALID_LEVEL)
+ printk("%s""level: %d\n", pfx, proc->level);
+ if (proc->validation_bits & CPER_PROC_VALID_VERSION)
+ printk("%s""version_info: 0x%016llx\n", pfx, proc->cpu_version);
+ if (proc->validation_bits & CPER_PROC_VALID_ID)
+ printk("%s""processor_id: 0x%016llx\n", pfx, proc->proc_id);
+ if (proc->validation_bits & CPER_PROC_VALID_TARGET_ADDRESS)
+ printk("%s""target_address: 0x%016llx\n",
+ pfx, proc->target_addr);
+ if (proc->validation_bits & CPER_PROC_VALID_REQUESTOR_ID)
+ printk("%s""requestor_id: 0x%016llx\n",
+ pfx, proc->requestor_id);
+ if (proc->validation_bits & CPER_PROC_VALID_RESPONDER_ID)
+ printk("%s""responder_id: 0x%016llx\n",
+ pfx, proc->responder_id);
+ if (proc->validation_bits & CPER_PROC_VALID_IP)
+ printk("%s""IP: 0x%016llx\n", pfx, proc->ip);
+}
+
+static const char *cper_mem_err_type_strs[] = {
+ "unknown",
+ "no error",
+ "single-bit ECC",
+ "multi-bit ECC",
+ "single-symbol chipkill ECC",
+ "multi-symbol chipkill ECC",
+ "master abort",
+ "target abort",
+ "parity error",
+ "watchdog timeout",
+ "invalid address",
+ "mirror Broken",
+ "memory sparing",
+ "scrub corrected error",
+ "scrub uncorrected error",
+};
+
+static void cper_print_mem(const char *pfx, const struct cper_sec_mem_err *mem)
+{
+ if (mem->validation_bits & CPER_MEM_VALID_ERROR_STATUS)
+ printk("%s""error_status: 0x%016llx\n", pfx, mem->error_status);
+ if (mem->validation_bits & CPER_MEM_VALID_PHYSICAL_ADDRESS)
+ printk("%s""physical_address: 0x%016llx\n",
+ pfx, mem->physical_addr);
+ if (mem->validation_bits & CPER_MEM_VALID_PHYSICAL_ADDRESS_MASK)
+ printk("%s""physical_address_mask: 0x%016llx\n",
+ pfx, mem->physical_addr_mask);
+ if (mem->validation_bits & CPER_MEM_VALID_NODE)
+ printk("%s""node: %d\n", pfx, mem->node);
+ if (mem->validation_bits & CPER_MEM_VALID_CARD)
+ printk("%s""card: %d\n", pfx, mem->card);
+ if (mem->validation_bits & CPER_MEM_VALID_MODULE)
+ printk("%s""module: %d\n", pfx, mem->module);
+ if (mem->validation_bits & CPER_MEM_VALID_BANK)
+ printk("%s""bank: %d\n", pfx, mem->bank);
+ if (mem->validation_bits & CPER_MEM_VALID_DEVICE)
+ printk("%s""device: %d\n", pfx, mem->device);
+ if (mem->validation_bits & CPER_MEM_VALID_ROW)
+ printk("%s""row: %d\n", pfx, mem->row);
+ if (mem->validation_bits & CPER_MEM_VALID_COLUMN)
+ printk("%s""column: %d\n", pfx, mem->column);
+ if (mem->validation_bits & CPER_MEM_VALID_BIT_POSITION)
+ printk("%s""bit_position: %d\n", pfx, mem->bit_pos);
+ if (mem->validation_bits & CPER_MEM_VALID_REQUESTOR_ID)
+ printk("%s""requestor_id: 0x%016llx\n", pfx, mem->requestor_id);
+ if (mem->validation_bits & CPER_MEM_VALID_RESPONDER_ID)
+ printk("%s""responder_id: 0x%016llx\n", pfx, mem->responder_id);
+ if (mem->validation_bits & CPER_MEM_VALID_TARGET_ID)
+ printk("%s""target_id: 0x%016llx\n", pfx, mem->target_id);
+ if (mem->validation_bits & CPER_MEM_VALID_ERROR_TYPE) {
+ u8 etype = mem->error_type;
+ printk("%s""error_type: %d, %s\n", pfx, etype,
+ etype < ARRAY_SIZE(cper_mem_err_type_strs) ?
+ cper_mem_err_type_strs[etype] : "unknown");
+ }
+}
+
+static const char *cper_pcie_port_type_strs[] = {
+ "PCIe end point",
+ "legacy PCI end point",
+ "unknown",
+ "unknown",
+ "root port",
+ "upstream switch port",
+ "downstream switch port",
+ "PCIe to PCI/PCI-X bridge",
+ "PCI/PCI-X to PCIe bridge",
+ "root complex integrated endpoint device",
+ "root complex event collector",
+};
+
+static void cper_print_pcie(const char *pfx, const struct cper_sec_pcie *pcie)
+{
+ if (pcie->validation_bits & CPER_PCIE_VALID_PORT_TYPE)
+ printk("%s""port_type: %d, %s\n", pfx, pcie->port_type,
+ pcie->port_type < ARRAY_SIZE(cper_pcie_port_type_strs) ?
+ cper_pcie_port_type_strs[pcie->port_type] : "unknown");
+ if (pcie->validation_bits & CPER_PCIE_VALID_VERSION)
+ printk("%s""version: %d.%d\n", pfx,
+ pcie->version.major, pcie->version.minor);
+ if (pcie->validation_bits & CPER_PCIE_VALID_COMMAND_STATUS)
+ printk("%s""command: 0x%04x, status: 0x%04x\n", pfx,
+ pcie->command, pcie->status);
+ if (pcie->validation_bits & CPER_PCIE_VALID_DEVICE_ID) {
+ const __u8 *p;
+ printk("%s""device_id: %04x:%02x:%02x.%x\n", pfx,
+ pcie->device_id.segment, pcie->device_id.bus,
+ pcie->device_id.device, pcie->device_id.function);
+ printk("%s""slot: %d\n", pfx,
+ pcie->device_id.slot >> CPER_PCIE_SLOT_SHIFT);
+ printk("%s""secondary_bus: 0x%02x\n", pfx,
+ pcie->device_id.secondary_bus);
+ printk("%s""vendor_id: 0x%04x, device_id: 0x%04x\n", pfx,
+ pcie->device_id.vendor_id, pcie->device_id.device_id);
+ p = pcie->device_id.class_code;
+ printk("%s""class_code: %02x%02x%02x\n", pfx, p[0], p[1], p[2]);
+ }
+ if (pcie->validation_bits & CPER_PCIE_VALID_SERIAL_NUMBER)
+ printk("%s""serial number: 0x%04x, 0x%04x\n", pfx,
+ pcie->serial_number.lower, pcie->serial_number.upper);
+ if (pcie->validation_bits & CPER_PCIE_VALID_BRIDGE_CONTROL_STATUS)
+ printk(
+ "%s""bridge: secondary_status: 0x%04x, control: 0x%04x\n",
+ pfx, pcie->bridge.secondary_status, pcie->bridge.control);
+}
+
+static const char *apei_estatus_section_flag_strs[] = {
+ "primary",
+ "containment warning",
+ "reset",
+ "threshold exceeded",
+ "resource not accessible",
+ "latent error",
+};
+
+static void apei_estatus_print_section(
+ const char *pfx, const struct acpi_hest_generic_data *gdata, int sec_no)
+{
+ uuid_le *sec_type = (uuid_le *)gdata->section_type;
+ __u16 severity;
+
+ severity = gdata->error_severity;
+ printk("%s""section: %d, severity: %d, %s\n", pfx, sec_no, severity,
+ cper_severity_str(severity));
+ printk("%s""flags: 0x%02x\n", pfx, gdata->flags);
+ cper_print_bits(pfx, gdata->flags, apei_estatus_section_flag_strs,
+ ARRAY_SIZE(apei_estatus_section_flag_strs));
+ if (gdata->validation_bits & CPER_SEC_VALID_FRU_ID)
+ printk("%s""fru_id: %pUl\n", pfx, (uuid_le *)gdata->fru_id);
+ if (gdata->validation_bits & CPER_SEC_VALID_FRU_TEXT)
+ printk("%s""fru_text: %.20s\n", pfx, gdata->fru_text);
+
+ if (!uuid_le_cmp(*sec_type, CPER_SEC_PROC_GENERIC)) {
+ struct cper_sec_proc_generic *proc_err = (void *)(gdata + 1);
+ printk("%s""section_type: general processor error\n", pfx);
+ if (gdata->error_data_length >= sizeof(*proc_err))
+ cper_print_proc_generic(pfx, proc_err);
+ else
+ goto err_section_too_small;
+ } else if (!uuid_le_cmp(*sec_type, CPER_SEC_PLATFORM_MEM)) {
+ struct cper_sec_mem_err *mem_err = (void *)(gdata + 1);
+ printk("%s""section_type: memory error\n", pfx);
+ if (gdata->error_data_length >= sizeof(*mem_err))
+ cper_print_mem(pfx, mem_err);
+ else
+ goto err_section_too_small;
+ } else if (!uuid_le_cmp(*sec_type, CPER_SEC_PCIE)) {
+ struct cper_sec_pcie *pcie = (void *)(gdata + 1);
+ printk("%s""section_type: PCIe error\n", pfx);
+ if (gdata->error_data_length >= sizeof(*pcie))
+ cper_print_pcie(pfx, pcie);
+ else
+ goto err_section_too_small;
+ } else
+ printk("%s""section type: unknown, %pUl\n", pfx, sec_type);
+
+ return;
+
+err_section_too_small:
+ pr_err(FW_WARN "error section length is too small\n");
+}
+
+void apei_estatus_print(const char *pfx,
+ const struct acpi_hest_generic_status *estatus)
+{
+ struct acpi_hest_generic_data *gdata;
+ unsigned int data_len, gedata_len;
+ int sec_no = 0;
+ __u16 severity;
+
+ printk("%s""APEI generic hardware error status\n", pfx);
+ severity = estatus->error_severity;
+ printk("%s""severity: %d, %s\n", pfx, severity,
+ cper_severity_str(severity));
+ data_len = estatus->data_length;
+ gdata = (struct acpi_hest_generic_data *)(estatus + 1);
+ while (data_len > sizeof(*gdata)) {
+ gedata_len = gdata->error_data_length;
+ apei_estatus_print_section(pfx, gdata, sec_no);
+ data_len -= gedata_len + sizeof(*gdata);
+ sec_no++;
+ }
+}
+EXPORT_SYMBOL_GPL(apei_estatus_print);
+
int apei_estatus_check_header(const struct acpi_hest_generic_status *estatus)
{
if (estatus->data_length &&
diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c
index 0d505e5..d1d484d 100644
--- a/drivers/acpi/apei/ghes.c
+++ b/drivers/acpi/apei/ghes.c
@@ -12,10 +12,6 @@
* For more information about Generic Hardware Error Source, please
* refer to ACPI Specification version 4.0, section 17.3.2.6
*
- * Now, only SCI notification type and memory errors are
- * supported. More notification type and hardware error type will be
- * added later.
- *
* Copyright 2010 Intel Corp.
* Author: Huang Ying <ying.huang@intel.com>
*
@@ -39,14 +35,18 @@
#include <linux/acpi.h>
#include <linux/io.h>
#include <linux/interrupt.h>
+#include <linux/timer.h>
#include <linux/cper.h>
#include <linux/kdebug.h>
#include <linux/platform_device.h>
#include <linux/mutex.h>
+#include <linux/ratelimit.h>
+#include <linux/vmalloc.h>
#include <acpi/apei.h>
#include <acpi/atomicio.h>
#include <acpi/hed.h>
#include <asm/mce.h>
+#include <asm/tlbflush.h>
#include "apei-internal.h"
@@ -55,42 +55,131 @@
#define GHES_ESTATUS_MAX_SIZE 65536
/*
- * One struct ghes is created for each generic hardware error
- * source.
- *
+ * One struct ghes is created for each generic hardware error source.
* It provides the context for APEI hardware error timer/IRQ/SCI/NMI
- * handler. Handler for one generic hardware error source is only
- * triggered after the previous one is done. So handler can uses
- * struct ghes without locking.
+ * handler.
*
* estatus: memory buffer for error status block, allocated during
* HEST parsing.
*/
#define GHES_TO_CLEAR 0x0001
+#define GHES_EXITING 0x0002
struct ghes {
struct acpi_hest_generic *generic;
struct acpi_hest_generic_status *estatus;
- struct list_head list;
u64 buffer_paddr;
unsigned long flags;
+ union {
+ struct list_head list;
+ struct timer_list timer;
+ unsigned int irq;
+ };
};
+static int ghes_panic_timeout __read_mostly = 30;
+
/*
- * Error source lists, one list for each notification method. The
- * members in lists are struct ghes.
+ * All error sources notified with SCI shares one notifier function,
+ * so they need to be linked and checked one by one. This is applied
+ * to NMI too.
*
- * The list members are only added in HEST parsing and deleted during
- * module_exit, that is, single-threaded. So no lock is needed for
- * that.
- *
- * But the mutual exclusion is needed between members adding/deleting
- * and timer/IRQ/SCI/NMI handler, which may traverse the list. RCU is
- * used for that.
+ * RCU is used for these lists, so ghes_list_mutex is only used for
+ * list changing, not for traversing.
*/
static LIST_HEAD(ghes_sci);
+static LIST_HEAD(ghes_nmi);
static DEFINE_MUTEX(ghes_list_mutex);
+/*
+ * NMI may be triggered on any CPU, so ghes_nmi_lock is used for
+ * mutual exclusion.
+ */
+static DEFINE_RAW_SPINLOCK(ghes_nmi_lock);
+
+/*
+ * Because the memory area used to transfer hardware error information
+ * from BIOS to Linux can be determined only in NMI, IRQ or timer
+ * handler, but general ioremap can not be used in atomic context, so
+ * a special version of atomic ioremap is implemented for that.
+ */
+
+/*
+ * Two virtual pages are used, one for NMI context, the other for
+ * IRQ/PROCESS context
+ */
+#define GHES_IOREMAP_PAGES 2
+#define GHES_IOREMAP_NMI_PAGE(base) (base)
+#define GHES_IOREMAP_IRQ_PAGE(base) ((base) + PAGE_SIZE)
+
+/* virtual memory area for atomic ioremap */
+static struct vm_struct *ghes_ioremap_area;
+/*
+ * These 2 spinlock is used to prevent atomic ioremap virtual memory
+ * area from being mapped simultaneously.
+ */
+static DEFINE_RAW_SPINLOCK(ghes_ioremap_lock_nmi);
+static DEFINE_SPINLOCK(ghes_ioremap_lock_irq);
+
+static int ghes_ioremap_init(void)
+{
+ ghes_ioremap_area = __get_vm_area(PAGE_SIZE * GHES_IOREMAP_PAGES,
+ VM_IOREMAP, VMALLOC_START, VMALLOC_END);
+ if (!ghes_ioremap_area) {
+ pr_err(GHES_PFX "Failed to allocate virtual memory area for atomic ioremap.\n");
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+static void ghes_ioremap_exit(void)
+{
+ free_vm_area(ghes_ioremap_area);
+}
+
+static void __iomem *ghes_ioremap_pfn_nmi(u64 pfn)
+{
+ unsigned long vaddr;
+
+ vaddr = (unsigned long)GHES_IOREMAP_NMI_PAGE(ghes_ioremap_area->addr);
+ ioremap_page_range(vaddr, vaddr + PAGE_SIZE,
+ pfn << PAGE_SHIFT, PAGE_KERNEL);
+
+ return (void __iomem *)vaddr;
+}
+
+static void __iomem *ghes_ioremap_pfn_irq(u64 pfn)
+{
+ unsigned long vaddr;
+
+ vaddr = (unsigned long)GHES_IOREMAP_IRQ_PAGE(ghes_ioremap_area->addr);
+ ioremap_page_range(vaddr, vaddr + PAGE_SIZE,
+ pfn << PAGE_SHIFT, PAGE_KERNEL);
+
+ return (void __iomem *)vaddr;
+}
+
+static void ghes_iounmap_nmi(void __iomem *vaddr_ptr)
+{
+ unsigned long vaddr = (unsigned long __force)vaddr_ptr;
+ void *base = ghes_ioremap_area->addr;
+
+ BUG_ON(vaddr != (unsigned long)GHES_IOREMAP_NMI_PAGE(base));
+ unmap_kernel_range_noflush(vaddr, PAGE_SIZE);
+ __flush_tlb_one(vaddr);
+}
+
+static void ghes_iounmap_irq(void __iomem *vaddr_ptr)
+{
+ unsigned long vaddr = (unsigned long __force)vaddr_ptr;
+ void *base = ghes_ioremap_area->addr;
+
+ BUG_ON(vaddr != (unsigned long)GHES_IOREMAP_IRQ_PAGE(base));
+ unmap_kernel_range_noflush(vaddr, PAGE_SIZE);
+ __flush_tlb_one(vaddr);
+}
+
static struct ghes *ghes_new(struct acpi_hest_generic *generic)
{
struct ghes *ghes;
@@ -101,7 +190,6 @@ static struct ghes *ghes_new(struct acpi_hest_generic *generic)
if (!ghes)
return ERR_PTR(-ENOMEM);
ghes->generic = generic;
- INIT_LIST_HEAD(&ghes->list);
rc = acpi_pre_map_gar(&generic->error_status_address);
if (rc)
goto err_free;
@@ -158,22 +246,41 @@ static inline int ghes_severity(int severity)
}
}
-/* SCI handler run in work queue, so ioremap can be used here */
-static int ghes_copy_tofrom_phys(void *buffer, u64 paddr, u32 len,
- int from_phys)
+static void ghes_copy_tofrom_phys(void *buffer, u64 paddr, u32 len,
+ int from_phys)
{
- void *vaddr;
-
- vaddr = ioremap_cache(paddr, len);
- if (!vaddr)
- return -ENOMEM;
- if (from_phys)
- memcpy(buffer, vaddr, len);
- else
- memcpy(vaddr, buffer, len);
- iounmap(vaddr);
-
- return 0;
+ void __iomem *vaddr;
+ unsigned long flags = 0;
+ int in_nmi = in_nmi();
+ u64 offset;
+ u32 trunk;
+
+ while (len > 0) {
+ offset = paddr - (paddr & PAGE_MASK);
+ if (in_nmi) {
+ raw_spin_lock(&ghes_ioremap_lock_nmi);
+ vaddr = ghes_ioremap_pfn_nmi(paddr >> PAGE_SHIFT);
+ } else {
+ spin_lock_irqsave(&ghes_ioremap_lock_irq, flags);
+ vaddr = ghes_ioremap_pfn_irq(paddr >> PAGE_SHIFT);
+ }
+ trunk = PAGE_SIZE - offset;
+ trunk = min(trunk, len);
+ if (from_phys)
+ memcpy_fromio(buffer, vaddr + offset, trunk);
+ else
+ memcpy_toio(vaddr + offset, buffer, trunk);
+ len -= trunk;
+ paddr += trunk;
+ buffer += trunk;
+ if (in_nmi) {
+ ghes_iounmap_nmi(vaddr);
+ raw_spin_unlock(&ghes_ioremap_lock_nmi);
+ } else {
+ ghes_iounmap_irq(vaddr);
+ spin_unlock_irqrestore(&ghes_ioremap_lock_irq, flags);
+ }
+ }
}
static int ghes_read_estatus(struct ghes *ghes, int silent)
@@ -194,10 +301,8 @@ static int ghes_read_estatus(struct ghes *ghes, int silent)
if (!buf_paddr)
return -ENOENT;
- rc = ghes_copy_tofrom_phys(ghes->estatus, buf_paddr,
- sizeof(*ghes->estatus), 1);
- if (rc)
- return rc;
+ ghes_copy_tofrom_phys(ghes->estatus, buf_paddr,
+ sizeof(*ghes->estatus), 1);
if (!ghes->estatus->block_status)
return -ENOENT;
@@ -212,17 +317,15 @@ static int ghes_read_estatus(struct ghes *ghes, int silent)
goto err_read_block;
if (apei_estatus_check_header(ghes->estatus))
goto err_read_block;
- rc = ghes_copy_tofrom_phys(ghes->estatus + 1,
- buf_paddr + sizeof(*ghes->estatus),
- len - sizeof(*ghes->estatus), 1);
- if (rc)
- return rc;
+ ghes_copy_tofrom_phys(ghes->estatus + 1,
+ buf_paddr + sizeof(*ghes->estatus),
+ len - sizeof(*ghes->estatus), 1);
if (apei_estatus_check(ghes->estatus))
goto err_read_block;
rc = 0;
err_read_block:
- if (rc && !silent)
+ if (rc && !silent && printk_ratelimit())
pr_warning(FW_WARN GHES_PFX
"Failed to read error status block!\n");
return rc;
@@ -255,11 +358,26 @@ static void ghes_do_proc(struct ghes *ghes)
}
#endif
}
+}
- if (!processed && printk_ratelimit())
- pr_warning(GHES_PFX
- "Unknown error record from generic hardware error source: %d\n",
- ghes->generic->header.source_id);
+static void ghes_print_estatus(const char *pfx, struct ghes *ghes)
+{
+ /* Not more than 2 messages every 5 seconds */
+ static DEFINE_RATELIMIT_STATE(ratelimit, 5*HZ, 2);
+
+ if (pfx == NULL) {
+ if (ghes_severity(ghes->estatus->error_severity) <=
+ GHES_SEV_CORRECTED)
+ pfx = KERN_WARNING HW_ERR;
+ else
+ pfx = KERN_ERR HW_ERR;
+ }
+ if (__ratelimit(&ratelimit)) {
+ printk(
+ "%s""Hardware error from APEI Generic Hardware Error Source: %d\n",
+ pfx, ghes->generic->header.source_id);
+ apei_estatus_print(pfx, ghes->estatus);
+ }
}
static int ghes_proc(struct ghes *ghes)
@@ -269,6 +387,7 @@ static int ghes_proc(struct ghes *ghes)
rc = ghes_read_estatus(ghes, 0);
if (rc)
goto out;
+ ghes_print_estatus(NULL, ghes);
ghes_do_proc(ghes);
out:
@@ -276,6 +395,42 @@ out:
return 0;
}
+static void ghes_add_timer(struct ghes *ghes)
+{
+ struct acpi_hest_generic *g = ghes->generic;
+ unsigned long expire;
+
+ if (!g->notify.poll_interval) {
+ pr_warning(FW_WARN GHES_PFX "Poll interval is 0 for generic hardware error source: %d, disabled.\n",
+ g->header.source_id);
+ return;
+ }
+ expire = jiffies + msecs_to_jiffies(g->notify.poll_interval);
+ ghes->timer.expires = round_jiffies_relative(expire);
+ add_timer(&ghes->timer);
+}
+
+static void ghes_poll_func(unsigned long data)
+{
+ struct ghes *ghes = (void *)data;
+
+ ghes_proc(ghes);
+ if (!(ghes->flags & GHES_EXITING))
+ ghes_add_timer(ghes);
+}
+
+static irqreturn_t ghes_irq_func(int irq, void *data)
+{
+ struct ghes *ghes = data;
+ int rc;
+
+ rc = ghes_proc(ghes);
+ if (rc)
+ return IRQ_NONE;
+
+ return IRQ_HANDLED;
+}
+
static int ghes_notify_sci(struct notifier_block *this,
unsigned long event, void *data)
{
@@ -292,10 +447,63 @@ static int ghes_notify_sci(struct notifier_block *this,
return ret;
}
+static int ghes_notify_nmi(struct notifier_block *this,
+ unsigned long cmd, void *data)
+{
+ struct ghes *ghes, *ghes_global = NULL;
+ int sev, sev_global = -1;
+ int ret = NOTIFY_DONE;
+
+ if (cmd != DIE_NMI)
+ return ret;
+
+ raw_spin_lock(&ghes_nmi_lock);
+ list_for_each_entry_rcu(ghes, &ghes_nmi, list) {
+ if (ghes_read_estatus(ghes, 1)) {
+ ghes_clear_estatus(ghes);
+ continue;
+ }
+ sev = ghes_severity(ghes->estatus->error_severity);
+ if (sev > sev_global) {
+ sev_global = sev;
+ ghes_global = ghes;
+ }
+ ret = NOTIFY_STOP;
+ }
+
+ if (ret == NOTIFY_DONE)
+ goto out;
+
+ if (sev_global >= GHES_SEV_PANIC) {
+ oops_begin();
+ ghes_print_estatus(KERN_EMERG HW_ERR, ghes_global);
+ /* reboot to log the error! */
+ if (panic_timeout == 0)
+ panic_timeout = ghes_panic_timeout;
+ panic("Fatal hardware error!");
+ }
+
+ list_for_each_entry_rcu(ghes, &ghes_nmi, list) {
+ if (!(ghes->flags & GHES_TO_CLEAR))
+ continue;
+ /* Do not print estatus because printk is not NMI safe */
+ ghes_do_proc(ghes);
+ ghes_clear_estatus(ghes);
+ }
+
+out:
+ raw_spin_unlock(&ghes_nmi_lock);
+ return ret;
+}
+
static struct notifier_block ghes_notifier_sci = {
.notifier_call = ghes_notify_sci,
};
+static struct notifier_block ghes_notifier_nmi = {
+ .notifier_call = ghes_notify_nmi,
+};
+
static int __devinit ghes_probe(struct platform_device *ghes_dev)
{
struct acpi_hest_generic *generic;
@@ -306,18 +514,27 @@ static int __devinit ghes_probe(struct platform_device *ghes_dev)
if (!generic->enabled)
return -ENODEV;
- if (generic->error_block_length <
- sizeof(struct acpi_hest_generic_status)) {
- pr_warning(FW_BUG GHES_PFX
-"Invalid error block length: %u for generic hardware error source: %d\n",
- generic->error_block_length,
+ switch (generic->notify.type) {
+ case ACPI_HEST_NOTIFY_POLLED:
+ case ACPI_HEST_NOTIFY_EXTERNAL:
+ case ACPI_HEST_NOTIFY_SCI:
+ case ACPI_HEST_NOTIFY_NMI:
+ break;
+ case ACPI_HEST_NOTIFY_LOCAL:
+ pr_warning(GHES_PFX "Generic hardware error source: %d notified via local interrupt is not supported!\n",
generic->header.source_id);
goto err;
+ default:
+ pr_warning(FW_WARN GHES_PFX "Unknown notification type: %u for generic hardware error source: %d\n",
+ generic->notify.type, generic->header.source_id);
+ goto err;
}
- if (generic->records_to_preallocate == 0) {
- pr_warning(FW_BUG GHES_PFX
-"Invalid records to preallocate: %u for generic hardware error source: %d\n",
- generic->records_to_preallocate,
+
+ rc = -EIO;
+ if (generic->error_block_length <
+ sizeof(struct acpi_hest_generic_status)) {
+ pr_warning(FW_BUG GHES_PFX "Invalid error block length: %u for generic hardware error source: %d\n",
+ generic->error_block_length,
generic->header.source_id);
goto err;
}
@@ -327,38 +544,43 @@ static int __devinit ghes_probe(struct platform_device *ghes_dev)
ghes = NULL;
goto err;
}
- if (generic->notify.type == ACPI_HEST_NOTIFY_SCI) {
+ switch (generic->notify.type) {
+ case ACPI_HEST_NOTIFY_POLLED:
+ ghes->timer.function = ghes_poll_func;
+ ghes->timer.data = (unsigned long)ghes;
+ init_timer_deferrable(&ghes->timer);
+ ghes_add_timer(ghes);
+ break;
+ case ACPI_HEST_NOTIFY_EXTERNAL:
+ /* External interrupt vector is GSI */
+ if (acpi_gsi_to_irq(generic->notify.vector, &ghes->irq)) {
+ pr_err(GHES_PFX "Failed to map GSI to IRQ for generic hardware error source: %d\n",
+ generic->header.source_id);
+ goto err;
+ }
+ if (request_irq(ghes->irq, ghes_irq_func,
+ 0, "GHES IRQ", ghes)) {
+ pr_err(GHES_PFX "Failed to register IRQ for generic hardware error source: %d\n",
+ generic->header.source_id);
+ goto err;
+ }
+ break;
+ case ACPI_HEST_NOTIFY_SCI:
mutex_lock(&ghes_list_mutex);
if (list_empty(&ghes_sci))
register_acpi_hed_notifier(&ghes_notifier_sci);
list_add_rcu(&ghes->list, &ghes_sci);
mutex_unlock(&ghes_list_mutex);
- } else {
- unsigned char *notify = NULL;
-
- switch (generic->notify.type) {
- case ACPI_HEST_NOTIFY_POLLED:
- notify = "POLL";
- break;
- case ACPI_HEST_NOTIFY_EXTERNAL:
- case ACPI_HEST_NOTIFY_LOCAL:
- notify = "IRQ";
- break;
- case ACPI_HEST_NOTIFY_NMI:
- notify = "NMI";
- break;
- }
- if (notify) {
- pr_warning(GHES_PFX
-"Generic hardware error source: %d notified via %s is not supported!\n",
- generic->header.source_id, notify);
- } else {
- pr_warning(FW_WARN GHES_PFX
-"Unknown notification type: %u for generic hardware error source: %d\n",
- generic->notify.type, generic->header.source_id);
- }
- rc = -ENODEV;
- goto err;
+ break;
+ case ACPI_HEST_NOTIFY_NMI:
+ mutex_lock(&ghes_list_mutex);
+ if (list_empty(&ghes_nmi))
+ register_die_notifier(&ghes_notifier_nmi);
+ list_add_rcu(&ghes->list, &ghes_nmi);
+ mutex_unlock(&ghes_list_mutex);
+ break;
+ default:
+ BUG();
}
platform_set_drvdata(ghes_dev, ghes);
@@ -379,7 +601,14 @@ static int __devexit ghes_remove(struct platform_device *ghes_dev)
ghes = platform_get_drvdata(ghes_dev);
generic = ghes->generic;
+ ghes->flags |= GHES_EXITING;
switch (generic->notify.type) {
+ case ACPI_HEST_NOTIFY_POLLED:
+ del_timer_sync(&ghes->timer);
+ break;
+ case ACPI_HEST_NOTIFY_EXTERNAL:
+ free_irq(ghes->irq, ghes);
+ break;
case ACPI_HEST_NOTIFY_SCI:
mutex_lock(&ghes_list_mutex);
list_del_rcu(&ghes->list);
@@ -387,12 +616,23 @@ static int __devexit ghes_remove(struct platform_device *ghes_dev)
unregister_acpi_hed_notifier(&ghes_notifier_sci);
mutex_unlock(&ghes_list_mutex);
break;
+ case ACPI_HEST_NOTIFY_NMI:
+ mutex_lock(&ghes_list_mutex);
+ list_del_rcu(&ghes->list);
+ if (list_empty(&ghes_nmi))
+ unregister_die_notifier(&ghes_notifier_nmi);
+ mutex_unlock(&ghes_list_mutex);
+ /*
+ * To synchronize with NMI handler, ghes can only be
+ * freed after NMI handler finishes.
+ */
+ synchronize_rcu();
+ break;
default:
BUG();
break;
}
- synchronize_rcu();
ghes_fini(ghes);
kfree(ghes);
@@ -412,6 +652,8 @@ static struct platform_driver ghes_platform_driver = {
static int __init ghes_init(void)
{
+ int rc;
+
if (acpi_disabled)
return -ENODEV;
@@ -420,12 +662,25 @@ static int __init ghes_init(void)
return -EINVAL;
}
- return platform_driver_register(&ghes_platform_driver);
+ rc = ghes_ioremap_init();
+ if (rc)
+ goto err;
+
+ rc = platform_driver_register(&ghes_platform_driver);
+ if (rc)
+ goto err_ioremap_exit;
+
+ return 0;
+err_ioremap_exit:
+ ghes_ioremap_exit();
+err:
+ return rc;
}
static void __exit ghes_exit(void)
{
platform_driver_unregister(&ghes_platform_driver);
+ ghes_ioremap_exit();
}
module_init(ghes_init);
diff --git a/drivers/acpi/apei/hest.c b/drivers/acpi/apei/hest.c
index daa7bc6..abda378 100644
--- a/drivers/acpi/apei/hest.c
+++ b/drivers/acpi/apei/hest.c
@@ -195,24 +195,24 @@ static int __init setup_hest_disable(char *str)
__setup("hest_disable", setup_hest_disable);
-static int __init hest_init(void)
+void __init acpi_hest_init(void)
{
acpi_status status;
int rc = -ENODEV;
unsigned int ghes_count = 0;
- if (acpi_disabled)
- goto err;
-
if (hest_disable) {
- pr_info(HEST_PFX "HEST tabling parsing is disabled.\n");
- goto err;
+ pr_info(HEST_PFX "Table parsing disabled.\n");
+ return;
}
+ if (acpi_disabled)
+ goto err;
+
status = acpi_get_table(ACPI_SIG_HEST, 0,
(struct acpi_table_header **)&hest_tab);
if (status == AE_NOT_FOUND) {
- pr_info(HEST_PFX "Table is not found!\n");
+ pr_info(HEST_PFX "Table not found.\n");
goto err;
} else if (ACPI_FAILURE(status)) {
const char *msg = acpi_format_exception(status);
@@ -226,15 +226,11 @@ static int __init hest_init(void)
goto err;
rc = hest_ghes_dev_register(ghes_count);
- if (rc)
- goto err;
-
- pr_info(HEST_PFX "HEST table parsing is initialized.\n");
+ if (!rc) {
+ pr_info(HEST_PFX "Table parsing has been initialized.\n");
+ return;
+ }
- return 0;
err:
hest_disable = 1;
- return rc;
}
-
-subsys_initcall(hest_init);
diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c
index 95649d3..ac1a599 100644
--- a/drivers/acpi/battery.c
+++ b/drivers/acpi/battery.c
@@ -631,6 +631,17 @@ static int acpi_battery_update(struct acpi_battery *battery)
return result;
}
+static void acpi_battery_refresh(struct acpi_battery *battery)
+{
+ if (!battery->bat.dev)
+ return;
+
+ acpi_battery_get_info(battery);
+ /* The battery may have changed its reporting units. */
+ sysfs_remove_battery(battery);
+ sysfs_add_battery(battery);
+}
+
/* --------------------------------------------------------------------------
FS Interface (/proc)
-------------------------------------------------------------------------- */
@@ -868,6 +879,8 @@ static int acpi_battery_add_fs(struct acpi_device *device)
struct proc_dir_entry *entry = NULL;
int i;
+ printk(KERN_WARNING PREFIX "Deprecated procfs I/F for battery is loaded,"
+ " please retry with CONFIG_ACPI_PROCFS_POWER cleared\n");
if (!acpi_device_dir(device)) {
acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device),
acpi_battery_dir);
@@ -914,6 +927,8 @@ static void acpi_battery_notify(struct acpi_device *device, u32 event)
if (!battery)
return;
old = battery->bat.dev;
+ if (event == ACPI_BATTERY_NOTIFY_INFO)
+ acpi_battery_refresh(battery);
acpi_battery_update(battery);
acpi_bus_generate_proc_event(device, event,
acpi_battery_present(battery));
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
index d68bd61..7ced61f 100644
--- a/drivers/acpi/bus.c
+++ b/drivers/acpi/bus.c
@@ -52,22 +52,6 @@ EXPORT_SYMBOL(acpi_root_dir);
#define STRUCT_TO_INT(s) (*((int*)&s))
-static int set_power_nocheck(const struct dmi_system_id *id)
-{
- printk(KERN_NOTICE PREFIX "%s detected - "
- "disable power check in power transition\n", id->ident);
- acpi_power_nocheck = 1;
- return 0;
-}
-static struct dmi_system_id __cpuinitdata power_nocheck_dmi_table[] = {
- {
- set_power_nocheck, "HP Pavilion 05", {
- DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
- DMI_MATCH(DMI_SYS_VENDOR, "HP Pavilion 05"),
- DMI_MATCH(DMI_PRODUCT_VERSION, "2001211RE101GLEND") }, NULL},
- {},
-};
-
#ifdef CONFIG_X86
static int set_copy_dsdt(const struct dmi_system_id *id)
@@ -196,33 +180,24 @@ EXPORT_SYMBOL(acpi_bus_get_private_data);
Power Management
-------------------------------------------------------------------------- */
-int acpi_bus_get_power(acpi_handle handle, int *state)
+static int __acpi_bus_get_power(struct acpi_device *device, int *state)
{
int result = 0;
acpi_status status = 0;
- struct acpi_device *device = NULL;
unsigned long long psc = 0;
-
- result = acpi_bus_get_device(handle, &device);
- if (result)
- return result;
+ if (!device || !state)
+ return -EINVAL;
*state = ACPI_STATE_UNKNOWN;
- if (!device->flags.power_manageable) {
- /* TBD: Non-recursive algorithm for walking up hierarchy */
- if (device->parent)
- *state = device->parent->power.state;
- else
- *state = ACPI_STATE_D0;
- } else {
+ if (device->flags.power_manageable) {
/*
* Get the device's power state either directly (via _PSC) or
* indirectly (via power resources).
*/
if (device->power.flags.power_resources) {
- result = acpi_power_get_inferred_state(device);
+ result = acpi_power_get_inferred_state(device, state);
if (result)
return result;
} else if (device->power.flags.explicit_get) {
@@ -230,59 +205,33 @@ int acpi_bus_get_power(acpi_handle handle, int *state)
NULL, &psc);
if (ACPI_FAILURE(status))
return -ENODEV;
- device->power.state = (int)psc;
+ *state = (int)psc;
}
-
- *state = device->power.state;
+ } else {
+ /* TBD: Non-recursive algorithm for walking up hierarchy. */
+ *state = device->parent ?
+ device->parent->power.state : ACPI_STATE_D0;
}
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] power state is D%d\n",
- device->pnp.bus_id, device->power.state));
+ device->pnp.bus_id, *state));
return 0;
}
-EXPORT_SYMBOL(acpi_bus_get_power);
-int acpi_bus_set_power(acpi_handle handle, int state)
+static int __acpi_bus_set_power(struct acpi_device *device, int state)
{
int result = 0;
acpi_status status = AE_OK;
- struct acpi_device *device = NULL;
char object_name[5] = { '_', 'P', 'S', '0' + state, '\0' };
-
- result = acpi_bus_get_device(handle, &device);
- if (result)
- return result;
-
- if ((state < ACPI_STATE_D0) || (state > ACPI_STATE_D3))
+ if (!device || (state < ACPI_STATE_D0) || (state > ACPI_STATE_D3))
return -EINVAL;
/* Make sure this is a valid target state */
- if (!device->flags.power_manageable) {
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device `[%s]' is not power manageable\n",
- kobject_name(&device->dev.kobj)));
- return -ENODEV;
- }
- /*
- * Get device's current power state
- */
- if (!acpi_power_nocheck) {
- /*
- * Maybe the incorrect power state is returned on the bogus
- * bios, which is different with the real power state.
- * For example: the bios returns D0 state and the real power
- * state is D3. OS expects to set the device to D0 state. In
- * such case if OS uses the power state returned by the BIOS,
- * the device can't be transisted to the correct power state.
- * So if the acpi_power_nocheck is set, it is unnecessary to
- * get the power state by calling acpi_bus_get_power.
- */
- acpi_bus_get_power(device->handle, &device->power.state);
- }
- if ((state == device->power.state) && !device->flags.force_power_state) {
+ if (state == device->power.state) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device is already at D%d\n",
state));
return 0;
@@ -351,8 +300,75 @@ int acpi_bus_set_power(acpi_handle handle, int state)
return result;
}
+
+int acpi_bus_set_power(acpi_handle handle, int state)
+{
+ struct acpi_device *device;
+ int result;
+
+ result = acpi_bus_get_device(handle, &device);
+ if (result)
+ return result;
+
+ if (!device->flags.power_manageable) {
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "Device [%s] is not power manageable\n",
+ dev_name(&device->dev)));
+ return -ENODEV;
+ }
+
+ return __acpi_bus_set_power(device, state);
+}
EXPORT_SYMBOL(acpi_bus_set_power);
+
+int acpi_bus_init_power(struct acpi_device *device)
+{
+ int state;
+ int result;
+
+ if (!device)
+ return -EINVAL;
+
+ device->power.state = ACPI_STATE_UNKNOWN;
+
+ result = __acpi_bus_get_power(device, &state);
+ if (result)
+ return result;
+
+ if (device->power.flags.power_resources)
+ result = acpi_power_on_resources(device, state);
+
+ if (!result)
+ device->power.state = state;
+
+ return result;
+}
+
+
+int acpi_bus_update_power(acpi_handle handle, int *state_p)
+{
+ struct acpi_device *device;
+ int state;
+ int result;
+
+ result = acpi_bus_get_device(handle, &device);
+ if (result)
+ return result;
+
+ result = __acpi_bus_get_power(device, &state);
+ if (result)
+ return result;
+
+ result = __acpi_bus_set_power(device, state);
+ if (!result && state_p)
+ *state_p = state;
+
+ return result;
+}
+EXPORT_SYMBOL_GPL(acpi_bus_update_power);
+
+
bool acpi_bus_power_manageable(acpi_handle handle)
{
struct acpi_device *device;
@@ -1023,15 +1039,8 @@ static int __init acpi_init(void)
if (acpi_disabled)
return result;
- /*
- * If the laptop falls into the DMI check table, the power state check
- * will be disabled in the course of device power transition.
- */
- dmi_check_system(power_nocheck_dmi_table);
-
acpi_scan_init();
acpi_ec_init();
- acpi_power_init();
acpi_debugfs_init();
acpi_sleep_proc_init();
acpi_wakeup_device_init();
diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c
index 71ef9cd..76bbb78 100644
--- a/drivers/acpi/button.c
+++ b/drivers/acpi/button.c
@@ -279,6 +279,9 @@ static int acpi_lid_send_state(struct acpi_device *device)
input_report_switch(button->input, SW_LID, !state);
input_sync(button->input);
+ if (state)
+ pm_wakeup_event(&device->dev, 0);
+
ret = blocking_notifier_call_chain(&acpi_lid_notifier, state, device);
if (ret == NOTIFY_DONE)
ret = blocking_notifier_call_chain(&acpi_lid_notifier, state,
@@ -314,6 +317,8 @@ static void acpi_button_notify(struct acpi_device *device, u32 event)
input_sync(input);
input_report_key(input, keycode, 0);
input_sync(input);
+
+ pm_wakeup_event(&device->dev, 0);
}
acpi_bus_generate_proc_event(device, event, ++button->pushed);
@@ -426,7 +431,7 @@ static int acpi_button_add(struct acpi_device *device)
acpi_enable_gpe(device->wakeup.gpe_device,
device->wakeup.gpe_number);
device->wakeup.run_wake_count++;
- device->wakeup.state.enabled = 1;
+ device_set_wakeup_enable(&device->dev, true);
}
printk(KERN_INFO PREFIX "%s [%s]\n", name, acpi_device_bid(device));
@@ -449,7 +454,7 @@ static int acpi_button_remove(struct acpi_device *device, int type)
acpi_disable_gpe(device->wakeup.gpe_device,
device->wakeup.gpe_number);
device->wakeup.run_wake_count--;
- device->wakeup.state.enabled = 0;
+ device_set_wakeup_enable(&device->dev, false);
}
acpi_button_remove_fs(device);
diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c
index 81514a4..1864ad3 100644
--- a/drivers/acpi/dock.c
+++ b/drivers/acpi/dock.c
@@ -725,7 +725,7 @@ static void dock_notify(acpi_handle handle, u32 event, void *data)
complete_dock(ds);
dock_event(ds, event, DOCK_EVENT);
dock_lock(ds, 1);
- acpi_update_gpes();
+ acpi_update_all_gpes();
break;
}
if (dock_present(ds) || dock_in_progress(ds))
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index 302b31e..fa848c4 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -606,7 +606,8 @@ static int ec_check_sci(struct acpi_ec *ec, u8 state)
return 0;
}
-static u32 acpi_ec_gpe_handler(void *data)
+static u32 acpi_ec_gpe_handler(acpi_handle gpe_device,
+ u32 gpe_number, void *data)
{
struct acpi_ec *ec = data;
@@ -618,7 +619,7 @@ static u32 acpi_ec_gpe_handler(void *data)
wake_up(&ec->wait);
ec_check_sci(ec, acpi_ec_read_status(ec));
}
- return ACPI_INTERRUPT_HANDLED;
+ return ACPI_INTERRUPT_HANDLED | ACPI_REENABLE_GPE;
}
/* --------------------------------------------------------------------------
diff --git a/drivers/acpi/fan.c b/drivers/acpi/fan.c
index 6004908..467479f 100644
--- a/drivers/acpi/fan.c
+++ b/drivers/acpi/fan.c
@@ -86,7 +86,7 @@ static int fan_get_cur_state(struct thermal_cooling_device *cdev, unsigned long
if (!device)
return -EINVAL;
- result = acpi_bus_get_power(device->handle, &acpi_state);
+ result = acpi_bus_update_power(device->handle, &acpi_state);
if (result)
return result;
@@ -123,7 +123,6 @@ static struct thermal_cooling_device_ops fan_cooling_ops = {
static int acpi_fan_add(struct acpi_device *device)
{
int result = 0;
- int state = 0;
struct thermal_cooling_device *cdev;
if (!device)
@@ -132,16 +131,12 @@ static int acpi_fan_add(struct acpi_device *device)
strcpy(acpi_device_name(device), "Fan");
strcpy(acpi_device_class(device), ACPI_FAN_CLASS);
- result = acpi_bus_get_power(device->handle, &state);
+ result = acpi_bus_update_power(device->handle, NULL);
if (result) {
- printk(KERN_ERR PREFIX "Reading power state\n");
+ printk(KERN_ERR PREFIX "Setting initial power state\n");
goto end;
}
- device->flags.force_power_state = 1;
- acpi_bus_set_power(device->handle, state);
- device->flags.force_power_state = 0;
-
cdev = thermal_cooling_device_register("Fan", device,
&fan_cooling_ops);
if (IS_ERR(cdev)) {
@@ -200,22 +195,14 @@ static int acpi_fan_suspend(struct acpi_device *device, pm_message_t state)
static int acpi_fan_resume(struct acpi_device *device)
{
- int result = 0;
- int power_state = 0;
+ int result;
if (!device)
return -EINVAL;
- result = acpi_bus_get_power(device->handle, &power_state);
- if (result) {
- printk(KERN_ERR PREFIX
- "Error reading fan power state\n");
- return result;
- }
-
- device->flags.force_power_state = 1;
- acpi_bus_set_power(device->handle, power_state);
- device->flags.force_power_state = 0;
+ result = acpi_bus_update_power(device->handle, NULL);
+ if (result)
+ printk(KERN_ERR PREFIX "Error updating fan power state\n");
return result;
}
diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c
index 78b0164..7c47ed5 100644
--- a/drivers/acpi/glue.c
+++ b/drivers/acpi/glue.c
@@ -167,11 +167,8 @@ static int acpi_bind_one(struct device *dev, acpi_handle handle)
"firmware_node");
ret = sysfs_create_link(&acpi_dev->dev.kobj, &dev->kobj,
"physical_node");
- if (acpi_dev->wakeup.flags.valid) {
+ if (acpi_dev->wakeup.flags.valid)
device_set_wakeup_capable(dev, true);
- device_set_wakeup_enable(dev,
- acpi_dev->wakeup.state.enabled);
- }
}
return 0;
diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h
index a212bfe..b1cc81a 100644
--- a/drivers/acpi/internal.h
+++ b/drivers/acpi/internal.h
@@ -41,9 +41,10 @@ static inline int acpi_debugfs_init(void) { return 0; }
int acpi_power_init(void);
int acpi_device_sleep_wake(struct acpi_device *dev,
int enable, int sleep_state, int dev_state);
-int acpi_power_get_inferred_state(struct acpi_device *device);
+int acpi_power_get_inferred_state(struct acpi_device *device, int *state);
+int acpi_power_on_resources(struct acpi_device *device, int state);
int acpi_power_transition(struct acpi_device *device, int state);
-extern int acpi_power_nocheck;
+int acpi_bus_init_power(struct acpi_device *device);
int acpi_wakeup_device_init(void);
void acpi_early_processor_set_pdc(void);
@@ -82,8 +83,16 @@ extern int acpi_sleep_init(void);
#ifdef CONFIG_ACPI_SLEEP
int acpi_sleep_proc_init(void);
+int suspend_nvs_alloc(void);
+void suspend_nvs_free(void);
+int suspend_nvs_save(void);
+void suspend_nvs_restore(void);
#else
static inline int acpi_sleep_proc_init(void) { return 0; }
+static inline int suspend_nvs_alloc(void) { return 0; }
+static inline void suspend_nvs_free(void) {}
+static inline int suspend_nvs_save(void) { return 0; }
+static inline void suspend_nvs_restore(void) {}
#endif
#endif /* _ACPI_INTERNAL_H_ */
diff --git a/drivers/acpi/numa.c b/drivers/acpi/numa.c
index d9926af..5eb25eb 100644
--- a/drivers/acpi/numa.c
+++ b/drivers/acpi/numa.c
@@ -275,23 +275,19 @@ acpi_table_parse_srat(enum acpi_srat_type id,
int __init acpi_numa_init(void)
{
int ret = 0;
- int nr_cpu_entries = nr_cpu_ids;
-#ifdef CONFIG_X86
/*
* Should not limit number with cpu num that is from NR_CPUS or nr_cpus=
* SRAT cpu entries could have different order with that in MADT.
* So go over all cpu entries in SRAT to get apicid to node mapping.
*/
- nr_cpu_entries = MAX_LOCAL_APIC;
-#endif
/* SRAT: Static Resource Affinity Table */
if (!acpi_table_parse(ACPI_SIG_SRAT, acpi_parse_srat)) {
acpi_table_parse_srat(ACPI_SRAT_TYPE_X2APIC_CPU_AFFINITY,
- acpi_parse_x2apic_affinity, nr_cpu_entries);
+ acpi_parse_x2apic_affinity, 0);
acpi_table_parse_srat(ACPI_SRAT_TYPE_CPU_AFFINITY,
- acpi_parse_processor_affinity, nr_cpu_entries);
+ acpi_parse_processor_affinity, 0);
ret = acpi_table_parse_srat(ACPI_SRAT_TYPE_MEMORY_AFFINITY,
acpi_parse_memory_affinity,
NR_NODE_MEMBLKS);
diff --git a/kernel/power/nvs.c b/drivers/acpi/nvs.c
index 1836db6..fa5a1df 100644
--- a/kernel/power/nvs.c
+++ b/drivers/acpi/nvs.c
@@ -1,7 +1,7 @@
/*
- * linux/kernel/power/hibernate_nvs.c - Routines for handling NVS memory
+ * nvs.c - Routines for saving and restoring ACPI NVS memory region
*
- * Copyright (C) 2008,2009 Rafael J. Wysocki <rjw@sisk.pl>, Novell Inc.
+ * Copyright (C) 2008-2011 Rafael J. Wysocki <rjw@sisk.pl>, Novell Inc.
*
* This file is released under the GPLv2.
*/
@@ -11,7 +11,9 @@
#include <linux/list.h>
#include <linux/mm.h>
#include <linux/slab.h>
-#include <linux/suspend.h>
+#include <linux/acpi.h>
+#include <linux/acpi_io.h>
+#include <acpi/acpiosxf.h>
/*
* Platforms, like ACPI, may want us to save some memory used by them during
@@ -105,7 +107,7 @@ int suspend_nvs_alloc(void)
/**
* suspend_nvs_save - save NVS memory regions
*/
-void suspend_nvs_save(void)
+int suspend_nvs_save(void)
{
struct nvs_page *entry;
@@ -113,9 +115,16 @@ void suspend_nvs_save(void)
list_for_each_entry(entry, &nvs_list, node)
if (entry->data) {
- entry->kaddr = ioremap(entry->phys_start, entry->size);
+ entry->kaddr = acpi_os_ioremap(entry->phys_start,
+ entry->size);
+ if (!entry->kaddr) {
+ suspend_nvs_free();
+ return -ENOMEM;
+ }
memcpy(entry->data, entry->kaddr, entry->size);
}
+
+ return 0;
}
/**
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index 055d7b7..b093181 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -38,6 +38,7 @@
#include <linux/workqueue.h>
#include <linux/nmi.h>
#include <linux/acpi.h>
+#include <linux/acpi_io.h>
#include <linux/efi.h>
#include <linux/ioport.h>
#include <linux/list.h>
@@ -302,9 +303,10 @@ void __iomem *__init_refok
acpi_os_map_memory(acpi_physical_address phys, acpi_size size)
{
struct acpi_ioremap *map, *tmp_map;
- unsigned long flags, pg_sz;
+ unsigned long flags;
void __iomem *virt;
- phys_addr_t pg_off;
+ acpi_physical_address pg_off;
+ acpi_size pg_sz;
if (phys > ULONG_MAX) {
printk(KERN_ERR PREFIX "Cannot map memory that high\n");
@@ -320,7 +322,7 @@ acpi_os_map_memory(acpi_physical_address phys, acpi_size size)
pg_off = round_down(phys, PAGE_SIZE);
pg_sz = round_up(phys + size, PAGE_SIZE) - pg_off;
- virt = ioremap(pg_off, pg_sz);
+ virt = acpi_os_ioremap(pg_off, pg_sz);
if (!virt) {
kfree(map);
return NULL;
@@ -642,7 +644,7 @@ acpi_os_read_memory(acpi_physical_address phys_addr, u32 * value, u32 width)
virt_addr = acpi_map_vaddr_lookup(phys_addr, size);
rcu_read_unlock();
if (!virt_addr) {
- virt_addr = ioremap(phys_addr, size);
+ virt_addr = acpi_os_ioremap(phys_addr, size);
unmap = 1;
}
if (!value)
@@ -678,7 +680,7 @@ acpi_os_write_memory(acpi_physical_address phys_addr, u32 value, u32 width)
virt_addr = acpi_map_vaddr_lookup(phys_addr, size);
rcu_read_unlock();
if (!virt_addr) {
- virt_addr = ioremap(phys_addr, size);
+ virt_addr = acpi_os_ioremap(phys_addr, size);
unmap = 1;
}
@@ -1233,8 +1235,7 @@ __setup("acpi_enforce_resources=", acpi_enforce_resources_setup);
int acpi_check_resource_conflict(const struct resource *res)
{
struct acpi_res_list *res_list_elem;
- int ioport;
- int clash = 0;
+ int ioport = 0, clash = 0;
if (acpi_enforce_resources == ENFORCE_RESOURCES_NO)
return 0;
@@ -1264,9 +1265,13 @@ int acpi_check_resource_conflict(const struct resource *res)
if (clash) {
if (acpi_enforce_resources != ENFORCE_RESOURCES_NO) {
printk(KERN_WARNING "ACPI: resource %s %pR"
- " conflicts with ACPI region %s %pR\n",
+ " conflicts with ACPI region %s "
+ "[%s 0x%zx-0x%zx]\n",
res->name, res, res_list_elem->name,
- res_list_elem);
+ (res_list_elem->resource_type ==
+ ACPI_ADR_SPACE_SYSTEM_IO) ? "io" : "mem",
+ (size_t) res_list_elem->start,
+ (size_t) res_list_elem->end);
if (acpi_enforce_resources == ENFORCE_RESOURCES_LAX)
printk(KERN_NOTICE "ACPI: This conflict may"
" cause random problems and system"
diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c
index 96668ad..8524939 100644
--- a/drivers/acpi/pci_root.c
+++ b/drivers/acpi/pci_root.c
@@ -36,6 +36,7 @@
#include <linux/slab.h>
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
+#include <acpi/apei.h>
#define PREFIX "ACPI: "
@@ -47,6 +48,11 @@ static int acpi_pci_root_add(struct acpi_device *device);
static int acpi_pci_root_remove(struct acpi_device *device, int type);
static int acpi_pci_root_start(struct acpi_device *device);
+#define ACPI_PCIE_REQ_SUPPORT (OSC_EXT_PCI_CONFIG_SUPPORT \
+ | OSC_ACTIVE_STATE_PWR_SUPPORT \
+ | OSC_CLOCK_PWR_CAPABILITY_SUPPORT \
+ | OSC_MSI_SUPPORT)
+
static const struct acpi_device_id root_device_ids[] = {
{"PNP0A03", 0},
{"", 0},
@@ -566,6 +572,33 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device)
if (flags != base_flags)
acpi_pci_osc_support(root, flags);
+ if (!pcie_ports_disabled
+ && (flags & ACPI_PCIE_REQ_SUPPORT) == ACPI_PCIE_REQ_SUPPORT) {
+ flags = OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL
+ | OSC_PCI_EXPRESS_NATIVE_HP_CONTROL
+ | OSC_PCI_EXPRESS_PME_CONTROL;
+
+ if (pci_aer_available()) {
+ if (aer_acpi_firmware_first())
+ dev_dbg(root->bus->bridge,
+ "PCIe errors handled by BIOS.\n");
+ else
+ flags |= OSC_PCI_EXPRESS_AER_CONTROL;
+ }
+
+ dev_info(root->bus->bridge,
+ "Requesting ACPI _OSC control (0x%02x)\n", flags);
+
+ status = acpi_pci_osc_control_set(device->handle, &flags,
+ OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL);
+ if (ACPI_SUCCESS(status))
+ dev_info(root->bus->bridge,
+ "ACPI _OSC control (0x%02x) granted\n", flags);
+ else
+ dev_dbg(root->bus->bridge,
+ "ACPI _OSC request failed (code %d)\n", status);
+ }
+
pci_acpi_add_bus_pm_notifier(device, root->bus);
if (device->wakeup.flags.run_wake)
device_set_run_wake(root->bus->bridge, true);
@@ -600,6 +633,8 @@ static int acpi_pci_root_remove(struct acpi_device *device, int type)
static int __init acpi_pci_root_init(void)
{
+ acpi_hest_init();
+
if (acpi_pci_disabled)
return 0;
diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c
index 4c9c2fb..9ac2a9f 100644
--- a/drivers/acpi/power.c
+++ b/drivers/acpi/power.c
@@ -56,9 +56,6 @@ ACPI_MODULE_NAME("power");
#define ACPI_POWER_RESOURCE_STATE_ON 0x01
#define ACPI_POWER_RESOURCE_STATE_UNKNOWN 0xFF
-int acpi_power_nocheck;
-module_param_named(power_nocheck, acpi_power_nocheck, bool, 000);
-
static int acpi_power_add(struct acpi_device *device);
static int acpi_power_remove(struct acpi_device *device, int type);
static int acpi_power_resume(struct acpi_device *device);
@@ -148,9 +145,8 @@ static int acpi_power_get_state(acpi_handle handle, int *state)
static int acpi_power_get_list_state(struct acpi_handle_list *list, int *state)
{
- int result = 0, state1;
- u32 i = 0;
-
+ int cur_state;
+ int i = 0;
if (!list || !state)
return -EINVAL;
@@ -158,25 +154,33 @@ static int acpi_power_get_list_state(struct acpi_handle_list *list, int *state)
/* The state of the list is 'on' IFF all resources are 'on'. */
for (i = 0; i < list->count; i++) {
- /*
- * The state of the power resource can be obtained by
- * using the ACPI handle. In such case it is unnecessary to
- * get the Power resource first and then get its state again.
- */
- result = acpi_power_get_state(list->handles[i], &state1);
+ struct acpi_power_resource *resource;
+ acpi_handle handle = list->handles[i];
+ int result;
+
+ result = acpi_power_get_context(handle, &resource);
if (result)
return result;
- *state = state1;
+ mutex_lock(&resource->resource_lock);
- if (*state != ACPI_POWER_RESOURCE_STATE_ON)
+ result = acpi_power_get_state(handle, &cur_state);
+
+ mutex_unlock(&resource->resource_lock);
+
+ if (result)
+ return result;
+
+ if (cur_state != ACPI_POWER_RESOURCE_STATE_ON)
break;
}
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Resource list is %s\n",
- *state ? "on" : "off"));
+ cur_state ? "on" : "off"));
- return result;
+ *state = cur_state;
+
+ return 0;
}
static int __acpi_power_on(struct acpi_power_resource *resource)
@@ -222,7 +226,7 @@ static int acpi_power_on(acpi_handle handle)
return result;
}
-static int acpi_power_off_device(acpi_handle handle)
+static int acpi_power_off(acpi_handle handle)
{
int result = 0;
acpi_status status = AE_OK;
@@ -266,6 +270,35 @@ static int acpi_power_off_device(acpi_handle handle)
return result;
}
+static void __acpi_power_off_list(struct acpi_handle_list *list, int num_res)
+{
+ int i;
+
+ for (i = num_res - 1; i >= 0 ; i--)
+ acpi_power_off(list->handles[i]);
+}
+
+static void acpi_power_off_list(struct acpi_handle_list *list)
+{
+ __acpi_power_off_list(list, list->count);
+}
+
+static int acpi_power_on_list(struct acpi_handle_list *list)
+{
+ int result = 0;
+ int i;
+
+ for (i = 0; i < list->count; i++) {
+ result = acpi_power_on(list->handles[i]);
+ if (result) {
+ __acpi_power_off_list(list, i);
+ break;
+ }
+ }
+
+ return result;
+}
+
/**
* acpi_device_sleep_wake - execute _DSW (Device Sleep Wake) or (deprecated in
* ACPI 3.0) _PSW (Power State Wake)
@@ -404,8 +437,7 @@ int acpi_disable_wakeup_device_power(struct acpi_device *dev)
/* Close power resource */
for (i = 0; i < dev->wakeup.resources.count; i++) {
- int ret = acpi_power_off_device(
- dev->wakeup.resources.handles[i]);
+ int ret = acpi_power_off(dev->wakeup.resources.handles[i]);
if (ret) {
printk(KERN_ERR PREFIX "Transition power state\n");
dev->wakeup.flags.valid = 0;
@@ -423,19 +455,16 @@ int acpi_disable_wakeup_device_power(struct acpi_device *dev)
Device Power Management
-------------------------------------------------------------------------- */
-int acpi_power_get_inferred_state(struct acpi_device *device)
+int acpi_power_get_inferred_state(struct acpi_device *device, int *state)
{
int result = 0;
struct acpi_handle_list *list = NULL;
int list_state = 0;
int i = 0;
-
- if (!device)
+ if (!device || !state)
return -EINVAL;
- device->power.state = ACPI_STATE_UNKNOWN;
-
/*
* We know a device's inferred power state when all the resources
* required for a given D-state are 'on'.
@@ -450,22 +479,26 @@ int acpi_power_get_inferred_state(struct acpi_device *device)
return result;
if (list_state == ACPI_POWER_RESOURCE_STATE_ON) {
- device->power.state = i;
+ *state = i;
return 0;
}
}
- device->power.state = ACPI_STATE_D3;
-
+ *state = ACPI_STATE_D3;
return 0;
}
+int acpi_power_on_resources(struct acpi_device *device, int state)
+{
+ if (!device || state < ACPI_STATE_D0 || state > ACPI_STATE_D3)
+ return -EINVAL;
+
+ return acpi_power_on_list(&device->power.states[state].resources);
+}
+
int acpi_power_transition(struct acpi_device *device, int state)
{
- int result = 0;
- struct acpi_handle_list *cl = NULL; /* Current Resources */
- struct acpi_handle_list *tl = NULL; /* Target Resources */
- int i = 0;
+ int result;
if (!device || (state < ACPI_STATE_D0) || (state > ACPI_STATE_D3))
return -EINVAL;
@@ -477,37 +510,20 @@ int acpi_power_transition(struct acpi_device *device, int state)
|| (device->power.state > ACPI_STATE_D3))
return -ENODEV;
- cl = &device->power.states[device->power.state].resources;
- tl = &device->power.states[state].resources;
-
/* TBD: Resources must be ordered. */
/*
* First we reference all power resources required in the target list
- * (e.g. so the device doesn't lose power while transitioning).
+ * (e.g. so the device doesn't lose power while transitioning). Then,
+ * we dereference all power resources used in the current list.
*/
- for (i = 0; i < tl->count; i++) {
- result = acpi_power_on(tl->handles[i]);
- if (result)
- goto end;
- }
+ result = acpi_power_on_list(&device->power.states[state].resources);
+ if (!result)
+ acpi_power_off_list(
+ &device->power.states[device->power.state].resources);
- /*
- * Then we dereference all power resources used in the current list.
- */
- for (i = 0; i < cl->count; i++) {
- result = acpi_power_off_device(cl->handles[i]);
- if (result)
- goto end;
- }
-
- end:
- if (result)
- device->power.state = ACPI_STATE_UNKNOWN;
- else {
- /* We shouldn't change the state till all above operations succeed */
- device->power.state = state;
- }
+ /* We shouldn't change the state unless the above operations succeed. */
+ device->power.state = result ? ACPI_STATE_UNKNOWN : state;
return result;
}
diff --git a/drivers/acpi/proc.c b/drivers/acpi/proc.c
index afad677..f5f9869 100644
--- a/drivers/acpi/proc.c
+++ b/drivers/acpi/proc.c
@@ -311,7 +311,9 @@ acpi_system_wakeup_device_seq_show(struct seq_file *seq, void *offset)
dev->pnp.bus_id,
(u32) dev->wakeup.sleep_state,
dev->wakeup.flags.run_wake ? '*' : ' ',
- dev->wakeup.state.enabled ? "enabled" : "disabled");
+ (device_may_wakeup(&dev->dev)
+ || (ldev && device_may_wakeup(ldev))) ?
+ "enabled" : "disabled");
if (ldev)
seq_printf(seq, "%s:%s",
ldev->bus ? ldev->bus->name : "no-bus",
@@ -328,8 +330,10 @@ static void physical_device_enable_wakeup(struct acpi_device *adev)
{
struct device *dev = acpi_get_physical_device(adev->handle);
- if (dev && device_can_wakeup(dev))
- device_set_wakeup_enable(dev, adev->wakeup.state.enabled);
+ if (dev && device_can_wakeup(dev)) {
+ bool enable = !device_may_wakeup(dev);
+ device_set_wakeup_enable(dev, enable);
+ }
}
static ssize_t
@@ -341,7 +345,6 @@ acpi_system_write_wakeup_device(struct file *file,
char strbuf[5];
char str[5] = "";
unsigned int len = count;
- struct acpi_device *found_dev = NULL;
if (len > 4)
len = 4;
@@ -361,33 +364,13 @@ acpi_system_write_wakeup_device(struct file *file,
continue;
if (!strncmp(dev->pnp.bus_id, str, 4)) {
- dev->wakeup.state.enabled =
- dev->wakeup.state.enabled ? 0 : 1;
- found_dev = dev;
- break;
- }
- }
- if (found_dev) {
- physical_device_enable_wakeup(found_dev);
- list_for_each_safe(node, next, &acpi_wakeup_device_list) {
- struct acpi_device *dev = container_of(node,
- struct
- acpi_device,
- wakeup_list);
-
- if ((dev != found_dev) &&
- (dev->wakeup.gpe_number ==
- found_dev->wakeup.gpe_number)
- && (dev->wakeup.gpe_device ==
- found_dev->wakeup.gpe_device)) {
- printk(KERN_WARNING
- "ACPI: '%s' and '%s' have the same GPE, "
- "can't disable/enable one separately\n",
- dev->pnp.bus_id, found_dev->pnp.bus_id);
- dev->wakeup.state.enabled =
- found_dev->wakeup.state.enabled;
+ if (device_can_wakeup(&dev->dev)) {
+ bool enable = !device_may_wakeup(&dev->dev);
+ device_set_wakeup_enable(&dev->dev, enable);
+ } else {
physical_device_enable_wakeup(dev);
}
+ break;
}
}
mutex_unlock(&acpi_device_lock);
diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c
index bec561c..3c1a2fe 100644
--- a/drivers/acpi/processor_core.c
+++ b/drivers/acpi/processor_core.c
@@ -23,7 +23,7 @@ static int set_no_mwait(const struct dmi_system_id *id)
{
printk(KERN_NOTICE PREFIX "%s detected - "
"disabling mwait for CPU C-states\n", id->ident);
- idle_nomwait = 1;
+ boot_option_idle_override = IDLE_NOMWAIT;
return 0;
}
@@ -283,7 +283,7 @@ acpi_processor_eval_pdc(acpi_handle handle, struct acpi_object_list *pdc_in)
{
acpi_status status = AE_OK;
- if (idle_nomwait) {
+ if (boot_option_idle_override == IDLE_NOMWAIT) {
/*
* If mwait is disabled for CPU C-states, the C2C3_FFH access
* mode will be disabled in the parameter of _PDC object.
diff --git a/drivers/acpi/processor_driver.c b/drivers/acpi/processor_driver.c
index 85e4804..360a74e 100644
--- a/drivers/acpi/processor_driver.c
+++ b/drivers/acpi/processor_driver.c
@@ -40,10 +40,6 @@
#include <linux/pm.h>
#include <linux/cpufreq.h>
#include <linux/cpu.h>
-#ifdef CONFIG_ACPI_PROCFS
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
-#endif
#include <linux/dmi.h>
#include <linux/moduleparam.h>
#include <linux/cpuidle.h>
@@ -246,53 +242,6 @@ static int acpi_processor_errata(struct acpi_processor *pr)
return result;
}
-#ifdef CONFIG_ACPI_PROCFS
-static struct proc_dir_entry *acpi_processor_dir = NULL;
-
-static int __cpuinit acpi_processor_add_fs(struct acpi_device *device)
-{
- struct proc_dir_entry *entry = NULL;
-
-
- if (!acpi_device_dir(device)) {
- acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device),
- acpi_processor_dir);
- if (!acpi_device_dir(device))
- return -ENODEV;
- }
-
- /* 'throttling' [R/W] */
- entry = proc_create_data(ACPI_PROCESSOR_FILE_THROTTLING,
- S_IFREG | S_IRUGO | S_IWUSR,
- acpi_device_dir(device),
- &acpi_processor_throttling_fops,
- acpi_driver_data(device));
- if (!entry)
- return -EIO;
- return 0;
-}
-static int acpi_processor_remove_fs(struct acpi_device *device)
-{
-
- if (acpi_device_dir(device)) {
- remove_proc_entry(ACPI_PROCESSOR_FILE_THROTTLING,
- acpi_device_dir(device));
- remove_proc_entry(acpi_device_bid(device), acpi_processor_dir);
- acpi_device_dir(device) = NULL;
- }
-
- return 0;
-}
-#else
-static inline int acpi_processor_add_fs(struct acpi_device *device)
-{
- return 0;
-}
-static inline int acpi_processor_remove_fs(struct acpi_device *device)
-{
- return 0;
-}
-#endif
/* --------------------------------------------------------------------------
Driver Interface
-------------------------------------------------------------------------- */
@@ -478,8 +427,13 @@ static int acpi_cpu_soft_notify(struct notifier_block *nfb,
if (action == CPU_ONLINE && pr) {
acpi_processor_ppc_has_changed(pr, 0);
acpi_processor_cst_has_changed(pr);
+ acpi_processor_reevaluate_tstate(pr, action);
acpi_processor_tstate_has_changed(pr);
}
+ if (action == CPU_DEAD && pr) {
+ /* invalidate the flag.throttling after one CPU is offline */
+ acpi_processor_reevaluate_tstate(pr, action);
+ }
return NOTIFY_OK;
}
@@ -537,14 +491,10 @@ static int __cpuinit acpi_processor_add(struct acpi_device *device)
per_cpu(processors, pr->id) = pr;
- result = acpi_processor_add_fs(device);
- if (result)
- goto err_free_cpumask;
-
sysdev = get_cpu_sysdev(pr->id);
if (sysfs_create_link(&device->dev.kobj, &sysdev->kobj, "sysdev")) {
result = -EFAULT;
- goto err_remove_fs;
+ goto err_free_cpumask;
}
#ifdef CONFIG_CPU_FREQ
@@ -590,8 +540,6 @@ err_thermal_unregister:
thermal_cooling_device_unregister(pr->cdev);
err_power_exit:
acpi_processor_power_exit(pr, device);
-err_remove_fs:
- acpi_processor_remove_fs(device);
err_free_cpumask:
free_cpumask_var(pr->throttling.shared_cpu_map);
@@ -620,8 +568,6 @@ static int acpi_processor_remove(struct acpi_device *device, int type)
sysfs_remove_link(&device->dev.kobj, "sysdev");
- acpi_processor_remove_fs(device);
-
if (pr->cdev) {
sysfs_remove_link(&device->dev.kobj, "thermal_cooling");
sysfs_remove_link(&pr->cdev->device.kobj, "device");
@@ -854,12 +800,6 @@ static int __init acpi_processor_init(void)
memset(&errata, 0, sizeof(errata));
-#ifdef CONFIG_ACPI_PROCFS
- acpi_processor_dir = proc_mkdir(ACPI_PROCESSOR_CLASS, acpi_root_dir);
- if (!acpi_processor_dir)
- return -ENOMEM;
-#endif
-
if (!cpuidle_register_driver(&acpi_idle_driver)) {
printk(KERN_DEBUG "ACPI: %s registered with cpuidle\n",
acpi_idle_driver.name);
@@ -885,10 +825,6 @@ static int __init acpi_processor_init(void)
out_cpuidle:
cpuidle_unregister_driver(&acpi_idle_driver);
-#ifdef CONFIG_ACPI_PROCFS
- remove_proc_entry(ACPI_PROCESSOR_CLASS, acpi_root_dir);
-#endif
-
return result;
}
@@ -907,10 +843,6 @@ static void __exit acpi_processor_exit(void)
cpuidle_unregister_driver(&acpi_idle_driver);
-#ifdef CONFIG_ACPI_PROCFS
- remove_proc_entry(ACPI_PROCESSOR_CLASS, acpi_root_dir);
-#endif
-
return;
}
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
index a765b82..d615b7d 100644
--- a/drivers/acpi/processor_idle.c
+++ b/drivers/acpi/processor_idle.c
@@ -79,6 +79,13 @@ module_param(bm_check_disable, uint, 0000);
static unsigned int latency_factor __read_mostly = 2;
module_param(latency_factor, uint, 0644);
+static int disabled_by_idle_boot_param(void)
+{
+ return boot_option_idle_override == IDLE_POLL ||
+ boot_option_idle_override == IDLE_FORCE_MWAIT ||
+ boot_option_idle_override == IDLE_HALT;
+}
+
/*
* IBM ThinkPad R40e crashes mysteriously when going into C2 or C3.
* For now disable this. Probably a bug somewhere else.
@@ -455,7 +462,7 @@ static int acpi_processor_get_power_info_cst(struct acpi_processor *pr)
continue;
}
if (cx.type == ACPI_STATE_C1 &&
- (idle_halt || idle_nomwait)) {
+ (boot_option_idle_override == IDLE_NOMWAIT)) {
/*
* In most cases the C1 space_id obtained from
* _CST object is FIXED_HARDWARE access mode.
@@ -1016,7 +1023,6 @@ static int acpi_processor_setup_cpuidle(struct acpi_processor *pr)
state->flags = 0;
switch (cx->type) {
case ACPI_STATE_C1:
- state->flags |= CPUIDLE_FLAG_SHALLOW;
if (cx->entry_method == ACPI_CSTATE_FFH)
state->flags |= CPUIDLE_FLAG_TIME_VALID;
@@ -1025,16 +1031,13 @@ static int acpi_processor_setup_cpuidle(struct acpi_processor *pr)
break;
case ACPI_STATE_C2:
- state->flags |= CPUIDLE_FLAG_BALANCED;
state->flags |= CPUIDLE_FLAG_TIME_VALID;
state->enter = acpi_idle_enter_simple;
dev->safe_state = state;
break;
case ACPI_STATE_C3:
- state->flags |= CPUIDLE_FLAG_DEEP;
state->flags |= CPUIDLE_FLAG_TIME_VALID;
- state->flags |= CPUIDLE_FLAG_CHECK_BM;
state->enter = pr->flags.bm_check ?
acpi_idle_enter_bm :
acpi_idle_enter_simple;
@@ -1058,7 +1061,7 @@ int acpi_processor_cst_has_changed(struct acpi_processor *pr)
{
int ret = 0;
- if (boot_option_idle_override)
+ if (disabled_by_idle_boot_param())
return 0;
if (!pr)
@@ -1089,19 +1092,10 @@ int __cpuinit acpi_processor_power_init(struct acpi_processor *pr,
acpi_status status = 0;
static int first_run;
- if (boot_option_idle_override)
+ if (disabled_by_idle_boot_param())
return 0;
if (!first_run) {
- if (idle_halt) {
- /*
- * When the boot option of "idle=halt" is added, halt
- * is used for CPU IDLE.
- * In such case C2/C3 is meaningless. So the max_cstate
- * is set to one.
- */
- max_cstate = 1;
- }
dmi_check_system(processor_power_dmi_table);
max_cstate = acpi_processor_cstate_check(max_cstate);
if (max_cstate < ACPI_C_STATES_MAX)
@@ -1142,7 +1136,7 @@ int __cpuinit acpi_processor_power_init(struct acpi_processor *pr,
int acpi_processor_power_exit(struct acpi_processor *pr,
struct acpi_device *device)
{
- if (boot_option_idle_override)
+ if (disabled_by_idle_boot_param())
return 0;
cpuidle_unregister_device(&pr->power.dev);
diff --git a/drivers/acpi/processor_throttling.c b/drivers/acpi/processor_throttling.c
index ff36327..fa84e97 100644
--- a/drivers/acpi/processor_throttling.c
+++ b/drivers/acpi/processor_throttling.c
@@ -32,10 +32,6 @@
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/cpufreq.h>
-#ifdef CONFIG_ACPI_PROCFS
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
-#endif
#include <asm/io.h>
#include <asm/uaccess.h>
@@ -370,6 +366,58 @@ int acpi_processor_tstate_has_changed(struct acpi_processor *pr)
}
/*
+ * This function is used to reevaluate whether the T-state is valid
+ * after one CPU is onlined/offlined.
+ * It is noted that it won't reevaluate the following properties for
+ * the T-state.
+ * 1. Control method.
+ * 2. the number of supported T-state
+ * 3. TSD domain
+ */
+void acpi_processor_reevaluate_tstate(struct acpi_processor *pr,
+ unsigned long action)
+{
+ int result = 0;
+
+ if (action == CPU_DEAD) {
+ /* When one CPU is offline, the T-state throttling
+ * will be invalidated.
+ */
+ pr->flags.throttling = 0;
+ return;
+ }
+ /* the following is to recheck whether the T-state is valid for
+ * the online CPU
+ */
+ if (!pr->throttling.state_count) {
+ /* If the number of T-state is invalid, it is
+ * invalidated.
+ */
+ pr->flags.throttling = 0;
+ return;
+ }
+ pr->flags.throttling = 1;
+
+ /* Disable throttling (if enabled). We'll let subsequent
+ * policy (e.g.thermal) decide to lower performance if it
+ * so chooses, but for now we'll crank up the speed.
+ */
+
+ result = acpi_processor_get_throttling(pr);
+ if (result)
+ goto end;
+
+ if (pr->throttling.state) {
+ result = acpi_processor_set_throttling(pr, 0, false);
+ if (result)
+ goto end;
+ }
+
+end:
+ if (result)
+ pr->flags.throttling = 0;
+}
+/*
* _PTC - Processor Throttling Control (and status) register location
*/
static int acpi_processor_get_throttling_control(struct acpi_processor *pr)
@@ -876,7 +924,11 @@ static int acpi_processor_get_throttling(struct acpi_processor *pr)
*/
cpumask_copy(saved_mask, &current->cpus_allowed);
/* FIXME: use work_on_cpu() */
- set_cpus_allowed_ptr(current, cpumask_of(pr->id));
+ if (set_cpus_allowed_ptr(current, cpumask_of(pr->id))) {
+ /* Can't migrate to the target pr->id CPU. Exit */
+ free_cpumask_var(saved_mask);
+ return -ENODEV;
+ }
ret = pr->throttling.acpi_processor_get_throttling(pr);
/* restore the previous state */
set_cpus_allowed_ptr(current, saved_mask);
@@ -1051,6 +1103,14 @@ int acpi_processor_set_throttling(struct acpi_processor *pr,
return -ENOMEM;
}
+ if (cpu_is_offline(pr->id)) {
+ /*
+ * the cpu pointed by pr->id is offline. Unnecessary to change
+ * the throttling state any more.
+ */
+ return -ENODEV;
+ }
+
cpumask_copy(saved_mask, &current->cpus_allowed);
t_state.target_state = state;
p_throttling = &(pr->throttling);
@@ -1074,7 +1134,11 @@ int acpi_processor_set_throttling(struct acpi_processor *pr,
*/
if (p_throttling->shared_type == DOMAIN_COORD_TYPE_SW_ANY) {
/* FIXME: use work_on_cpu() */
- set_cpus_allowed_ptr(current, cpumask_of(pr->id));
+ if (set_cpus_allowed_ptr(current, cpumask_of(pr->id))) {
+ /* Can't migrate to the pr->id CPU. Exit */
+ ret = -ENODEV;
+ goto exit;
+ }
ret = p_throttling->acpi_processor_set_throttling(pr,
t_state.target_state, force);
} else {
@@ -1106,7 +1170,8 @@ int acpi_processor_set_throttling(struct acpi_processor *pr,
}
t_state.cpu = i;
/* FIXME: use work_on_cpu() */
- set_cpus_allowed_ptr(current, cpumask_of(i));
+ if (set_cpus_allowed_ptr(current, cpumask_of(i)))
+ continue;
ret = match_pr->throttling.
acpi_processor_set_throttling(
match_pr, t_state.target_state, force);
@@ -1126,6 +1191,7 @@ int acpi_processor_set_throttling(struct acpi_processor *pr,
/* restore the previous state */
/* FIXME: use work_on_cpu() */
set_cpus_allowed_ptr(current, saved_mask);
+exit:
free_cpumask_var(online_throttling_cpus);
free_cpumask_var(saved_mask);
return ret;
@@ -1216,113 +1282,3 @@ int acpi_processor_get_throttling_info(struct acpi_processor *pr)
return result;
}
-#ifdef CONFIG_ACPI_PROCFS
-/* proc interface */
-static int acpi_processor_throttling_seq_show(struct seq_file *seq,
- void *offset)
-{
- struct acpi_processor *pr = seq->private;
- int i = 0;
- int result = 0;
-
- if (!pr)
- goto end;
-
- if (!(pr->throttling.state_count > 0)) {
- seq_puts(seq, "<not supported>\n");
- goto end;
- }
-
- result = acpi_processor_get_throttling(pr);
-
- if (result) {
- seq_puts(seq,
- "Could not determine current throttling state.\n");
- goto end;
- }
-
- seq_printf(seq, "state count: %d\n"
- "active state: T%d\n"
- "state available: T%d to T%d\n",
- pr->throttling.state_count, pr->throttling.state,
- pr->throttling_platform_limit,
- pr->throttling.state_count - 1);
-
- seq_puts(seq, "states:\n");
- if (pr->throttling.acpi_processor_get_throttling ==
- acpi_processor_get_throttling_fadt) {
- for (i = 0; i < pr->throttling.state_count; i++)
- seq_printf(seq, " %cT%d: %02d%%\n",
- (i == pr->throttling.state ? '*' : ' '), i,
- (pr->throttling.states[i].performance ? pr->
- throttling.states[i].performance / 10 : 0));
- } else {
- for (i = 0; i < pr->throttling.state_count; i++)
- seq_printf(seq, " %cT%d: %02d%%\n",
- (i == pr->throttling.state ? '*' : ' '), i,
- (int)pr->throttling.states_tss[i].
- freqpercentage);
- }
-
- end:
- return 0;
-}
-
-static int acpi_processor_throttling_open_fs(struct inode *inode,
- struct file *file)
-{
- return single_open(file, acpi_processor_throttling_seq_show,
- PDE(inode)->data);
-}
-
-static ssize_t acpi_processor_write_throttling(struct file *file,
- const char __user * buffer,
- size_t count, loff_t * data)
-{
- int result = 0;
- struct seq_file *m = file->private_data;
- struct acpi_processor *pr = m->private;
- char state_string[5] = "";
- char *charp = NULL;
- size_t state_val = 0;
- char tmpbuf[5] = "";
-
- if (!pr || (count > sizeof(state_string) - 1))
- return -EINVAL;
-
- if (copy_from_user(state_string, buffer, count))
- return -EFAULT;
-
- state_string[count] = '\0';
- if ((count > 0) && (state_string[count-1] == '\n'))
- state_string[count-1] = '\0';
-
- charp = state_string;
- if ((state_string[0] == 't') || (state_string[0] == 'T'))
- charp++;
-
- state_val = simple_strtoul(charp, NULL, 0);
- if (state_val >= pr->throttling.state_count)
- return -EINVAL;
-
- snprintf(tmpbuf, 5, "%zu", state_val);
-
- if (strcmp(tmpbuf, charp) != 0)
- return -EINVAL;
-
- result = acpi_processor_set_throttling(pr, state_val, false);
- if (result)
- return result;
-
- return count;
-}
-
-const struct file_operations acpi_processor_throttling_fops = {
- .owner = THIS_MODULE,
- .open = acpi_processor_throttling_open_fs,
- .read = seq_read,
- .write = acpi_processor_write_throttling,
- .llseek = seq_lseek,
- .release = single_release,
-};
-#endif
diff --git a/drivers/acpi/sbs.c b/drivers/acpi/sbs.c
index e5dbedb..51ae379 100644
--- a/drivers/acpi/sbs.c
+++ b/drivers/acpi/sbs.c
@@ -484,6 +484,8 @@ acpi_sbs_add_fs(struct proc_dir_entry **dir,
const struct file_operations *state_fops,
const struct file_operations *alarm_fops, void *data)
{
+ printk(KERN_WARNING PREFIX "Deprecated procfs I/F for SBS is loaded,"
+ " please retry with CONFIG_ACPI_PROCFS_POWER cleared\n");
if (!*dir) {
*dir = proc_mkdir(dir_name, parent_dir);
if (!*dir) {
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index 29ef505..b99e624 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -778,7 +778,7 @@ acpi_bus_extract_wakeup_device_power_package(acpi_handle handle,
wakeup->resources.handles[i] = element->reference.handle;
}
- acpi_gpe_can_wake(wakeup->gpe_device, wakeup->gpe_number);
+ acpi_setup_gpe_for_wake(handle, wakeup->gpe_device, wakeup->gpe_number);
out:
kfree(buffer.pointer);
@@ -803,7 +803,7 @@ static void acpi_bus_set_run_wake_flags(struct acpi_device *device)
/* Power button, Lid switch always enable wakeup */
if (!acpi_match_device_ids(device, button_device_ids)) {
device->wakeup.flags.run_wake = 1;
- device->wakeup.flags.always_enabled = 1;
+ device_set_wakeup_capable(&device->dev, true);
return;
}
@@ -815,16 +815,22 @@ static void acpi_bus_set_run_wake_flags(struct acpi_device *device)
!!(event_status & ACPI_EVENT_FLAG_HANDLE);
}
-static int acpi_bus_get_wakeup_device_flags(struct acpi_device *device)
+static void acpi_bus_get_wakeup_device_flags(struct acpi_device *device)
{
+ acpi_handle temp;
acpi_status status = 0;
int psw_error;
+ /* Presence of _PRW indicates wake capable */
+ status = acpi_get_handle(device->handle, "_PRW", &temp);
+ if (ACPI_FAILURE(status))
+ return;
+
status = acpi_bus_extract_wakeup_device_power_package(device->handle,
&device->wakeup);
if (ACPI_FAILURE(status)) {
ACPI_EXCEPTION((AE_INFO, status, "Extracting _PRW package"));
- goto end;
+ return;
}
device->wakeup.flags.valid = 1;
@@ -840,13 +846,10 @@ static int acpi_bus_get_wakeup_device_flags(struct acpi_device *device)
if (psw_error)
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"error in _DSW or _PSW evaluation\n"));
-
-end:
- if (ACPI_FAILURE(status))
- device->flags.wake_capable = 0;
- return 0;
}
+static void acpi_bus_add_power_resource(acpi_handle handle);
+
static int acpi_bus_get_power_flags(struct acpi_device *device)
{
acpi_status status = 0;
@@ -875,8 +878,12 @@ static int acpi_bus_get_power_flags(struct acpi_device *device)
acpi_evaluate_reference(device->handle, object_name, NULL,
&ps->resources);
if (ps->resources.count) {
+ int j;
+
device->power.flags.power_resources = 1;
ps->flags.valid = 1;
+ for (j = 0; j < ps->resources.count; j++)
+ acpi_bus_add_power_resource(ps->resources.handles[j]);
}
/* Evaluate "_PSx" to see if we can do explicit sets */
@@ -901,10 +908,7 @@ static int acpi_bus_get_power_flags(struct acpi_device *device)
device->power.states[ACPI_STATE_D3].flags.valid = 1;
device->power.states[ACPI_STATE_D3].power = 0;
- /* TBD: System wake support and resource requirements. */
-
- device->power.state = ACPI_STATE_UNKNOWN;
- acpi_bus_get_power(device->handle, &(device->power.state));
+ acpi_bus_init_power(device);
return 0;
}
@@ -947,11 +951,6 @@ static int acpi_bus_get_flags(struct acpi_device *device)
if (ACPI_SUCCESS(status))
device->flags.power_manageable = 1;
- /* Presence of _PRW indicates wake capable */
- status = acpi_get_handle(device->handle, "_PRW", &temp);
- if (ACPI_SUCCESS(status))
- device->flags.wake_capable = 1;
-
/* TBD: Performance management */
return 0;
@@ -1278,11 +1277,7 @@ static int acpi_add_single_object(struct acpi_device **child,
* Wakeup device management
*-----------------------
*/
- if (device->flags.wake_capable) {
- result = acpi_bus_get_wakeup_device_flags(device);
- if (result)
- goto end;
- }
+ acpi_bus_get_wakeup_device_flags(device);
/*
* Performance Management
@@ -1326,6 +1321,20 @@ end:
#define ACPI_STA_DEFAULT (ACPI_STA_DEVICE_PRESENT | ACPI_STA_DEVICE_ENABLED | \
ACPI_STA_DEVICE_UI | ACPI_STA_DEVICE_FUNCTIONING)
+static void acpi_bus_add_power_resource(acpi_handle handle)
+{
+ struct acpi_bus_ops ops = {
+ .acpi_op_add = 1,
+ .acpi_op_start = 1,
+ };
+ struct acpi_device *device = NULL;
+
+ acpi_bus_get_device(handle, &device);
+ if (!device)
+ acpi_add_single_object(&device, handle, ACPI_BUS_TYPE_POWER,
+ ACPI_STA_DEFAULT, &ops);
+}
+
static int acpi_bus_type_and_status(acpi_handle handle, int *type,
unsigned long long *sta)
{
@@ -1371,7 +1380,6 @@ static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl,
struct acpi_bus_ops *ops = context;
int type;
unsigned long long sta;
- struct acpi_device_wakeup wakeup;
struct acpi_device *device;
acpi_status status;
int result;
@@ -1382,7 +1390,13 @@ static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl,
if (!(sta & ACPI_STA_DEVICE_PRESENT) &&
!(sta & ACPI_STA_DEVICE_FUNCTIONING)) {
- acpi_bus_extract_wakeup_device_power_package(handle, &wakeup);
+ struct acpi_device_wakeup wakeup;
+ acpi_handle temp;
+
+ status = acpi_get_handle(handle, "_PRW", &temp);
+ if (ACPI_SUCCESS(status))
+ acpi_bus_extract_wakeup_device_power_package(handle,
+ &wakeup);
return AE_CTRL_DEPTH;
}
@@ -1467,7 +1481,7 @@ int acpi_bus_start(struct acpi_device *device)
result = acpi_bus_scan(device->handle, &ops, NULL);
- acpi_update_gpes();
+ acpi_update_all_gpes();
return result;
}
@@ -1573,6 +1587,8 @@ int __init acpi_scan_init(void)
printk(KERN_ERR PREFIX "Could not register bus type\n");
}
+ acpi_power_init();
+
/*
* Enumerate devices in the ACPI namespace.
*/
@@ -1584,7 +1600,7 @@ int __init acpi_scan_init(void)
if (result)
acpi_device_unregister(acpi_root, ACPI_BUS_REMOVAL_NORMAL);
else
- acpi_update_gpes();
+ acpi_update_all_gpes();
return result;
}
diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c
index c423231..d6a8cd1 100644
--- a/drivers/acpi/sleep.c
+++ b/drivers/acpi/sleep.c
@@ -124,8 +124,7 @@ static int acpi_pm_freeze(void)
static int acpi_pm_pre_suspend(void)
{
acpi_pm_freeze();
- suspend_nvs_save();
- return 0;
+ return suspend_nvs_save();
}
/**
@@ -151,7 +150,7 @@ static int acpi_pm_prepare(void)
{
int error = __acpi_pm_prepare();
if (!error)
- acpi_pm_pre_suspend();
+ error = acpi_pm_pre_suspend();
return error;
}
@@ -167,6 +166,7 @@ static void acpi_pm_finish(void)
u32 acpi_state = acpi_target_sleep_state;
acpi_ec_unblock_transactions();
+ suspend_nvs_free();
if (acpi_state == ACPI_STATE_S0)
return;
@@ -187,7 +187,6 @@ static void acpi_pm_finish(void)
*/
static void acpi_pm_end(void)
{
- suspend_nvs_free();
/*
* This is necessary in case acpi_pm_finish() is not called during a
* failing transition to a sleep state.
@@ -435,6 +434,14 @@ static struct dmi_system_id __initdata acpisleep_dmi_table[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "VGN-NW130D"),
},
},
+ {
+ .callback = init_nvs_nosave,
+ .ident = "Averatec AV1020-ED2",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "AVERATEC"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "1000 Series"),
+ },
+ },
{},
};
#endif /* CONFIG_SUSPEND */
diff --git a/drivers/acpi/sysfs.c b/drivers/acpi/sysfs.c
index f8588f8..61891e7 100644
--- a/drivers/acpi/sysfs.c
+++ b/drivers/acpi/sysfs.c
@@ -438,7 +438,7 @@ static void delete_gpe_attr_array(void)
return;
}
-void acpi_os_gpe_count(u32 gpe_number)
+static void gpe_count(u32 gpe_number)
{
acpi_gpe_count++;
@@ -454,7 +454,7 @@ void acpi_os_gpe_count(u32 gpe_number)
return;
}
-void acpi_os_fixed_event_count(u32 event_number)
+static void fixed_event_count(u32 event_number)
{
if (!all_counters)
return;
@@ -468,6 +468,16 @@ void acpi_os_fixed_event_count(u32 event_number)
return;
}
+static void acpi_gbl_event_handler(u32 event_type, acpi_handle device,
+ u32 event_number, void *context)
+{
+ if (event_type == ACPI_EVENT_TYPE_GPE)
+ gpe_count(event_number);
+
+ if (event_type == ACPI_EVENT_TYPE_FIXED)
+ fixed_event_count(event_number);
+}
+
static int get_status(u32 index, acpi_event_status *status,
acpi_handle *handle)
{
@@ -601,6 +611,7 @@ end:
void acpi_irq_stats_init(void)
{
+ acpi_status status;
int i;
if (all_counters)
@@ -619,6 +630,10 @@ void acpi_irq_stats_init(void)
if (all_counters == NULL)
goto fail;
+ status = acpi_install_global_event_handler(acpi_gbl_event_handler, NULL);
+ if (ACPI_FAILURE(status))
+ goto fail;
+
counter_attrs = kzalloc(sizeof(struct kobj_attribute) * (num_counters),
GFP_KERNEL);
if (counter_attrs == NULL)
diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c
index 5a27b0a..2607e17 100644
--- a/drivers/acpi/thermal.c
+++ b/drivers/acpi/thermal.c
@@ -1059,8 +1059,9 @@ static int acpi_thermal_resume(struct acpi_device *device)
break;
tz->trips.active[i].flags.enabled = 1;
for (j = 0; j < tz->trips.active[i].devices.count; j++) {
- result = acpi_bus_get_power(tz->trips.active[i].devices.
- handles[j], &power_state);
+ result = acpi_bus_update_power(
+ tz->trips.active[i].devices.handles[j],
+ &power_state);
if (result || (power_state != ACPI_STATE_D0)) {
tz->trips.active[i].flags.enabled = 0;
break;
diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c
index 15a0fde..90f8f76 100644
--- a/drivers/acpi/video.c
+++ b/drivers/acpi/video.c
@@ -33,7 +33,6 @@
#include <linux/input.h>
#include <linux/backlight.h>
#include <linux/thermal.h>
-#include <linux/video_output.h>
#include <linux/sort.h>
#include <linux/pci.h>
#include <linux/pci_ids.h>
@@ -81,6 +80,13 @@ module_param(brightness_switch_enabled, bool, 0644);
static int allow_duplicates;
module_param(allow_duplicates, bool, 0644);
+/*
+ * Some BIOSes claim they use minimum backlight at boot,
+ * and this may bring dimming screen after boot
+ */
+static int use_bios_initial_backlight = 1;
+module_param(use_bios_initial_backlight, bool, 0644);
+
static int register_count = 0;
static int acpi_video_bus_add(struct acpi_device *device);
static int acpi_video_bus_remove(struct acpi_device *device, int type);
@@ -172,9 +178,6 @@ struct acpi_video_device_cap {
u8 _BQC:1; /* Get current brightness level */
u8 _BCQ:1; /* Some buggy BIOS uses _BCQ instead of _BQC */
u8 _DDC:1; /*Return the EDID for this device */
- u8 _DCS:1; /*Return status of output device */
- u8 _DGS:1; /*Query graphics state */
- u8 _DSS:1; /*Device state set */
};
struct acpi_video_brightness_flags {
@@ -202,7 +205,6 @@ struct acpi_video_device {
struct acpi_video_device_brightness *brightness;
struct backlight_device *backlight;
struct thermal_cooling_device *cooling_dev;
- struct output_device *output_dev;
};
static const char device_decode[][30] = {
@@ -226,10 +228,6 @@ static int acpi_video_get_next_level(struct acpi_video_device *device,
u32 level_current, u32 event);
static int acpi_video_switch_brightness(struct acpi_video_device *device,
int event);
-static int acpi_video_device_get_state(struct acpi_video_device *device,
- unsigned long long *state);
-static int acpi_video_output_get(struct output_device *od);
-static int acpi_video_device_set_state(struct acpi_video_device *device, int state);
/*backlight device sysfs support*/
static int acpi_video_get_brightness(struct backlight_device *bd)
@@ -265,30 +263,6 @@ static const struct backlight_ops acpi_backlight_ops = {
.update_status = acpi_video_set_brightness,
};
-/*video output device sysfs support*/
-static int acpi_video_output_get(struct output_device *od)
-{
- unsigned long long state;
- struct acpi_video_device *vd =
- (struct acpi_video_device *)dev_get_drvdata(&od->dev);
- acpi_video_device_get_state(vd, &state);
- return (int)state;
-}
-
-static int acpi_video_output_set(struct output_device *od)
-{
- unsigned long state = od->request_state;
- struct acpi_video_device *vd=
- (struct acpi_video_device *)dev_get_drvdata(&od->dev);
- return acpi_video_device_set_state(vd, state);
-}
-
-static struct output_properties acpi_output_properties = {
- .set_state = acpi_video_output_set,
- .get_status = acpi_video_output_get,
-};
-
-
/* thermal cooling device callbacks */
static int video_get_max_state(struct thermal_cooling_device *cooling_dev, unsigned
long *state)
@@ -344,34 +318,6 @@ static struct thermal_cooling_device_ops video_cooling_ops = {
Video Management
-------------------------------------------------------------------------- */
-/* device */
-
-static int
-acpi_video_device_get_state(struct acpi_video_device *device,
- unsigned long long *state)
-{
- int status;
-
- status = acpi_evaluate_integer(device->dev->handle, "_DCS", NULL, state);
-
- return status;
-}
-
-static int
-acpi_video_device_set_state(struct acpi_video_device *device, int state)
-{
- int status;
- union acpi_object arg0 = { ACPI_TYPE_INTEGER };
- struct acpi_object_list args = { 1, &arg0 };
- unsigned long long ret;
-
-
- arg0.integer.value = state;
- status = acpi_evaluate_integer(device->dev->handle, "_DSS", &args, &ret);
-
- return status;
-}
-
static int
acpi_video_device_lcd_query_levels(struct acpi_video_device *device,
union acpi_object **levels)
@@ -766,9 +712,11 @@ acpi_video_init_brightness(struct acpi_video_device *device)
* when invoked for the first time, i.e. level_old is invalid.
* set the backlight to max_level in this case
*/
- for (i = 2; i < br->count; i++)
- if (level_old == br->levels[i])
- level = level_old;
+ if (use_bios_initial_backlight) {
+ for (i = 2; i < br->count; i++)
+ if (level_old == br->levels[i])
+ level = level_old;
+ }
goto set_level;
}
@@ -831,15 +779,6 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device)
if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle, "_DDC", &h_dummy1))) {
device->cap._DDC = 1;
}
- if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle, "_DCS", &h_dummy1))) {
- device->cap._DCS = 1;
- }
- if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle, "_DGS", &h_dummy1))) {
- device->cap._DGS = 1;
- }
- if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle, "_DSS", &h_dummy1))) {
- device->cap._DSS = 1;
- }
if (acpi_video_backlight_support()) {
struct backlight_properties props;
@@ -904,21 +843,6 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device)
printk(KERN_ERR PREFIX "Create sysfs link\n");
}
-
- if (acpi_video_display_switch_support()) {
-
- if (device->cap._DCS && device->cap._DSS) {
- static int count;
- char *name;
- name = kasprintf(GFP_KERNEL, "acpi_video%d", count);
- if (!name)
- return;
- count++;
- device->output_dev = video_output_register(name,
- NULL, device, &acpi_output_properties);
- kfree(name);
- }
- }
}
/*
@@ -1360,6 +1284,9 @@ int acpi_video_get_edid(struct acpi_device *device, int type, int device_id,
if (!video_device)
continue;
+ if (!video_device->cap._DDC)
+ continue;
+
if (type) {
switch (type) {
case ACPI_VIDEO_DISPLAY_CRT:
@@ -1452,7 +1379,6 @@ static int acpi_video_bus_put_one_device(struct acpi_video_device *device)
thermal_cooling_device_unregister(device->cooling_dev);
device->cooling_dev = NULL;
}
- video_output_unregister(device->output_dev);
return 0;
}
diff --git a/drivers/acpi/video_detect.c b/drivers/acpi/video_detect.c
index b836761..42d3d72 100644
--- a/drivers/acpi/video_detect.c
+++ b/drivers/acpi/video_detect.c
@@ -17,15 +17,14 @@
* capabilities the graphics cards plugged in support. The check for general
* video capabilities will be triggered by the first caller of
* acpi_video_get_capabilities(NULL); which will happen when the first
- * backlight (or display output) switching supporting driver calls:
+ * backlight switching supporting driver calls:
* acpi_video_backlight_support();
*
* Depending on whether ACPI graphics extensions (cmp. ACPI spec Appendix B)
* are available, video.ko should be used to handle the device.
*
* Otherwise vendor specific drivers like thinkpad_acpi, asus_acpi,
- * sony_acpi,... can take care about backlight brightness and display output
- * switching.
+ * sony_acpi,... can take care about backlight brightness.
*
* If CONFIG_ACPI_VIDEO is neither set as "compiled in" (y) nor as a module (m)
* this file will not be compiled, acpi_video_get_capabilities() and
@@ -83,11 +82,6 @@ long acpi_is_video_device(struct acpi_device *device)
if (!device)
return 0;
- /* Is this device able to support video switching ? */
- if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOD", &h_dummy)) ||
- ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOS", &h_dummy)))
- video_caps |= ACPI_VIDEO_OUTPUT_SWITCHING;
-
/* Is this device able to retrieve a video ROM ? */
if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_ROM", &h_dummy)))
video_caps |= ACPI_VIDEO_ROM_AVAILABLE;
@@ -161,8 +155,6 @@ long acpi_video_get_capabilities(acpi_handle graphics_handle)
*
* if (dmi_name_in_vendors("XY")) {
* acpi_video_support |=
- * ACPI_VIDEO_OUTPUT_SWITCHING_DMI_VENDOR;
- * acpi_video_support |=
* ACPI_VIDEO_BACKLIGHT_DMI_VENDOR;
*}
*/
@@ -212,33 +204,8 @@ int acpi_video_backlight_support(void)
EXPORT_SYMBOL(acpi_video_backlight_support);
/*
- * Returns true if video.ko can do display output switching.
- * This does not work well/at all with binary graphics drivers
- * which disable system io ranges and do it on their own.
- */
-int acpi_video_display_switch_support(void)
-{
- if (!acpi_video_caps_checked)
- acpi_video_get_capabilities(NULL);
-
- if (acpi_video_support & ACPI_VIDEO_OUTPUT_SWITCHING_FORCE_VENDOR)
- return 0;
- else if (acpi_video_support & ACPI_VIDEO_OUTPUT_SWITCHING_FORCE_VIDEO)
- return 1;
-
- if (acpi_video_support & ACPI_VIDEO_OUTPUT_SWITCHING_DMI_VENDOR)
- return 0;
- else if (acpi_video_support & ACPI_VIDEO_OUTPUT_SWITCHING_DMI_VIDEO)
- return 1;
-
- return acpi_video_support & ACPI_VIDEO_OUTPUT_SWITCHING;
-}
-EXPORT_SYMBOL(acpi_video_display_switch_support);
-
-/*
- * Use acpi_display_output=vendor/video or acpi_backlight=vendor/video
- * To force that backlight or display output switching is processed by vendor
- * specific acpi drivers or video.ko driver.
+ * Use acpi_backlight=vendor/video to force that backlight switching
+ * is processed by vendor specific acpi drivers or video.ko driver.
*/
static int __init acpi_backlight(char *str)
{
@@ -255,19 +222,3 @@ static int __init acpi_backlight(char *str)
return 1;
}
__setup("acpi_backlight=", acpi_backlight);
-
-static int __init acpi_display_output(char *str)
-{
- if (str == NULL || *str == '\0')
- return 1;
- else {
- if (!strcmp("vendor", str))
- acpi_video_support |=
- ACPI_VIDEO_OUTPUT_SWITCHING_FORCE_VENDOR;
- if (!strcmp("video", str))
- acpi_video_support |=
- ACPI_VIDEO_OUTPUT_SWITCHING_FORCE_VIDEO;
- }
- return 1;
-}
-__setup("acpi_display_output=", acpi_display_output);
diff --git a/drivers/acpi/wakeup.c b/drivers/acpi/wakeup.c
index f62a50c..ed65014 100644
--- a/drivers/acpi/wakeup.c
+++ b/drivers/acpi/wakeup.c
@@ -37,15 +37,16 @@ void acpi_enable_wakeup_devices(u8 sleep_state)
container_of(node, struct acpi_device, wakeup_list);
if (!dev->wakeup.flags.valid
- || !(dev->wakeup.state.enabled || dev->wakeup.prepare_count)
- || sleep_state > (u32) dev->wakeup.sleep_state)
+ || sleep_state > (u32) dev->wakeup.sleep_state
+ || !(device_may_wakeup(&dev->dev)
+ || dev->wakeup.prepare_count))
continue;
- if (dev->wakeup.state.enabled)
+ if (device_may_wakeup(&dev->dev))
acpi_enable_wakeup_device_power(dev, sleep_state);
/* The wake-up power should have been enabled already. */
- acpi_gpe_wakeup(dev->wakeup.gpe_device, dev->wakeup.gpe_number,
+ acpi_set_gpe_wake_mask(dev->wakeup.gpe_device, dev->wakeup.gpe_number,
ACPI_GPE_ENABLE);
}
}
@@ -63,14 +64,15 @@ void acpi_disable_wakeup_devices(u8 sleep_state)
container_of(node, struct acpi_device, wakeup_list);
if (!dev->wakeup.flags.valid
- || !(dev->wakeup.state.enabled || dev->wakeup.prepare_count)
- || (sleep_state > (u32) dev->wakeup.sleep_state))
+ || sleep_state > (u32) dev->wakeup.sleep_state
+ || !(device_may_wakeup(&dev->dev)
+ || dev->wakeup.prepare_count))
continue;
- acpi_gpe_wakeup(dev->wakeup.gpe_device, dev->wakeup.gpe_number,
+ acpi_set_gpe_wake_mask(dev->wakeup.gpe_device, dev->wakeup.gpe_number,
ACPI_GPE_DISABLE);
- if (dev->wakeup.state.enabled)
+ if (device_may_wakeup(&dev->dev))
acpi_disable_wakeup_device_power(dev);
}
}
@@ -84,8 +86,8 @@ int __init acpi_wakeup_device_init(void)
struct acpi_device *dev = container_of(node,
struct acpi_device,
wakeup_list);
- if (dev->wakeup.flags.always_enabled)
- dev->wakeup.state.enabled = 1;
+ if (device_can_wakeup(&dev->dev))
+ device_set_wakeup_enable(&dev->dev, true);
}
mutex_unlock(&acpi_device_lock);
return 0;
diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig
index c6b298d..c2328ae 100644
--- a/drivers/ata/Kconfig
+++ b/drivers/ata/Kconfig
@@ -783,7 +783,7 @@ config PATA_PCMCIA
config PATA_PLATFORM
tristate "Generic platform device PATA support"
- depends on EMBEDDED || PPC || HAVE_PATA_PLATFORM
+ depends on EXPERT || PPC || HAVE_PATA_PLATFORM
help
This option enables support for generic directly connected ATA
devices commonly found on embedded systems.
diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig
index fd96345..d57e8d0 100644
--- a/drivers/base/Kconfig
+++ b/drivers/base/Kconfig
@@ -70,7 +70,7 @@ config PREVENT_FIRMWARE_BUILD
If unsure say Y here.
config FW_LOADER
- tristate "Userspace firmware loading support" if EMBEDDED
+ tristate "Userspace firmware loading support" if EXPERT
default y
---help---
This option is provided for the case where no in-kernel-tree modules
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index 0f175a8..b7980a83 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -5,7 +5,7 @@
menu "Character devices"
config VT
- bool "Virtual terminal" if EMBEDDED
+ bool "Virtual terminal" if EXPERT
depends on !S390
select INPUT
default y
@@ -39,13 +39,13 @@ config VT
config CONSOLE_TRANSLATIONS
depends on VT
default y
- bool "Enable character translations in console" if EMBEDDED
+ bool "Enable character translations in console" if EXPERT
---help---
This enables support for font mapping and Unicode translation
on virtual consoles.
config VT_CONSOLE
- bool "Support for console on virtual terminal" if EMBEDDED
+ bool "Support for console on virtual terminal" if EXPERT
depends on VT
default y
---help---
@@ -426,10 +426,10 @@ config SGI_MBCS
If you have an SGI Altix with an attached SABrick
say Y or M here, otherwise say N.
-source "drivers/serial/Kconfig"
+source "drivers/tty/serial/Kconfig"
config UNIX98_PTYS
- bool "Unix98 PTY support" if EMBEDDED
+ bool "Unix98 PTY support" if EXPERT
default y
---help---
A pseudo terminal (PTY) is a software device consisting of two
@@ -495,7 +495,7 @@ config LEGACY_PTY_COUNT
config TTY_PRINTK
bool "TTY driver to output user messages via printk"
- depends on EMBEDDED
+ depends on EXPERT
default n
---help---
If you say Y here, the support for writing user messages (i.e.
diff --git a/drivers/char/Makefile b/drivers/char/Makefile
index 1e9dffb..5bc765d 100644
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -30,25 +30,12 @@ obj-$(CONFIG_SYNCLINK_GT) += synclink_gt.o
obj-$(CONFIG_AMIGA_BUILTIN_SERIAL) += amiserial.o
obj-$(CONFIG_SX) += sx.o generic_serial.o
obj-$(CONFIG_RIO) += rio/ generic_serial.o
-obj-$(CONFIG_HVC_CONSOLE) += hvc_vio.o hvsi.o
-obj-$(CONFIG_HVC_ISERIES) += hvc_iseries.o
-obj-$(CONFIG_HVC_RTAS) += hvc_rtas.o
-obj-$(CONFIG_HVC_TILE) += hvc_tile.o
-obj-$(CONFIG_HVC_DCC) += hvc_dcc.o
-obj-$(CONFIG_HVC_BEAT) += hvc_beat.o
-obj-$(CONFIG_HVC_DRIVER) += hvc_console.o
-obj-$(CONFIG_HVC_IRQ) += hvc_irq.o
-obj-$(CONFIG_HVC_XEN) += hvc_xen.o
-obj-$(CONFIG_HVC_IUCV) += hvc_iucv.o
-obj-$(CONFIG_HVC_UDBG) += hvc_udbg.o
-obj-$(CONFIG_VIRTIO_CONSOLE) += virtio_console.o
obj-$(CONFIG_RAW_DRIVER) += raw.o
obj-$(CONFIG_SGI_SNSC) += snsc.o snsc_event.o
obj-$(CONFIG_MSPEC) += mspec.o
obj-$(CONFIG_MMTIMER) += mmtimer.o
obj-$(CONFIG_UV_MMTIMER) += uv_mmtimer.o
obj-$(CONFIG_VIOTAPE) += viotape.o
-obj-$(CONFIG_HVCS) += hvcs.o
obj-$(CONFIG_IBM_BSR) += bsr.o
obj-$(CONFIG_SGI_MBCS) += mbcs.o
obj-$(CONFIG_BRIQ_PANEL) += briq_panel.o
diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c
index 07e9796..857df10 100644
--- a/drivers/char/agp/intel-agp.c
+++ b/drivers/char/agp/intel-agp.c
@@ -717,8 +717,8 @@ static const struct intel_agp_driver_description {
{ PCI_DEVICE_ID_INTEL_82820_UP_HB, "i820", &intel_820_driver },
{ PCI_DEVICE_ID_INTEL_82830_HB, "830M", &intel_830mp_driver },
{ PCI_DEVICE_ID_INTEL_82840_HB, "i840", &intel_840_driver },
- { PCI_DEVICE_ID_INTEL_82845_HB, "845G", &intel_845_driver },
- { PCI_DEVICE_ID_INTEL_82845G_HB, "830M", &intel_845_driver },
+ { PCI_DEVICE_ID_INTEL_82845_HB, "i845", &intel_845_driver },
+ { PCI_DEVICE_ID_INTEL_82845G_HB, "845G", &intel_845_driver },
{ PCI_DEVICE_ID_INTEL_82850_HB, "i850", &intel_850_driver },
{ PCI_DEVICE_ID_INTEL_82854_HB, "854", &intel_845_driver },
{ PCI_DEVICE_ID_INTEL_82855PM_HB, "855PM", &intel_845_driver },
diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c
index e921b69..fab3d32 100644
--- a/drivers/char/agp/intel-gtt.c
+++ b/drivers/char/agp/intel-gtt.c
@@ -68,6 +68,7 @@ static struct _intel_private {
phys_addr_t gma_bus_addr;
u32 PGETBL_save;
u32 __iomem *gtt; /* I915G */
+ bool clear_fake_agp; /* on first access via agp, fill with scratch */
int num_dcache_entries;
union {
void __iomem *i9xx_flush_page;
@@ -869,21 +870,12 @@ static int intel_fake_agp_free_gatt_table(struct agp_bridge_data *bridge)
static int intel_fake_agp_configure(void)
{
- int i;
-
if (!intel_enable_gtt())
return -EIO;
+ intel_private.clear_fake_agp = true;
agp_bridge->gart_bus_addr = intel_private.gma_bus_addr;
- for (i = 0; i < intel_private.base.gtt_total_entries; i++) {
- intel_private.driver->write_entry(intel_private.scratch_page_dma,
- i, 0);
- }
- readl(intel_private.gtt+i-1); /* PCI Posting. */
-
- global_cache_flush();
-
return 0;
}
@@ -945,6 +937,13 @@ static int intel_fake_agp_insert_entries(struct agp_memory *mem,
{
int ret = -EINVAL;
+ if (intel_private.clear_fake_agp) {
+ int start = intel_private.base.stolen_size / PAGE_SIZE;
+ int end = intel_private.base.gtt_mappable_entries;
+ intel_gtt_clear_range(start, end - start);
+ intel_private.clear_fake_agp = false;
+ }
+
if (INTEL_GTT_GEN == 1 && type == AGP_DCACHE_MEMORY)
return i810_insert_dcache_entries(mem, pg_start, type);
@@ -1361,7 +1360,7 @@ static const struct intel_gtt_driver_description {
&i81x_gtt_driver},
{ PCI_DEVICE_ID_INTEL_82830_CGC, "830M",
&i8xx_gtt_driver},
- { PCI_DEVICE_ID_INTEL_82845G_IG, "830M",
+ { PCI_DEVICE_ID_INTEL_82845G_IG, "845G",
&i8xx_gtt_driver},
{ PCI_DEVICE_ID_INTEL_82854_IG, "854",
&i8xx_gtt_driver},
diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c
index 2fe72f8..38223e9 100644
--- a/drivers/char/ipmi/ipmi_msghandler.c
+++ b/drivers/char/ipmi/ipmi_msghandler.c
@@ -970,6 +970,33 @@ out_kfree:
}
EXPORT_SYMBOL(ipmi_create_user);
+int ipmi_get_smi_info(int if_num, struct ipmi_smi_info *data)
+{
+ int rv = 0;
+ ipmi_smi_t intf;
+ struct ipmi_smi_handlers *handlers;
+
+ mutex_lock(&ipmi_interfaces_mutex);
+ list_for_each_entry_rcu(intf, &ipmi_interfaces, link) {
+ if (intf->intf_num == if_num)
+ goto found;
+ }
+ /* Not found, return an error */
+ rv = -EINVAL;
+ mutex_unlock(&ipmi_interfaces_mutex);
+ return rv;
+
+found:
+ handlers = intf->handlers;
+ rv = -ENOSYS;
+ if (handlers->get_smi_info)
+ rv = handlers->get_smi_info(intf->send_info, data);
+ mutex_unlock(&ipmi_interfaces_mutex);
+
+ return rv;
+}
+EXPORT_SYMBOL(ipmi_get_smi_info);
+
static void free_user(struct kref *ref)
{
ipmi_user_t user = container_of(ref, struct ipmi_user, refcount);
diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c
index f27c04e..b6ae6e9 100644
--- a/drivers/char/ipmi/ipmi_si_intf.c
+++ b/drivers/char/ipmi/ipmi_si_intf.c
@@ -57,6 +57,7 @@
#include <asm/irq.h>
#include <linux/interrupt.h>
#include <linux/rcupdate.h>
+#include <linux/ipmi.h>
#include <linux/ipmi_smi.h>
#include <asm/io.h>
#include "ipmi_si_sm.h"
@@ -109,10 +110,6 @@ enum si_type {
};
static char *si_to_str[] = { "kcs", "smic", "bt" };
-enum ipmi_addr_src {
- SI_INVALID = 0, SI_HOTMOD, SI_HARDCODED, SI_SPMI, SI_ACPI, SI_SMBIOS,
- SI_PCI, SI_DEVICETREE, SI_DEFAULT
-};
static char *ipmi_addr_src_to_str[] = { NULL, "hotmod", "hardcoded", "SPMI",
"ACPI", "SMBIOS", "PCI",
"device-tree", "default" };
@@ -293,6 +290,7 @@ struct smi_info {
struct task_struct *thread;
struct list_head link;
+ union ipmi_smi_info_union addr_info;
};
#define smi_inc_stat(smi, stat) \
@@ -1188,6 +1186,18 @@ static int smi_start_processing(void *send_info,
return 0;
}
+static int get_smi_info(void *send_info, struct ipmi_smi_info *data)
+{
+ struct smi_info *smi = send_info;
+
+ data->addr_src = smi->addr_source;
+ data->dev = smi->dev;
+ data->addr_info = smi->addr_info;
+ get_device(smi->dev);
+
+ return 0;
+}
+
static void set_maintenance_mode(void *send_info, int enable)
{
struct smi_info *smi_info = send_info;
@@ -1199,6 +1209,7 @@ static void set_maintenance_mode(void *send_info, int enable)
static struct ipmi_smi_handlers handlers = {
.owner = THIS_MODULE,
.start_processing = smi_start_processing,
+ .get_smi_info = get_smi_info,
.sender = sender,
.request_events = request_events,
.set_maintenance_mode = set_maintenance_mode,
@@ -1930,7 +1941,8 @@ static void __devinit hardcode_find_bmc(void)
static int acpi_failure;
/* For GPE-type interrupts. */
-static u32 ipmi_acpi_gpe(void *context)
+static u32 ipmi_acpi_gpe(acpi_handle gpe_device,
+ u32 gpe_number, void *context)
{
struct smi_info *smi_info = context;
unsigned long flags;
@@ -2158,6 +2170,7 @@ static int __devinit ipmi_pnp_probe(struct pnp_dev *dev,
printk(KERN_INFO PFX "probing via ACPI\n");
handle = acpi_dev->handle;
+ info->addr_info.acpi_info.acpi_handle = handle;
/* _IFT tells us the interface type: KCS, BT, etc */
status = acpi_evaluate_integer(handle, "_IFT", NULL, &tmp);
diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c
index 1f46f1c..36e0fa1 100644
--- a/drivers/char/tpm/tpm.c
+++ b/drivers/char/tpm/tpm.c
@@ -364,12 +364,14 @@ unsigned long tpm_calc_ordinal_duration(struct tpm_chip *chip,
tpm_protected_ordinal_duration[ordinal &
TPM_PROTECTED_ORDINAL_MASK];
- if (duration_idx != TPM_UNDEFINED)
+ if (duration_idx != TPM_UNDEFINED) {
duration = chip->vendor.duration[duration_idx];
- if (duration <= 0)
+ /* if duration is 0, it's because chip->vendor.duration wasn't */
+ /* filled yet, so we set the lowest timeout just to give enough */
+ /* time for tpm_get_timeouts() to succeed */
+ return (duration <= 0 ? HZ : duration);
+ } else
return 2 * 60 * HZ;
- else
- return duration;
}
EXPORT_SYMBOL_GPL(tpm_calc_ordinal_duration);
diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c
index c17a305..dd21df5 100644
--- a/drivers/char/tpm/tpm_tis.c
+++ b/drivers/char/tpm/tpm_tis.c
@@ -493,9 +493,6 @@ static int tpm_tis_init(struct device *dev, resource_size_t start,
"1.2 TPM (device-id 0x%X, rev-id %d)\n",
vendor >> 16, ioread8(chip->vendor.iobase + TPM_RID(0)));
- if (is_itpm(to_pnp_dev(dev)))
- itpm = 1;
-
if (itpm)
dev_info(dev, "Intel iTPM workaround enabled\n");
@@ -637,6 +634,9 @@ static int __devinit tpm_tis_pnp_init(struct pnp_dev *pnp_dev,
else
interrupts = 0;
+ if (is_itpm(pnp_dev))
+ itpm = 1;
+
return tpm_tis_init(&pnp_dev->dev, start, len, irq);
}
diff --git a/drivers/clocksource/acpi_pm.c b/drivers/clocksource/acpi_pm.c
index cfb0f52..effe797 100644
--- a/drivers/clocksource/acpi_pm.c
+++ b/drivers/clocksource/acpi_pm.c
@@ -202,17 +202,21 @@ static int __init init_acpi_pm_clocksource(void)
printk(KERN_INFO "PM-Timer had inconsistent results:"
" 0x%#llx, 0x%#llx - aborting.\n",
value1, value2);
+ pmtmr_ioport = 0;
return -EINVAL;
}
if (i == ACPI_PM_READ_CHECKS) {
printk(KERN_INFO "PM-Timer failed consistency check "
" (0x%#llx) - aborting.\n", value1);
+ pmtmr_ioport = 0;
return -ENODEV;
}
}
- if (verify_pmtmr_rate() != 0)
+ if (verify_pmtmr_rate() != 0){
+ pmtmr_ioport = 0;
return -ENODEV;
+ }
return clocksource_register_hz(&clocksource_acpi_pm,
PMTMR_TICKS_PER_SEC);
diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig
index a8c8d9c..ca8ee80 100644
--- a/drivers/cpufreq/Kconfig
+++ b/drivers/cpufreq/Kconfig
@@ -71,7 +71,7 @@ config CPU_FREQ_DEFAULT_GOV_PERFORMANCE
config CPU_FREQ_DEFAULT_GOV_POWERSAVE
bool "powersave"
- depends on EMBEDDED
+ depends on EXPERT
select CPU_FREQ_GOV_POWERSAVE
help
Use the CPUFreq governor 'powersave' as default. This sets
diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c
index 386888f..bf50924 100644
--- a/drivers/cpuidle/cpuidle.c
+++ b/drivers/cpuidle/cpuidle.c
@@ -96,7 +96,15 @@ static void cpuidle_idle_call(void)
/* enter the state and update stats */
dev->last_state = target_state;
+
+ trace_power_start(POWER_CSTATE, next_state, dev->cpu);
+ trace_cpu_idle(next_state, dev->cpu);
+
dev->last_residency = target_state->enter(dev, target_state);
+
+ trace_power_end(dev->cpu);
+ trace_cpu_idle(PWR_EVENT_EXIT, dev->cpu);
+
if (dev->last_state)
target_state = dev->last_state;
@@ -106,8 +114,6 @@ static void cpuidle_idle_call(void)
/* give the governor an opportunity to reflect on the outcome */
if (cpuidle_curr_governor->reflect)
cpuidle_curr_governor->reflect(dev);
- trace_power_end(smp_processor_id());
- trace_cpu_idle(PWR_EVENT_EXIT, smp_processor_id());
}
/**
@@ -155,6 +161,45 @@ void cpuidle_resume_and_unlock(void)
EXPORT_SYMBOL_GPL(cpuidle_resume_and_unlock);
+#ifdef CONFIG_ARCH_HAS_CPU_RELAX
+static int poll_idle(struct cpuidle_device *dev, struct cpuidle_state *st)
+{
+ ktime_t t1, t2;
+ s64 diff;
+ int ret;
+
+ t1 = ktime_get();
+ local_irq_enable();
+ while (!need_resched())
+ cpu_relax();
+
+ t2 = ktime_get();
+ diff = ktime_to_us(ktime_sub(t2, t1));
+ if (diff > INT_MAX)
+ diff = INT_MAX;
+
+ ret = (int) diff;
+ return ret;
+}
+
+static void poll_idle_init(struct cpuidle_device *dev)
+{
+ struct cpuidle_state *state = &dev->states[0];
+
+ cpuidle_set_statedata(state, NULL);
+
+ snprintf(state->name, CPUIDLE_NAME_LEN, "POLL");
+ snprintf(state->desc, CPUIDLE_DESC_LEN, "CPUIDLE CORE POLL IDLE");
+ state->exit_latency = 0;
+ state->target_residency = 0;
+ state->power_usage = -1;
+ state->flags = 0;
+ state->enter = poll_idle;
+}
+#else
+static void poll_idle_init(struct cpuidle_device *dev) {}
+#endif /* CONFIG_ARCH_HAS_CPU_RELAX */
+
/**
* cpuidle_enable_device - enables idle PM for a CPU
* @dev: the CPU
@@ -179,6 +224,8 @@ int cpuidle_enable_device(struct cpuidle_device *dev)
return ret;
}
+ poll_idle_init(dev);
+
if ((ret = cpuidle_add_state_sysfs(dev)))
return ret;
@@ -233,45 +280,6 @@ void cpuidle_disable_device(struct cpuidle_device *dev)
EXPORT_SYMBOL_GPL(cpuidle_disable_device);
-#ifdef CONFIG_ARCH_HAS_CPU_RELAX
-static int poll_idle(struct cpuidle_device *dev, struct cpuidle_state *st)
-{
- ktime_t t1, t2;
- s64 diff;
- int ret;
-
- t1 = ktime_get();
- local_irq_enable();
- while (!need_resched())
- cpu_relax();
-
- t2 = ktime_get();
- diff = ktime_to_us(ktime_sub(t2, t1));
- if (diff > INT_MAX)
- diff = INT_MAX;
-
- ret = (int) diff;
- return ret;
-}
-
-static void poll_idle_init(struct cpuidle_device *dev)
-{
- struct cpuidle_state *state = &dev->states[0];
-
- cpuidle_set_statedata(state, NULL);
-
- snprintf(state->name, CPUIDLE_NAME_LEN, "C0");
- snprintf(state->desc, CPUIDLE_DESC_LEN, "CPUIDLE CORE POLL IDLE");
- state->exit_latency = 0;
- state->target_residency = 0;
- state->power_usage = -1;
- state->flags = CPUIDLE_FLAG_POLL;
- state->enter = poll_idle;
-}
-#else
-static void poll_idle_init(struct cpuidle_device *dev) {}
-#endif /* CONFIG_ARCH_HAS_CPU_RELAX */
-
/**
* __cpuidle_register_device - internal register function called before register
* and enable routines
@@ -292,8 +300,6 @@ static int __cpuidle_register_device(struct cpuidle_device *dev)
init_completion(&dev->kobj_unregister);
- poll_idle_init(dev);
-
/*
* cpuidle driver should set the dev->power_specified bit
* before registering the device if the driver provides
diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
index ef13873..1c28816 100644
--- a/drivers/dma/Kconfig
+++ b/drivers/dma/Kconfig
@@ -200,11 +200,16 @@ config PL330_DMA
platform_data for a dma-pl330 device.
config PCH_DMA
- tristate "Topcliff (Intel EG20T) PCH DMA support"
+ tristate "Intel EG20T PCH / OKI SEMICONDUCTOR ML7213 IOH DMA support"
depends on PCI && X86
select DMA_ENGINE
help
- Enable support for the Topcliff (Intel EG20T) PCH DMA engine.
+ Enable support for Intel EG20T PCH DMA engine.
+
+ This driver also can be used for OKI SEMICONDUCTOR ML7213 IOH(Input/
+ Output Hub) which is for IVI(In-Vehicle Infotainment) use.
+ ML7213 is companion chip for Intel Atom E6xx series.
+ ML7213 is completely compatible for Intel EG20T PCH.
config IMX_SDMA
tristate "i.MX SDMA support"
diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c
index b605cc9..297f48b 100644
--- a/drivers/dma/amba-pl08x.c
+++ b/drivers/dma/amba-pl08x.c
@@ -19,14 +19,14 @@
* this program; if not, write to the Free Software Foundation, Inc., 59
* Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
- * The full GNU General Public License is iin this distribution in the
- * file called COPYING.
+ * The full GNU General Public License is in this distribution in the file
+ * called COPYING.
*
* Documentation: ARM DDI 0196G == PL080
- * Documentation: ARM DDI 0218E == PL081
+ * Documentation: ARM DDI 0218E == PL081
*
- * PL080 & PL081 both have 16 sets of DMA signals that can be routed to
- * any channel.
+ * PL080 & PL081 both have 16 sets of DMA signals that can be routed to any
+ * channel.
*
* The PL080 has 8 channels available for simultaneous use, and the PL081
* has only two channels. So on these DMA controllers the number of channels
@@ -53,7 +53,23 @@
*
* ASSUMES default (little) endianness for DMA transfers
*
- * Only DMAC flow control is implemented
+ * The PL08x has two flow control settings:
+ * - DMAC flow control: the transfer size defines the number of transfers
+ * which occur for the current LLI entry, and the DMAC raises TC at the
+ * end of every LLI entry. Observed behaviour shows the DMAC listening
+ * to both the BREQ and SREQ signals (contrary to documented),
+ * transferring data if either is active. The LBREQ and LSREQ signals
+ * are ignored.
+ *
+ * - Peripheral flow control: the transfer size is ignored (and should be
+ * zero). The data is transferred from the current LLI entry, until
+ * after the final transfer signalled by LBREQ or LSREQ. The DMAC
+ * will then move to the next LLI entry.
+ *
+ * Only the former works sanely with scatter lists, so we only implement
+ * the DMAC flow control method. However, peripherals which use the LBREQ
+ * and LSREQ signals (eg, MMCI) are unable to use this mode, which through
+ * these hardware restrictions prevents them from using scatter DMA.
*
* Global TODO:
* - Break out common code from arch/arm/mach-s3c64xx and share
@@ -61,50 +77,39 @@
#include <linux/device.h>
#include <linux/init.h>
#include <linux/module.h>
-#include <linux/pci.h>
#include <linux/interrupt.h>
#include <linux/slab.h>
#include <linux/dmapool.h>
-#include <linux/amba/bus.h>
#include <linux/dmaengine.h>
+#include <linux/amba/bus.h>
#include <linux/amba/pl08x.h>
#include <linux/debugfs.h>
#include <linux/seq_file.h>
#include <asm/hardware/pl080.h>
-#include <asm/dma.h>
-#include <asm/mach/dma.h>
-#include <asm/atomic.h>
-#include <asm/processor.h>
-#include <asm/cacheflush.h>
#define DRIVER_NAME "pl08xdmac"
/**
- * struct vendor_data - vendor-specific config parameters
- * for PL08x derivates
- * @name: the name of this specific variant
+ * struct vendor_data - vendor-specific config parameters for PL08x derivatives
* @channels: the number of channels available in this variant
- * @dualmaster: whether this version supports dual AHB masters
- * or not.
+ * @dualmaster: whether this version supports dual AHB masters or not.
*/
struct vendor_data {
- char *name;
u8 channels;
bool dualmaster;
};
/*
* PL08X private data structures
- * An LLI struct - see pl08x TRM
- * Note that next uses bit[0] as a bus bit,
- * start & end do not - their bus bit info
- * is in cctl
+ * An LLI struct - see PL08x TRM. Note that next uses bit[0] as a bus bit,
+ * start & end do not - their bus bit info is in cctl. Also note that these
+ * are fixed 32-bit quantities.
*/
-struct lli {
- dma_addr_t src;
- dma_addr_t dst;
- dma_addr_t next;
+struct pl08x_lli {
+ u32 src;
+ u32 dst;
+ u32 lli;
u32 cctl;
};
@@ -119,6 +124,8 @@ struct lli {
* @phy_chans: array of data for the physical channels
* @pool: a pool for the LLI descriptors
* @pool_ctr: counter of LLIs in the pool
+ * @lli_buses: bitmask to or in to LLI pointer selecting AHB port for LLI fetches
+ * @mem_buses: set to indicate memory transfers on AHB2.
* @lock: a spinlock for this struct
*/
struct pl08x_driver_data {
@@ -126,11 +133,13 @@ struct pl08x_driver_data {
struct dma_device memcpy;
void __iomem *base;
struct amba_device *adev;
- struct vendor_data *vd;
+ const struct vendor_data *vd;
struct pl08x_platform_data *pd;
struct pl08x_phy_chan *phy_chans;
struct dma_pool *pool;
int pool_ctr;
+ u8 lli_buses;
+ u8 mem_buses;
spinlock_t lock;
};
@@ -152,9 +161,9 @@ struct pl08x_driver_data {
/* Size (bytes) of each LLI buffer allocated for one transfer */
# define PL08X_LLI_TSFR_SIZE 0x2000
-/* Maximimum times we call dma_pool_alloc on this pool without freeing */
+/* Maximum times we call dma_pool_alloc on this pool without freeing */
#define PL08X_MAX_ALLOCS 0x40
-#define MAX_NUM_TSFR_LLIS (PL08X_LLI_TSFR_SIZE/sizeof(struct lli))
+#define MAX_NUM_TSFR_LLIS (PL08X_LLI_TSFR_SIZE/sizeof(struct pl08x_lli))
#define PL08X_ALIGN 8
static inline struct pl08x_dma_chan *to_pl08x_chan(struct dma_chan *chan)
@@ -162,6 +171,11 @@ static inline struct pl08x_dma_chan *to_pl08x_chan(struct dma_chan *chan)
return container_of(chan, struct pl08x_dma_chan, chan);
}
+static inline struct pl08x_txd *to_pl08x_txd(struct dma_async_tx_descriptor *tx)
+{
+ return container_of(tx, struct pl08x_txd, tx);
+}
+
/*
* Physical channel handling
*/
@@ -177,88 +191,47 @@ static int pl08x_phy_channel_busy(struct pl08x_phy_chan *ch)
/*
* Set the initial DMA register values i.e. those for the first LLI
- * The next lli pointer and the configuration interrupt bit have
- * been set when the LLIs were constructed
+ * The next LLI pointer and the configuration interrupt bit have
+ * been set when the LLIs were constructed. Poke them into the hardware
+ * and start the transfer.
*/
-static void pl08x_set_cregs(struct pl08x_driver_data *pl08x,
- struct pl08x_phy_chan *ch)
-{
- /* Wait for channel inactive */
- while (pl08x_phy_channel_busy(ch))
- ;
-
- dev_vdbg(&pl08x->adev->dev,
- "WRITE channel %d: csrc=%08x, cdst=%08x, "
- "cctl=%08x, clli=%08x, ccfg=%08x\n",
- ch->id,
- ch->csrc,
- ch->cdst,
- ch->cctl,
- ch->clli,
- ch->ccfg);
-
- writel(ch->csrc, ch->base + PL080_CH_SRC_ADDR);
- writel(ch->cdst, ch->base + PL080_CH_DST_ADDR);
- writel(ch->clli, ch->base + PL080_CH_LLI);
- writel(ch->cctl, ch->base + PL080_CH_CONTROL);
- writel(ch->ccfg, ch->base + PL080_CH_CONFIG);
-}
-
-static inline void pl08x_config_phychan_for_txd(struct pl08x_dma_chan *plchan)
+static void pl08x_start_txd(struct pl08x_dma_chan *plchan,
+ struct pl08x_txd *txd)
{
- struct pl08x_channel_data *cd = plchan->cd;
+ struct pl08x_driver_data *pl08x = plchan->host;
struct pl08x_phy_chan *phychan = plchan->phychan;
- struct pl08x_txd *txd = plchan->at;
-
- /* Copy the basic control register calculated at transfer config */
- phychan->csrc = txd->csrc;
- phychan->cdst = txd->cdst;
- phychan->clli = txd->clli;
- phychan->cctl = txd->cctl;
-
- /* Assign the signal to the proper control registers */
- phychan->ccfg = cd->ccfg;
- phychan->ccfg &= ~PL080_CONFIG_SRC_SEL_MASK;
- phychan->ccfg &= ~PL080_CONFIG_DST_SEL_MASK;
- /* If it wasn't set from AMBA, ignore it */
- if (txd->direction == DMA_TO_DEVICE)
- /* Select signal as destination */
- phychan->ccfg |=
- (phychan->signal << PL080_CONFIG_DST_SEL_SHIFT);
- else if (txd->direction == DMA_FROM_DEVICE)
- /* Select signal as source */
- phychan->ccfg |=
- (phychan->signal << PL080_CONFIG_SRC_SEL_SHIFT);
- /* Always enable error interrupts */
- phychan->ccfg |= PL080_CONFIG_ERR_IRQ_MASK;
- /* Always enable terminal interrupts */
- phychan->ccfg |= PL080_CONFIG_TC_IRQ_MASK;
-}
-
-/*
- * Enable the DMA channel
- * Assumes all other configuration bits have been set
- * as desired before this code is called
- */
-static void pl08x_enable_phy_chan(struct pl08x_driver_data *pl08x,
- struct pl08x_phy_chan *ch)
-{
+ struct pl08x_lli *lli = &txd->llis_va[0];
u32 val;
- /*
- * Do not access config register until channel shows as disabled
- */
- while (readl(pl08x->base + PL080_EN_CHAN) & (1 << ch->id))
- ;
+ plchan->at = txd;
- /*
- * Do not access config register until channel shows as inactive
- */
- val = readl(ch->base + PL080_CH_CONFIG);
+ /* Wait for channel inactive */
+ while (pl08x_phy_channel_busy(phychan))
+ cpu_relax();
+
+ dev_vdbg(&pl08x->adev->dev,
+ "WRITE channel %d: csrc=0x%08x, cdst=0x%08x, "
+ "clli=0x%08x, cctl=0x%08x, ccfg=0x%08x\n",
+ phychan->id, lli->src, lli->dst, lli->lli, lli->cctl,
+ txd->ccfg);
+
+ writel(lli->src, phychan->base + PL080_CH_SRC_ADDR);
+ writel(lli->dst, phychan->base + PL080_CH_DST_ADDR);
+ writel(lli->lli, phychan->base + PL080_CH_LLI);
+ writel(lli->cctl, phychan->base + PL080_CH_CONTROL);
+ writel(txd->ccfg, phychan->base + PL080_CH_CONFIG);
+
+ /* Enable the DMA channel */
+ /* Do not access config register until channel shows as disabled */
+ while (readl(pl08x->base + PL080_EN_CHAN) & (1 << phychan->id))
+ cpu_relax();
+
+ /* Do not access config register until channel shows as inactive */
+ val = readl(phychan->base + PL080_CH_CONFIG);
while ((val & PL080_CONFIG_ACTIVE) || (val & PL080_CONFIG_ENABLE))
- val = readl(ch->base + PL080_CH_CONFIG);
+ val = readl(phychan->base + PL080_CH_CONFIG);
- writel(val | PL080_CONFIG_ENABLE, ch->base + PL080_CH_CONFIG);
+ writel(val | PL080_CONFIG_ENABLE, phychan->base + PL080_CH_CONFIG);
}
/*
@@ -266,10 +239,8 @@ static void pl08x_enable_phy_chan(struct pl08x_driver_data *pl08x,
*
* Disabling individual channels could lose data.
*
- * Disable the peripheral DMA after disabling the DMAC
- * in order to allow the DMAC FIFO to drain, and
- * hence allow the channel to show inactive
- *
+ * Disable the peripheral DMA after disabling the DMAC in order to allow
+ * the DMAC FIFO to drain, and hence allow the channel to show inactive
*/
static void pl08x_pause_phy_chan(struct pl08x_phy_chan *ch)
{
@@ -282,7 +253,7 @@ static void pl08x_pause_phy_chan(struct pl08x_phy_chan *ch)
/* Wait for channel inactive */
while (pl08x_phy_channel_busy(ch))
- ;
+ cpu_relax();
}
static void pl08x_resume_phy_chan(struct pl08x_phy_chan *ch)
@@ -333,54 +304,56 @@ static inline u32 get_bytes_in_cctl(u32 cctl)
static u32 pl08x_getbytes_chan(struct pl08x_dma_chan *plchan)
{
struct pl08x_phy_chan *ch;
- struct pl08x_txd *txdi = NULL;
struct pl08x_txd *txd;
unsigned long flags;
- u32 bytes = 0;
+ size_t bytes = 0;
spin_lock_irqsave(&plchan->lock, flags);
-
ch = plchan->phychan;
txd = plchan->at;
/*
- * Next follow the LLIs to get the number of pending bytes in the
- * currently active transaction.
+ * Follow the LLIs to get the number of remaining
+ * bytes in the currently active transaction.
*/
if (ch && txd) {
- struct lli *llis_va = txd->llis_va;
- struct lli *llis_bus = (struct lli *) txd->llis_bus;
- u32 clli = readl(ch->base + PL080_CH_LLI);
+ u32 clli = readl(ch->base + PL080_CH_LLI) & ~PL080_LLI_LM_AHB2;
- /* First get the bytes in the current active LLI */
+ /* First get the remaining bytes in the active transfer */
bytes = get_bytes_in_cctl(readl(ch->base + PL080_CH_CONTROL));
if (clli) {
- int i = 0;
+ struct pl08x_lli *llis_va = txd->llis_va;
+ dma_addr_t llis_bus = txd->llis_bus;
+ int index;
+
+ BUG_ON(clli < llis_bus || clli >= llis_bus +
+ sizeof(struct pl08x_lli) * MAX_NUM_TSFR_LLIS);
+
+ /*
+ * Locate the next LLI - as this is an array,
+ * it's simple maths to find.
+ */
+ index = (clli - llis_bus) / sizeof(struct pl08x_lli);
- /* Forward to the LLI pointed to by clli */
- while ((clli != (u32) &(llis_bus[i])) &&
- (i < MAX_NUM_TSFR_LLIS))
- i++;
+ for (; index < MAX_NUM_TSFR_LLIS; index++) {
+ bytes += get_bytes_in_cctl(llis_va[index].cctl);
- while (clli) {
- bytes += get_bytes_in_cctl(llis_va[i].cctl);
/*
- * A clli of 0x00000000 will terminate the
- * LLI list
+ * A LLI pointer of 0 terminates the LLI list
*/
- clli = llis_va[i].next;
- i++;
+ if (!llis_va[index].lli)
+ break;
}
}
}
/* Sum up all queued transactions */
- if (!list_empty(&plchan->desc_list)) {
- list_for_each_entry(txdi, &plchan->desc_list, node) {
+ if (!list_empty(&plchan->pend_list)) {
+ struct pl08x_txd *txdi;
+ list_for_each_entry(txdi, &plchan->pend_list, node) {
bytes += txdi->len;
}
-
}
spin_unlock_irqrestore(&plchan->lock, flags);
@@ -390,6 +363,10 @@ static u32 pl08x_getbytes_chan(struct pl08x_dma_chan *plchan)
/*
* Allocate a physical channel for a virtual channel
+ *
+ * Try to locate a physical channel to be used for this transfer. If all
+ * are taken return NULL and the requester will have to cope by using
+ * some fallback PIO mode or retrying later.
*/
static struct pl08x_phy_chan *
pl08x_get_phy_channel(struct pl08x_driver_data *pl08x,
@@ -399,12 +376,6 @@ pl08x_get_phy_channel(struct pl08x_driver_data *pl08x,
unsigned long flags;
int i;
- /*
- * Try to locate a physical channel to be used for
- * this transfer. If all are taken return NULL and
- * the requester will have to cope by using some fallback
- * PIO mode or retrying later.
- */
for (i = 0; i < pl08x->vd->channels; i++) {
ch = &pl08x->phy_chans[i];
@@ -465,11 +436,11 @@ static inline unsigned int pl08x_get_bytes_for_cctl(unsigned int coded)
}
static inline u32 pl08x_cctl_bits(u32 cctl, u8 srcwidth, u8 dstwidth,
- u32 tsize)
+ size_t tsize)
{
u32 retbits = cctl;
- /* Remove all src, dst and transfersize bits */
+ /* Remove all src, dst and transfer size bits */
retbits &= ~PL080_CONTROL_DWIDTH_MASK;
retbits &= ~PL080_CONTROL_SWIDTH_MASK;
retbits &= ~PL080_CONTROL_TRANSFER_SIZE_MASK;
@@ -509,95 +480,87 @@ static inline u32 pl08x_cctl_bits(u32 cctl, u8 srcwidth, u8 dstwidth,
return retbits;
}
+struct pl08x_lli_build_data {
+ struct pl08x_txd *txd;
+ struct pl08x_driver_data *pl08x;
+ struct pl08x_bus_data srcbus;
+ struct pl08x_bus_data dstbus;
+ size_t remainder;
+};
+
/*
- * Autoselect a master bus to use for the transfer
- * this prefers the destination bus if both available
- * if fixed address on one bus the other will be chosen
+ * Autoselect a master bus to use for the transfer this prefers the
+ * destination bus if both available if fixed address on one bus the
+ * other will be chosen
*/
-void pl08x_choose_master_bus(struct pl08x_bus_data *src_bus,
- struct pl08x_bus_data *dst_bus, struct pl08x_bus_data **mbus,
- struct pl08x_bus_data **sbus, u32 cctl)
+static void pl08x_choose_master_bus(struct pl08x_lli_build_data *bd,
+ struct pl08x_bus_data **mbus, struct pl08x_bus_data **sbus, u32 cctl)
{
if (!(cctl & PL080_CONTROL_DST_INCR)) {
- *mbus = src_bus;
- *sbus = dst_bus;
+ *mbus = &bd->srcbus;
+ *sbus = &bd->dstbus;
} else if (!(cctl & PL080_CONTROL_SRC_INCR)) {
- *mbus = dst_bus;
- *sbus = src_bus;
+ *mbus = &bd->dstbus;
+ *sbus = &bd->srcbus;
} else {
- if (dst_bus->buswidth == 4) {
- *mbus = dst_bus;
- *sbus = src_bus;
- } else if (src_bus->buswidth == 4) {
- *mbus = src_bus;
- *sbus = dst_bus;
- } else if (dst_bus->buswidth == 2) {
- *mbus = dst_bus;
- *sbus = src_bus;
- } else if (src_bus->buswidth == 2) {
- *mbus = src_bus;
- *sbus = dst_bus;
+ if (bd->dstbus.buswidth == 4) {
+ *mbus = &bd->dstbus;
+ *sbus = &bd->srcbus;
+ } else if (bd->srcbus.buswidth == 4) {
+ *mbus = &bd->srcbus;
+ *sbus = &bd->dstbus;
+ } else if (bd->dstbus.buswidth == 2) {
+ *mbus = &bd->dstbus;
+ *sbus = &bd->srcbus;
+ } else if (bd->srcbus.buswidth == 2) {
+ *mbus = &bd->srcbus;
+ *sbus = &bd->dstbus;
} else {
- /* src_bus->buswidth == 1 */
- *mbus = dst_bus;
- *sbus = src_bus;
+ /* bd->srcbus.buswidth == 1 */
+ *mbus = &bd->dstbus;
+ *sbus = &bd->srcbus;
}
}
}
/*
- * Fills in one LLI for a certain transfer descriptor
- * and advance the counter
+ * Fills in one LLI for a certain transfer descriptor and advance the counter
*/
-int pl08x_fill_lli_for_desc(struct pl08x_driver_data *pl08x,
- struct pl08x_txd *txd, int num_llis, int len,
- u32 cctl, u32 *remainder)
+static void pl08x_fill_lli_for_desc(struct pl08x_lli_build_data *bd,
+ int num_llis, int len, u32 cctl)
{
- struct lli *llis_va = txd->llis_va;
- struct lli *llis_bus = (struct lli *) txd->llis_bus;
+ struct pl08x_lli *llis_va = bd->txd->llis_va;
+ dma_addr_t llis_bus = bd->txd->llis_bus;
BUG_ON(num_llis >= MAX_NUM_TSFR_LLIS);
- llis_va[num_llis].cctl = cctl;
- llis_va[num_llis].src = txd->srcbus.addr;
- llis_va[num_llis].dst = txd->dstbus.addr;
-
- /*
- * On versions with dual masters, you can optionally AND on
- * PL080_LLI_LM_AHB2 to the LLI to tell the hardware to read
- * in new LLIs with that controller, but we always try to
- * choose AHB1 to point into memory. The idea is to have AHB2
- * fixed on the peripheral and AHB1 messing around in the
- * memory. So we don't manipulate this bit currently.
- */
-
- llis_va[num_llis].next =
- (dma_addr_t)((u32) &(llis_bus[num_llis + 1]));
+ llis_va[num_llis].cctl = cctl;
+ llis_va[num_llis].src = bd->srcbus.addr;
+ llis_va[num_llis].dst = bd->dstbus.addr;
+ llis_va[num_llis].lli = llis_bus + (num_llis + 1) * sizeof(struct pl08x_lli);
+ if (bd->pl08x->lli_buses & PL08X_AHB2)
+ llis_va[num_llis].lli |= PL080_LLI_LM_AHB2;
if (cctl & PL080_CONTROL_SRC_INCR)
- txd->srcbus.addr += len;
+ bd->srcbus.addr += len;
if (cctl & PL080_CONTROL_DST_INCR)
- txd->dstbus.addr += len;
+ bd->dstbus.addr += len;
- *remainder -= len;
+ BUG_ON(bd->remainder < len);
- return num_llis + 1;
+ bd->remainder -= len;
}
/*
- * Return number of bytes to fill to boundary, or len
+ * Return number of bytes to fill to boundary, or len.
+ * This calculation works for any value of addr.
*/
-static inline u32 pl08x_pre_boundary(u32 addr, u32 len)
+static inline size_t pl08x_pre_boundary(u32 addr, size_t len)
{
- u32 boundary;
-
- boundary = ((addr >> PL08X_BOUNDARY_SHIFT) + 1)
- << PL08X_BOUNDARY_SHIFT;
+ size_t boundary_len = PL08X_BOUNDARY_SIZE -
+ (addr & (PL08X_BOUNDARY_SIZE - 1));
- if (boundary < addr + len)
- return boundary - addr;
- else
- return len;
+ return min(boundary_len, len);
}
/*
@@ -608,20 +571,13 @@ static inline u32 pl08x_pre_boundary(u32 addr, u32 len)
static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x,
struct pl08x_txd *txd)
{
- struct pl08x_channel_data *cd = txd->cd;
struct pl08x_bus_data *mbus, *sbus;
- u32 remainder;
+ struct pl08x_lli_build_data bd;
int num_llis = 0;
u32 cctl;
- int max_bytes_per_lli;
- int total_bytes = 0;
- struct lli *llis_va;
- struct lli *llis_bus;
-
- if (!txd) {
- dev_err(&pl08x->adev->dev, "%s no descriptor\n", __func__);
- return 0;
- }
+ size_t max_bytes_per_lli;
+ size_t total_bytes = 0;
+ struct pl08x_lli *llis_va;
txd->llis_va = dma_pool_alloc(pl08x->pool, GFP_NOWAIT,
&txd->llis_bus);
@@ -632,121 +588,79 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x,
pl08x->pool_ctr++;
- /*
- * Initialize bus values for this transfer
- * from the passed optimal values
- */
- if (!cd) {
- dev_err(&pl08x->adev->dev, "%s no channel data\n", __func__);
- return 0;
- }
+ /* Get the default CCTL */
+ cctl = txd->cctl;
- /* Get the default CCTL from the platform data */
- cctl = cd->cctl;
-
- /*
- * On the PL080 we have two bus masters and we
- * should select one for source and one for
- * destination. We try to use AHB2 for the
- * bus which does not increment (typically the
- * peripheral) else we just choose something.
- */
- cctl &= ~(PL080_CONTROL_DST_AHB2 | PL080_CONTROL_SRC_AHB2);
- if (pl08x->vd->dualmaster) {
- if (cctl & PL080_CONTROL_SRC_INCR)
- /* Source increments, use AHB2 for destination */
- cctl |= PL080_CONTROL_DST_AHB2;
- else if (cctl & PL080_CONTROL_DST_INCR)
- /* Destination increments, use AHB2 for source */
- cctl |= PL080_CONTROL_SRC_AHB2;
- else
- /* Just pick something, source AHB1 dest AHB2 */
- cctl |= PL080_CONTROL_DST_AHB2;
- }
+ bd.txd = txd;
+ bd.pl08x = pl08x;
+ bd.srcbus.addr = txd->src_addr;
+ bd.dstbus.addr = txd->dst_addr;
/* Find maximum width of the source bus */
- txd->srcbus.maxwidth =
+ bd.srcbus.maxwidth =
pl08x_get_bytes_for_cctl((cctl & PL080_CONTROL_SWIDTH_MASK) >>
PL080_CONTROL_SWIDTH_SHIFT);
/* Find maximum width of the destination bus */
- txd->dstbus.maxwidth =
+ bd.dstbus.maxwidth =
pl08x_get_bytes_for_cctl((cctl & PL080_CONTROL_DWIDTH_MASK) >>
PL080_CONTROL_DWIDTH_SHIFT);
/* Set up the bus widths to the maximum */
- txd->srcbus.buswidth = txd->srcbus.maxwidth;
- txd->dstbus.buswidth = txd->dstbus.maxwidth;
+ bd.srcbus.buswidth = bd.srcbus.maxwidth;
+ bd.dstbus.buswidth = bd.dstbus.maxwidth;
dev_vdbg(&pl08x->adev->dev,
"%s source bus is %d bytes wide, dest bus is %d bytes wide\n",
- __func__, txd->srcbus.buswidth, txd->dstbus.buswidth);
+ __func__, bd.srcbus.buswidth, bd.dstbus.buswidth);
/*
* Bytes transferred == tsize * MIN(buswidths), not max(buswidths)
*/
- max_bytes_per_lli = min(txd->srcbus.buswidth, txd->dstbus.buswidth) *
+ max_bytes_per_lli = min(bd.srcbus.buswidth, bd.dstbus.buswidth) *
PL080_CONTROL_TRANSFER_SIZE_MASK;
dev_vdbg(&pl08x->adev->dev,
- "%s max bytes per lli = %d\n",
+ "%s max bytes per lli = %zu\n",
__func__, max_bytes_per_lli);
/* We need to count this down to zero */
- remainder = txd->len;
+ bd.remainder = txd->len;
dev_vdbg(&pl08x->adev->dev,
- "%s remainder = %d\n",
- __func__, remainder);
+ "%s remainder = %zu\n",
+ __func__, bd.remainder);
/*
* Choose bus to align to
* - prefers destination bus if both available
* - if fixed address on one bus chooses other
- * - modifies cctl to choose an apropriate master
- */
- pl08x_choose_master_bus(&txd->srcbus, &txd->dstbus,
- &mbus, &sbus, cctl);
-
-
- /*
- * The lowest bit of the LLI register
- * is also used to indicate which master to
- * use for reading the LLIs.
*/
+ pl08x_choose_master_bus(&bd, &mbus, &sbus, cctl);
if (txd->len < mbus->buswidth) {
- /*
- * Less than a bus width available
- * - send as single bytes
- */
- while (remainder) {
+ /* Less than a bus width available - send as single bytes */
+ while (bd.remainder) {
dev_vdbg(&pl08x->adev->dev,
"%s single byte LLIs for a transfer of "
- "less than a bus width (remain %08x)\n",
- __func__, remainder);
+ "less than a bus width (remain 0x%08x)\n",
+ __func__, bd.remainder);
cctl = pl08x_cctl_bits(cctl, 1, 1, 1);
- num_llis =
- pl08x_fill_lli_for_desc(pl08x, txd, num_llis, 1,
- cctl, &remainder);
+ pl08x_fill_lli_for_desc(&bd, num_llis++, 1, cctl);
total_bytes++;
}
} else {
- /*
- * Make one byte LLIs until master bus is aligned
- * - slave will then be aligned also
- */
+ /* Make one byte LLIs until master bus is aligned */
while ((mbus->addr) % (mbus->buswidth)) {
dev_vdbg(&pl08x->adev->dev,
"%s adjustment lli for less than bus width "
- "(remain %08x)\n",
- __func__, remainder);
+ "(remain 0x%08x)\n",
+ __func__, bd.remainder);
cctl = pl08x_cctl_bits(cctl, 1, 1, 1);
- num_llis = pl08x_fill_lli_for_desc
- (pl08x, txd, num_llis, 1, cctl, &remainder);
+ pl08x_fill_lli_for_desc(&bd, num_llis++, 1, cctl);
total_bytes++;
}
/*
- * Master now aligned
+ * Master now aligned
* - if slave is not then we must set its width down
*/
if (sbus->addr % sbus->buswidth) {
@@ -761,63 +675,51 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x,
* Make largest possible LLIs until less than one bus
* width left
*/
- while (remainder > (mbus->buswidth - 1)) {
- int lli_len, target_len;
- int tsize;
- int odd_bytes;
+ while (bd.remainder > (mbus->buswidth - 1)) {
+ size_t lli_len, target_len, tsize, odd_bytes;
/*
* If enough left try to send max possible,
* otherwise try to send the remainder
*/
- target_len = remainder;
- if (remainder > max_bytes_per_lli)
- target_len = max_bytes_per_lli;
+ target_len = min(bd.remainder, max_bytes_per_lli);
/*
- * Set bus lengths for incrementing busses
- * to number of bytes which fill to next memory
- * boundary
+ * Set bus lengths for incrementing buses to the
+ * number of bytes which fill to next memory boundary,
+ * limiting on the target length calculated above.
*/
if (cctl & PL080_CONTROL_SRC_INCR)
- txd->srcbus.fill_bytes =
- pl08x_pre_boundary(
- txd->srcbus.addr,
- remainder);
+ bd.srcbus.fill_bytes =
+ pl08x_pre_boundary(bd.srcbus.addr,
+ target_len);
else
- txd->srcbus.fill_bytes =
- max_bytes_per_lli;
+ bd.srcbus.fill_bytes = target_len;
if (cctl & PL080_CONTROL_DST_INCR)
- txd->dstbus.fill_bytes =
- pl08x_pre_boundary(
- txd->dstbus.addr,
- remainder);
+ bd.dstbus.fill_bytes =
+ pl08x_pre_boundary(bd.dstbus.addr,
+ target_len);
else
- txd->dstbus.fill_bytes =
- max_bytes_per_lli;
+ bd.dstbus.fill_bytes = target_len;
- /*
- * Find the nearest
- */
- lli_len = min(txd->srcbus.fill_bytes,
- txd->dstbus.fill_bytes);
+ /* Find the nearest */
+ lli_len = min(bd.srcbus.fill_bytes,
+ bd.dstbus.fill_bytes);
- BUG_ON(lli_len > remainder);
+ BUG_ON(lli_len > bd.remainder);
if (lli_len <= 0) {
dev_err(&pl08x->adev->dev,
- "%s lli_len is %d, <= 0\n",
+ "%s lli_len is %zu, <= 0\n",
__func__, lli_len);
return 0;
}
if (lli_len == target_len) {
/*
- * Can send what we wanted
- */
- /*
- * Maintain alignment
+ * Can send what we wanted.
+ * Maintain alignment
*/
lli_len = (lli_len/mbus->buswidth) *
mbus->buswidth;
@@ -825,17 +727,14 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x,
} else {
/*
* So now we know how many bytes to transfer
- * to get to the nearest boundary
- * The next lli will past the boundary
- * - however we may be working to a boundary
- * on the slave bus
- * We need to ensure the master stays aligned
+ * to get to the nearest boundary. The next
+ * LLI will past the boundary. However, we
+ * may be working to a boundary on the slave
+ * bus. We need to ensure the master stays
+ * aligned, and that we are working in
+ * multiples of the bus widths.
*/
odd_bytes = lli_len % mbus->buswidth;
- /*
- * - and that we are working in multiples
- * of the bus widths
- */
lli_len -= odd_bytes;
}
@@ -855,41 +754,38 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x,
if (target_len != lli_len) {
dev_vdbg(&pl08x->adev->dev,
- "%s can't send what we want. Desired %08x, lli of %08x bytes in txd of %08x\n",
+ "%s can't send what we want. Desired 0x%08zx, lli of 0x%08zx bytes in txd of 0x%08zx\n",
__func__, target_len, lli_len, txd->len);
}
cctl = pl08x_cctl_bits(cctl,
- txd->srcbus.buswidth,
- txd->dstbus.buswidth,
+ bd.srcbus.buswidth,
+ bd.dstbus.buswidth,
tsize);
dev_vdbg(&pl08x->adev->dev,
- "%s fill lli with single lli chunk of size %08x (remainder %08x)\n",
- __func__, lli_len, remainder);
- num_llis = pl08x_fill_lli_for_desc(pl08x, txd,
- num_llis, lli_len, cctl,
- &remainder);
+ "%s fill lli with single lli chunk of size 0x%08zx (remainder 0x%08zx)\n",
+ __func__, lli_len, bd.remainder);
+ pl08x_fill_lli_for_desc(&bd, num_llis++,
+ lli_len, cctl);
total_bytes += lli_len;
}
if (odd_bytes) {
/*
- * Creep past the boundary,
- * maintaining master alignment
+ * Creep past the boundary, maintaining
+ * master alignment
*/
int j;
for (j = 0; (j < mbus->buswidth)
- && (remainder); j++) {
+ && (bd.remainder); j++) {
cctl = pl08x_cctl_bits(cctl, 1, 1, 1);
dev_vdbg(&pl08x->adev->dev,
- "%s align with boundardy, single byte (remain %08x)\n",
- __func__, remainder);
- num_llis =
- pl08x_fill_lli_for_desc(pl08x,
- txd, num_llis, 1,
- cctl, &remainder);
+ "%s align with boundary, single byte (remain 0x%08zx)\n",
+ __func__, bd.remainder);
+ pl08x_fill_lli_for_desc(&bd,
+ num_llis++, 1, cctl);
total_bytes++;
}
}
@@ -898,25 +794,18 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x,
/*
* Send any odd bytes
*/
- if (remainder < 0) {
- dev_err(&pl08x->adev->dev, "%s remainder not fitted 0x%08x bytes\n",
- __func__, remainder);
- return 0;
- }
-
- while (remainder) {
+ while (bd.remainder) {
cctl = pl08x_cctl_bits(cctl, 1, 1, 1);
dev_vdbg(&pl08x->adev->dev,
- "%s align with boundardy, single odd byte (remain %d)\n",
- __func__, remainder);
- num_llis = pl08x_fill_lli_for_desc(pl08x, txd, num_llis,
- 1, cctl, &remainder);
+ "%s align with boundary, single odd byte (remain %zu)\n",
+ __func__, bd.remainder);
+ pl08x_fill_lli_for_desc(&bd, num_llis++, 1, cctl);
total_bytes++;
}
}
if (total_bytes != txd->len) {
dev_err(&pl08x->adev->dev,
- "%s size of encoded lli:s don't match total txd, transferred 0x%08x from size 0x%08x\n",
+ "%s size of encoded lli:s don't match total txd, transferred 0x%08zx from size 0x%08zx\n",
__func__, total_bytes, txd->len);
return 0;
}
@@ -927,41 +816,12 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x,
__func__, (u32) MAX_NUM_TSFR_LLIS);
return 0;
}
- /*
- * Decide whether this is a loop or a terminated transfer
- */
- llis_va = txd->llis_va;
- llis_bus = (struct lli *) txd->llis_bus;
- if (cd->circular_buffer) {
- /*
- * Loop the circular buffer so that the next element
- * points back to the beginning of the LLI.
- */
- llis_va[num_llis - 1].next =
- (dma_addr_t)((unsigned int)&(llis_bus[0]));
- } else {
- /*
- * On non-circular buffers, the final LLI terminates
- * the LLI.
- */
- llis_va[num_llis - 1].next = 0;
- /*
- * The final LLI element shall also fire an interrupt
- */
- llis_va[num_llis - 1].cctl |= PL080_CONTROL_TC_IRQ_EN;
- }
-
- /* Now store the channel register values */
- txd->csrc = llis_va[0].src;
- txd->cdst = llis_va[0].dst;
- if (num_llis > 1)
- txd->clli = llis_va[0].next;
- else
- txd->clli = 0;
-
- txd->cctl = llis_va[0].cctl;
- /* ccfg will be set at physical channel allocation time */
+ llis_va = txd->llis_va;
+ /* The final LLI terminates the LLI. */
+ llis_va[num_llis - 1].lli = 0;
+ /* The final LLI element shall also fire an interrupt. */
+ llis_va[num_llis - 1].cctl |= PL080_CONTROL_TC_IRQ_EN;
#ifdef VERBOSE_DEBUG
{
@@ -969,13 +829,13 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x,
for (i = 0; i < num_llis; i++) {
dev_vdbg(&pl08x->adev->dev,
- "lli %d @%p: csrc=%08x, cdst=%08x, cctl=%08x, clli=%08x\n",
+ "lli %d @%p: csrc=0x%08x, cdst=0x%08x, cctl=0x%08x, clli=0x%08x\n",
i,
&llis_va[i],
llis_va[i].src,
llis_va[i].dst,
llis_va[i].cctl,
- llis_va[i].next
+ llis_va[i].lli
);
}
}
@@ -988,14 +848,8 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x,
static void pl08x_free_txd(struct pl08x_driver_data *pl08x,
struct pl08x_txd *txd)
{
- if (!txd)
- dev_err(&pl08x->adev->dev,
- "%s no descriptor to free\n",
- __func__);
-
/* Free the LLI */
- dma_pool_free(pl08x->pool, txd->llis_va,
- txd->llis_bus);
+ dma_pool_free(pl08x->pool, txd->llis_va, txd->llis_bus);
pl08x->pool_ctr--;
@@ -1008,13 +862,12 @@ static void pl08x_free_txd_list(struct pl08x_driver_data *pl08x,
struct pl08x_txd *txdi = NULL;
struct pl08x_txd *next;
- if (!list_empty(&plchan->desc_list)) {
+ if (!list_empty(&plchan->pend_list)) {
list_for_each_entry_safe(txdi,
- next, &plchan->desc_list, node) {
+ next, &plchan->pend_list, node) {
list_del(&txdi->node);
pl08x_free_txd(pl08x, txdi);
}
-
}
}
@@ -1069,6 +922,12 @@ static int prep_phy_channel(struct pl08x_dma_chan *plchan,
return -EBUSY;
}
ch->signal = ret;
+
+ /* Assign the flow control signal to this channel */
+ if (txd->direction == DMA_TO_DEVICE)
+ txd->ccfg |= ch->signal << PL080_CONFIG_DST_SEL_SHIFT;
+ else if (txd->direction == DMA_FROM_DEVICE)
+ txd->ccfg |= ch->signal << PL080_CONFIG_SRC_SEL_SHIFT;
}
dev_dbg(&pl08x->adev->dev, "allocated physical channel %d and signal %d for xfer on %s\n",
@@ -1076,19 +935,54 @@ static int prep_phy_channel(struct pl08x_dma_chan *plchan,
ch->signal,
plchan->name);
+ plchan->phychan_hold++;
plchan->phychan = ch;
return 0;
}
+static void release_phy_channel(struct pl08x_dma_chan *plchan)
+{
+ struct pl08x_driver_data *pl08x = plchan->host;
+
+ if ((plchan->phychan->signal >= 0) && pl08x->pd->put_signal) {
+ pl08x->pd->put_signal(plchan);
+ plchan->phychan->signal = -1;
+ }
+ pl08x_put_phy_channel(pl08x, plchan->phychan);
+ plchan->phychan = NULL;
+}
+
static dma_cookie_t pl08x_tx_submit(struct dma_async_tx_descriptor *tx)
{
struct pl08x_dma_chan *plchan = to_pl08x_chan(tx->chan);
+ struct pl08x_txd *txd = to_pl08x_txd(tx);
+ unsigned long flags;
- atomic_inc(&plchan->last_issued);
- tx->cookie = atomic_read(&plchan->last_issued);
- /* This unlock follows the lock in the prep() function */
- spin_unlock_irqrestore(&plchan->lock, plchan->lockflags);
+ spin_lock_irqsave(&plchan->lock, flags);
+
+ plchan->chan.cookie += 1;
+ if (plchan->chan.cookie < 0)
+ plchan->chan.cookie = 1;
+ tx->cookie = plchan->chan.cookie;
+
+ /* Put this onto the pending list */
+ list_add_tail(&txd->node, &plchan->pend_list);
+
+ /*
+ * If there was no physical channel available for this memcpy,
+ * stack the request up and indicate that the channel is waiting
+ * for a free physical channel.
+ */
+ if (!plchan->slave && !plchan->phychan) {
+ /* Do this memcpy whenever there is a channel ready */
+ plchan->state = PL08X_CHAN_WAITING;
+ plchan->waiting = txd;
+ } else {
+ plchan->phychan_hold--;
+ }
+
+ spin_unlock_irqrestore(&plchan->lock, flags);
return tx->cookie;
}
@@ -1102,10 +996,9 @@ static struct dma_async_tx_descriptor *pl08x_prep_dma_interrupt(
}
/*
- * Code accessing dma_async_is_complete() in a tight loop
- * may give problems - could schedule where indicated.
- * If slaves are relying on interrupts to signal completion this
- * function must not be called with interrupts disabled
+ * Code accessing dma_async_is_complete() in a tight loop may give problems.
+ * If slaves are relying on interrupts to signal completion this function
+ * must not be called with interrupts disabled.
*/
static enum dma_status
pl08x_dma_tx_status(struct dma_chan *chan,
@@ -1118,7 +1011,7 @@ pl08x_dma_tx_status(struct dma_chan *chan,
enum dma_status ret;
u32 bytesleft = 0;
- last_used = atomic_read(&plchan->last_issued);
+ last_used = plchan->chan.cookie;
last_complete = plchan->lc;
ret = dma_async_is_complete(cookie, last_complete, last_used);
@@ -1128,13 +1021,9 @@ pl08x_dma_tx_status(struct dma_chan *chan,
}
/*
- * schedule(); could be inserted here
- */
-
- /*
* This cookie not complete yet
*/
- last_used = atomic_read(&plchan->last_issued);
+ last_used = plchan->chan.cookie;
last_complete = plchan->lc;
/* Get number of bytes left in the active transactions and queue */
@@ -1199,37 +1088,35 @@ static const struct burst_table burst_sizes[] = {
},
};
-static void dma_set_runtime_config(struct dma_chan *chan,
- struct dma_slave_config *config)
+static int dma_set_runtime_config(struct dma_chan *chan,
+ struct dma_slave_config *config)
{
struct pl08x_dma_chan *plchan = to_pl08x_chan(chan);
struct pl08x_driver_data *pl08x = plchan->host;
struct pl08x_channel_data *cd = plchan->cd;
enum dma_slave_buswidth addr_width;
+ dma_addr_t addr;
u32 maxburst;
u32 cctl = 0;
- /* Mask out all except src and dst channel */
- u32 ccfg = cd->ccfg & 0x000003DEU;
- int i = 0;
+ int i;
+
+ if (!plchan->slave)
+ return -EINVAL;
/* Transfer direction */
plchan->runtime_direction = config->direction;
if (config->direction == DMA_TO_DEVICE) {
- plchan->runtime_addr = config->dst_addr;
- cctl |= PL080_CONTROL_SRC_INCR;
- ccfg |= PL080_FLOW_MEM2PER << PL080_CONFIG_FLOW_CONTROL_SHIFT;
+ addr = config->dst_addr;
addr_width = config->dst_addr_width;
maxburst = config->dst_maxburst;
} else if (config->direction == DMA_FROM_DEVICE) {
- plchan->runtime_addr = config->src_addr;
- cctl |= PL080_CONTROL_DST_INCR;
- ccfg |= PL080_FLOW_PER2MEM << PL080_CONFIG_FLOW_CONTROL_SHIFT;
+ addr = config->src_addr;
addr_width = config->src_addr_width;
maxburst = config->src_maxburst;
} else {
dev_err(&pl08x->adev->dev,
"bad runtime_config: alien transfer direction\n");
- return;
+ return -EINVAL;
}
switch (addr_width) {
@@ -1248,42 +1135,40 @@ static void dma_set_runtime_config(struct dma_chan *chan,
default:
dev_err(&pl08x->adev->dev,
"bad runtime_config: alien address width\n");
- return;
+ return -EINVAL;
}
/*
* Now decide on a maxburst:
- * If this channel will only request single transfers, set
- * this down to ONE element.
+ * If this channel will only request single transfers, set this
+ * down to ONE element. Also select one element if no maxburst
+ * is specified.
*/
- if (plchan->cd->single) {
+ if (plchan->cd->single || maxburst == 0) {
cctl |= (PL080_BSIZE_1 << PL080_CONTROL_SB_SIZE_SHIFT) |
(PL080_BSIZE_1 << PL080_CONTROL_DB_SIZE_SHIFT);
} else {
- while (i < ARRAY_SIZE(burst_sizes)) {
+ for (i = 0; i < ARRAY_SIZE(burst_sizes); i++)
if (burst_sizes[i].burstwords <= maxburst)
break;
- i++;
- }
cctl |= burst_sizes[i].reg;
}
- /* Access the cell in privileged mode, non-bufferable, non-cacheable */
- cctl &= ~PL080_CONTROL_PROT_MASK;
- cctl |= PL080_CONTROL_PROT_SYS;
+ plchan->runtime_addr = addr;
/* Modify the default channel data to fit PrimeCell request */
cd->cctl = cctl;
- cd->ccfg = ccfg;
dev_dbg(&pl08x->adev->dev,
"configured channel %s (%s) for %s, data width %d, "
- "maxburst %d words, LE, CCTL=%08x, CCFG=%08x\n",
+ "maxburst %d words, LE, CCTL=0x%08x\n",
dma_chan_name(chan), plchan->name,
(config->direction == DMA_FROM_DEVICE) ? "RX" : "TX",
addr_width,
maxburst,
- cctl, ccfg);
+ cctl);
+
+ return 0;
}
/*
@@ -1293,35 +1178,26 @@ static void dma_set_runtime_config(struct dma_chan *chan,
static void pl08x_issue_pending(struct dma_chan *chan)
{
struct pl08x_dma_chan *plchan = to_pl08x_chan(chan);
- struct pl08x_driver_data *pl08x = plchan->host;
unsigned long flags;
spin_lock_irqsave(&plchan->lock, flags);
- /* Something is already active */
- if (plchan->at) {
- spin_unlock_irqrestore(&plchan->lock, flags);
- return;
- }
-
- /* Didn't get a physical channel so waiting for it ... */
- if (plchan->state == PL08X_CHAN_WAITING)
+ /* Something is already active, or we're waiting for a channel... */
+ if (plchan->at || plchan->state == PL08X_CHAN_WAITING) {
+ spin_unlock_irqrestore(&plchan->lock, flags);
return;
+ }
/* Take the first element in the queue and execute it */
- if (!list_empty(&plchan->desc_list)) {
+ if (!list_empty(&plchan->pend_list)) {
struct pl08x_txd *next;
- next = list_first_entry(&plchan->desc_list,
+ next = list_first_entry(&plchan->pend_list,
struct pl08x_txd,
node);
list_del(&next->node);
- plchan->at = next;
plchan->state = PL08X_CHAN_RUNNING;
- /* Configure the physical channel for the active txd */
- pl08x_config_phychan_for_txd(plchan);
- pl08x_set_cregs(pl08x, plchan->phychan);
- pl08x_enable_phy_chan(pl08x, plchan->phychan);
+ pl08x_start_txd(plchan, next);
}
spin_unlock_irqrestore(&plchan->lock, flags);
@@ -1330,30 +1206,17 @@ static void pl08x_issue_pending(struct dma_chan *chan)
static int pl08x_prep_channel_resources(struct pl08x_dma_chan *plchan,
struct pl08x_txd *txd)
{
- int num_llis;
struct pl08x_driver_data *pl08x = plchan->host;
- int ret;
+ unsigned long flags;
+ int num_llis, ret;
num_llis = pl08x_fill_llis_for_desc(pl08x, txd);
-
- if (!num_llis)
+ if (!num_llis) {
+ kfree(txd);
return -EINVAL;
+ }
- spin_lock_irqsave(&plchan->lock, plchan->lockflags);
-
- /*
- * If this device is not using a circular buffer then
- * queue this new descriptor for transfer.
- * The descriptor for a circular buffer continues
- * to be used until the channel is freed.
- */
- if (txd->cd->circular_buffer)
- dev_err(&pl08x->adev->dev,
- "%s attempting to queue a circular buffer\n",
- __func__);
- else
- list_add_tail(&txd->node,
- &plchan->desc_list);
+ spin_lock_irqsave(&plchan->lock, flags);
/*
* See if we already have a physical channel allocated,
@@ -1362,45 +1225,74 @@ static int pl08x_prep_channel_resources(struct pl08x_dma_chan *plchan,
ret = prep_phy_channel(plchan, txd);
if (ret) {
/*
- * No physical channel available, we will
- * stack up the memcpy channels until there is a channel
- * available to handle it whereas slave transfers may
- * have been denied due to platform channel muxing restrictions
- * and since there is no guarantee that this will ever be
- * resolved, and since the signal must be aquired AFTER
- * aquiring the physical channel, we will let them be NACK:ed
- * with -EBUSY here. The drivers can alway retry the prep()
- * call if they are eager on doing this using DMA.
+ * No physical channel was available.
+ *
+ * memcpy transfers can be sorted out at submission time.
+ *
+ * Slave transfers may have been denied due to platform
+ * channel muxing restrictions. Since there is no guarantee
+ * that this will ever be resolved, and the signal must be
+ * acquired AFTER acquiring the physical channel, we will let
+ * them be NACK:ed with -EBUSY here. The drivers can retry
+ * the prep() call if they are eager on doing this using DMA.
*/
if (plchan->slave) {
pl08x_free_txd_list(pl08x, plchan);
- spin_unlock_irqrestore(&plchan->lock, plchan->lockflags);
+ pl08x_free_txd(pl08x, txd);
+ spin_unlock_irqrestore(&plchan->lock, flags);
return -EBUSY;
}
- /* Do this memcpy whenever there is a channel ready */
- plchan->state = PL08X_CHAN_WAITING;
- plchan->waiting = txd;
} else
/*
- * Else we're all set, paused and ready to roll,
- * status will switch to PL08X_CHAN_RUNNING when
- * we call issue_pending(). If there is something
- * running on the channel already we don't change
- * its state.
+ * Else we're all set, paused and ready to roll, status
+ * will switch to PL08X_CHAN_RUNNING when we call
+ * issue_pending(). If there is something running on the
+ * channel already we don't change its state.
*/
if (plchan->state == PL08X_CHAN_IDLE)
plchan->state = PL08X_CHAN_PAUSED;
- /*
- * Notice that we leave plchan->lock locked on purpose:
- * it will be unlocked in the subsequent tx_submit()
- * call. This is a consequence of the current API.
- */
+ spin_unlock_irqrestore(&plchan->lock, flags);
return 0;
}
/*
+ * Given the source and destination available bus masks, select which
+ * will be routed to each port. We try to have source and destination
+ * on separate ports, but always respect the allowable settings.
+ */
+static u32 pl08x_select_bus(struct pl08x_driver_data *pl08x, u8 src, u8 dst)
+{
+ u32 cctl = 0;
+
+ if (!(dst & PL08X_AHB1) || ((dst & PL08X_AHB2) && (src & PL08X_AHB1)))
+ cctl |= PL080_CONTROL_DST_AHB2;
+ if (!(src & PL08X_AHB1) || ((src & PL08X_AHB2) && !(dst & PL08X_AHB2)))
+ cctl |= PL080_CONTROL_SRC_AHB2;
+
+ return cctl;
+}
+
+static struct pl08x_txd *pl08x_get_txd(struct pl08x_dma_chan *plchan,
+ unsigned long flags)
+{
+ struct pl08x_txd *txd = kzalloc(sizeof(struct pl08x_txd), GFP_NOWAIT);
+
+ if (txd) {
+ dma_async_tx_descriptor_init(&txd->tx, &plchan->chan);
+ txd->tx.flags = flags;
+ txd->tx.tx_submit = pl08x_tx_submit;
+ INIT_LIST_HEAD(&txd->node);
+
+ /* Always enable error and terminal interrupts */
+ txd->ccfg = PL080_CONFIG_ERR_IRQ_MASK |
+ PL080_CONFIG_TC_IRQ_MASK;
+ }
+ return txd;
+}
+
+/*
* Initialize a descriptor to be used by memcpy submit
*/
static struct dma_async_tx_descriptor *pl08x_prep_dma_memcpy(
@@ -1412,40 +1304,38 @@ static struct dma_async_tx_descriptor *pl08x_prep_dma_memcpy(
struct pl08x_txd *txd;
int ret;
- txd = kzalloc(sizeof(struct pl08x_txd), GFP_NOWAIT);
+ txd = pl08x_get_txd(plchan, flags);
if (!txd) {
dev_err(&pl08x->adev->dev,
"%s no memory for descriptor\n", __func__);
return NULL;
}
- dma_async_tx_descriptor_init(&txd->tx, chan);
txd->direction = DMA_NONE;
- txd->srcbus.addr = src;
- txd->dstbus.addr = dest;
+ txd->src_addr = src;
+ txd->dst_addr = dest;
+ txd->len = len;
/* Set platform data for m2m */
- txd->cd = &pl08x->pd->memcpy_channel;
+ txd->ccfg |= PL080_FLOW_MEM2MEM << PL080_CONFIG_FLOW_CONTROL_SHIFT;
+ txd->cctl = pl08x->pd->memcpy_channel.cctl &
+ ~(PL080_CONTROL_DST_AHB2 | PL080_CONTROL_SRC_AHB2);
+
/* Both to be incremented or the code will break */
- txd->cd->cctl |= PL080_CONTROL_SRC_INCR | PL080_CONTROL_DST_INCR;
- txd->tx.tx_submit = pl08x_tx_submit;
- txd->tx.callback = NULL;
- txd->tx.callback_param = NULL;
- txd->len = len;
+ txd->cctl |= PL080_CONTROL_SRC_INCR | PL080_CONTROL_DST_INCR;
+
+ if (pl08x->vd->dualmaster)
+ txd->cctl |= pl08x_select_bus(pl08x,
+ pl08x->mem_buses, pl08x->mem_buses);
- INIT_LIST_HEAD(&txd->node);
ret = pl08x_prep_channel_resources(plchan, txd);
if (ret)
return NULL;
- /*
- * NB: the channel lock is held at this point so tx_submit()
- * must be called in direct succession.
- */
return &txd->tx;
}
-struct dma_async_tx_descriptor *pl08x_prep_slave_sg(
+static struct dma_async_tx_descriptor *pl08x_prep_slave_sg(
struct dma_chan *chan, struct scatterlist *sgl,
unsigned int sg_len, enum dma_data_direction direction,
unsigned long flags)
@@ -1453,6 +1343,7 @@ struct dma_async_tx_descriptor *pl08x_prep_slave_sg(
struct pl08x_dma_chan *plchan = to_pl08x_chan(chan);
struct pl08x_driver_data *pl08x = plchan->host;
struct pl08x_txd *txd;
+ u8 src_buses, dst_buses;
int ret;
/*
@@ -1467,14 +1358,12 @@ struct dma_async_tx_descriptor *pl08x_prep_slave_sg(
dev_dbg(&pl08x->adev->dev, "%s prepare transaction of %d bytes from %s\n",
__func__, sgl->length, plchan->name);
- txd = kzalloc(sizeof(struct pl08x_txd), GFP_NOWAIT);
+ txd = pl08x_get_txd(plchan, flags);
if (!txd) {
dev_err(&pl08x->adev->dev, "%s no txd\n", __func__);
return NULL;
}
- dma_async_tx_descriptor_init(&txd->tx, chan);
-
if (direction != plchan->runtime_direction)
dev_err(&pl08x->adev->dev, "%s DMA setup does not match "
"the direction configured for the PrimeCell\n",
@@ -1486,37 +1375,47 @@ struct dma_async_tx_descriptor *pl08x_prep_slave_sg(
* channel target address dynamically at runtime.
*/
txd->direction = direction;
+ txd->len = sgl->length;
+
+ txd->cctl = plchan->cd->cctl &
+ ~(PL080_CONTROL_SRC_AHB2 | PL080_CONTROL_DST_AHB2 |
+ PL080_CONTROL_SRC_INCR | PL080_CONTROL_DST_INCR |
+ PL080_CONTROL_PROT_MASK);
+
+ /* Access the cell in privileged mode, non-bufferable, non-cacheable */
+ txd->cctl |= PL080_CONTROL_PROT_SYS;
+
if (direction == DMA_TO_DEVICE) {
- txd->srcbus.addr = sgl->dma_address;
+ txd->ccfg |= PL080_FLOW_MEM2PER << PL080_CONFIG_FLOW_CONTROL_SHIFT;
+ txd->cctl |= PL080_CONTROL_SRC_INCR;
+ txd->src_addr = sgl->dma_address;
if (plchan->runtime_addr)
- txd->dstbus.addr = plchan->runtime_addr;
+ txd->dst_addr = plchan->runtime_addr;
else
- txd->dstbus.addr = plchan->cd->addr;
+ txd->dst_addr = plchan->cd->addr;
+ src_buses = pl08x->mem_buses;
+ dst_buses = plchan->cd->periph_buses;
} else if (direction == DMA_FROM_DEVICE) {
+ txd->ccfg |= PL080_FLOW_PER2MEM << PL080_CONFIG_FLOW_CONTROL_SHIFT;
+ txd->cctl |= PL080_CONTROL_DST_INCR;
if (plchan->runtime_addr)
- txd->srcbus.addr = plchan->runtime_addr;
+ txd->src_addr = plchan->runtime_addr;
else
- txd->srcbus.addr = plchan->cd->addr;
- txd->dstbus.addr = sgl->dma_address;
+ txd->src_addr = plchan->cd->addr;
+ txd->dst_addr = sgl->dma_address;
+ src_buses = plchan->cd->periph_buses;
+ dst_buses = pl08x->mem_buses;
} else {
dev_err(&pl08x->adev->dev,
"%s direction unsupported\n", __func__);
return NULL;
}
- txd->cd = plchan->cd;
- txd->tx.tx_submit = pl08x_tx_submit;
- txd->tx.callback = NULL;
- txd->tx.callback_param = NULL;
- txd->len = sgl->length;
- INIT_LIST_HEAD(&txd->node);
+
+ txd->cctl |= pl08x_select_bus(pl08x, src_buses, dst_buses);
ret = pl08x_prep_channel_resources(plchan, txd);
if (ret)
return NULL;
- /*
- * NB: the channel lock is held at this point so tx_submit()
- * must be called in direct succession.
- */
return &txd->tx;
}
@@ -1531,10 +1430,8 @@ static int pl08x_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
/* Controls applicable to inactive channels */
if (cmd == DMA_SLAVE_CONFIG) {
- dma_set_runtime_config(chan,
- (struct dma_slave_config *)
- arg);
- return 0;
+ return dma_set_runtime_config(chan,
+ (struct dma_slave_config *)arg);
}
/*
@@ -1558,16 +1455,8 @@ static int pl08x_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
* Mark physical channel as free and free any slave
* signal
*/
- if ((plchan->phychan->signal >= 0) &&
- pl08x->pd->put_signal) {
- pl08x->pd->put_signal(plchan);
- plchan->phychan->signal = -1;
- }
- pl08x_put_phy_channel(pl08x, plchan->phychan);
- plchan->phychan = NULL;
+ release_phy_channel(plchan);
}
- /* Stop any pending tasklet */
- tasklet_disable(&plchan->tasklet);
/* Dequeue jobs and free LLIs */
if (plchan->at) {
pl08x_free_txd(pl08x, plchan->at);
@@ -1609,10 +1498,9 @@ bool pl08x_filter_id(struct dma_chan *chan, void *chan_id)
/*
* Just check that the device is there and active
- * TODO: turn this bit on/off depending on the number of
- * physical channels actually used, if it is zero... well
- * shut it off. That will save some power. Cut the clock
- * at the same time.
+ * TODO: turn this bit on/off depending on the number of physical channels
+ * actually used, if it is zero... well shut it off. That will save some
+ * power. Cut the clock at the same time.
*/
static void pl08x_ensure_on(struct pl08x_driver_data *pl08x)
{
@@ -1620,78 +1508,66 @@ static void pl08x_ensure_on(struct pl08x_driver_data *pl08x)
val = readl(pl08x->base + PL080_CONFIG);
val &= ~(PL080_CONFIG_M2_BE | PL080_CONFIG_M1_BE | PL080_CONFIG_ENABLE);
- /* We implictly clear bit 1 and that means little-endian mode */
+ /* We implicitly clear bit 1 and that means little-endian mode */
val |= PL080_CONFIG_ENABLE;
writel(val, pl08x->base + PL080_CONFIG);
}
+static void pl08x_unmap_buffers(struct pl08x_txd *txd)
+{
+ struct device *dev = txd->tx.chan->device->dev;
+
+ if (!(txd->tx.flags & DMA_COMPL_SKIP_SRC_UNMAP)) {
+ if (txd->tx.flags & DMA_COMPL_SRC_UNMAP_SINGLE)
+ dma_unmap_single(dev, txd->src_addr, txd->len,
+ DMA_TO_DEVICE);
+ else
+ dma_unmap_page(dev, txd->src_addr, txd->len,
+ DMA_TO_DEVICE);
+ }
+ if (!(txd->tx.flags & DMA_COMPL_SKIP_DEST_UNMAP)) {
+ if (txd->tx.flags & DMA_COMPL_DEST_UNMAP_SINGLE)
+ dma_unmap_single(dev, txd->dst_addr, txd->len,
+ DMA_FROM_DEVICE);
+ else
+ dma_unmap_page(dev, txd->dst_addr, txd->len,
+ DMA_FROM_DEVICE);
+ }
+}
+
static void pl08x_tasklet(unsigned long data)
{
struct pl08x_dma_chan *plchan = (struct pl08x_dma_chan *) data;
- struct pl08x_phy_chan *phychan = plchan->phychan;
struct pl08x_driver_data *pl08x = plchan->host;
+ struct pl08x_txd *txd;
+ unsigned long flags;
- if (!plchan)
- BUG();
-
- spin_lock(&plchan->lock);
-
- if (plchan->at) {
- dma_async_tx_callback callback =
- plchan->at->tx.callback;
- void *callback_param =
- plchan->at->tx.callback_param;
-
- /*
- * Update last completed
- */
- plchan->lc =
- (plchan->at->tx.cookie);
-
- /*
- * Callback to signal completion
- */
- if (callback)
- callback(callback_param);
+ spin_lock_irqsave(&plchan->lock, flags);
- /*
- * Device callbacks should NOT clear
- * the current transaction on the channel
- * Linus: sometimes they should?
- */
- if (!plchan->at)
- BUG();
+ txd = plchan->at;
+ plchan->at = NULL;
- /*
- * Free the descriptor if it's not for a device
- * using a circular buffer
- */
- if (!plchan->at->cd->circular_buffer) {
- pl08x_free_txd(pl08x, plchan->at);
- plchan->at = NULL;
- }
- /*
- * else descriptor for circular
- * buffers only freed when
- * client has disabled dma
- */
+ if (txd) {
+ /* Update last completed */
+ plchan->lc = txd->tx.cookie;
}
- /*
- * If a new descriptor is queued, set it up
- * plchan->at is NULL here
- */
- if (!list_empty(&plchan->desc_list)) {
+
+ /* If a new descriptor is queued, set it up plchan->at is NULL here */
+ if (!list_empty(&plchan->pend_list)) {
struct pl08x_txd *next;
- next = list_first_entry(&plchan->desc_list,
+ next = list_first_entry(&plchan->pend_list,
struct pl08x_txd,
node);
list_del(&next->node);
- plchan->at = next;
- /* Configure the physical channel for the next txd */
- pl08x_config_phychan_for_txd(plchan);
- pl08x_set_cregs(pl08x, plchan->phychan);
- pl08x_enable_phy_chan(pl08x, plchan->phychan);
+
+ pl08x_start_txd(plchan, next);
+ } else if (plchan->phychan_hold) {
+ /*
+ * This channel is still in use - we have a new txd being
+ * prepared and will soon be queued. Don't give up the
+ * physical channel.
+ */
} else {
struct pl08x_dma_chan *waiting = NULL;
@@ -1699,20 +1575,14 @@ static void pl08x_tasklet(unsigned long data)
* No more jobs, so free up the physical channel
* Free any allocated signal on slave transfers too
*/
- if ((phychan->signal >= 0) && pl08x->pd->put_signal) {
- pl08x->pd->put_signal(plchan);
- phychan->signal = -1;
- }
- pl08x_put_phy_channel(pl08x, phychan);
- plchan->phychan = NULL;
+ release_phy_channel(plchan);
plchan->state = PL08X_CHAN_IDLE;
/*
- * And NOW before anyone else can grab that free:d
- * up physical channel, see if there is some memcpy
- * pending that seriously needs to start because of
- * being stacked up while we were choking the
- * physical channels with data.
+ * And NOW before anyone else can grab that free:d up
+ * physical channel, see if there is some memcpy pending
+ * that seriously needs to start because of being stacked
+ * up while we were choking the physical channels with data.
*/
list_for_each_entry(waiting, &pl08x->memcpy.channels,
chan.device_node) {
@@ -1724,6 +1594,7 @@ static void pl08x_tasklet(unsigned long data)
ret = prep_phy_channel(waiting,
waiting->waiting);
BUG_ON(ret);
+ waiting->phychan_hold--;
waiting->state = PL08X_CHAN_RUNNING;
waiting->waiting = NULL;
pl08x_issue_pending(&waiting->chan);
@@ -1732,7 +1603,25 @@ static void pl08x_tasklet(unsigned long data)
}
}
- spin_unlock(&plchan->lock);
+ spin_unlock_irqrestore(&plchan->lock, flags);
+
+ if (txd) {
+ dma_async_tx_callback callback = txd->tx.callback;
+ void *callback_param = txd->tx.callback_param;
+
+ /* Don't try to unmap buffers on slave channels */
+ if (!plchan->slave)
+ pl08x_unmap_buffers(txd);
+
+ /* Free the descriptor */
+ spin_lock_irqsave(&plchan->lock, flags);
+ pl08x_free_txd(pl08x, txd);
+ spin_unlock_irqrestore(&plchan->lock, flags);
+
+ /* Callback to signal completion */
+ if (callback)
+ callback(callback_param);
+ }
}
static irqreturn_t pl08x_irq(int irq, void *dev)
@@ -1744,9 +1633,7 @@ static irqreturn_t pl08x_irq(int irq, void *dev)
val = readl(pl08x->base + PL080_ERR_STATUS);
if (val) {
- /*
- * An error interrupt (on one or more channels)
- */
+ /* An error interrupt (on one or more channels) */
dev_err(&pl08x->adev->dev,
"%s error interrupt, register value 0x%08x\n",
__func__, val);
@@ -1770,9 +1657,7 @@ static irqreturn_t pl08x_irq(int irq, void *dev)
mask |= (1 << i);
}
}
- /*
- * Clear only the terminal interrupts on channels we processed
- */
+ /* Clear only the terminal interrupts on channels we processed */
writel(mask, pl08x->base + PL080_TC_CLEAR);
return mask ? IRQ_HANDLED : IRQ_NONE;
@@ -1791,6 +1676,7 @@ static int pl08x_dma_init_virtual_channels(struct pl08x_driver_data *pl08x,
int i;
INIT_LIST_HEAD(&dmadev->channels);
+
/*
* Register as many many memcpy as we have physical channels,
* we won't always be able to use all but the code will have
@@ -1819,16 +1705,23 @@ static int pl08x_dma_init_virtual_channels(struct pl08x_driver_data *pl08x,
return -ENOMEM;
}
}
+ if (chan->cd->circular_buffer) {
+ dev_err(&pl08x->adev->dev,
+ "channel %s: circular buffers not supported\n",
+ chan->name);
+ kfree(chan);
+ continue;
+ }
dev_info(&pl08x->adev->dev,
"initialize virtual channel \"%s\"\n",
chan->name);
chan->chan.device = dmadev;
- atomic_set(&chan->last_issued, 0);
- chan->lc = atomic_read(&chan->last_issued);
+ chan->chan.cookie = 0;
+ chan->lc = 0;
spin_lock_init(&chan->lock);
- INIT_LIST_HEAD(&chan->desc_list);
+ INIT_LIST_HEAD(&chan->pend_list);
tasklet_init(&chan->tasklet, pl08x_tasklet,
(unsigned long) chan);
@@ -1898,7 +1791,7 @@ static int pl08x_debugfs_show(struct seq_file *s, void *data)
seq_printf(s, "CHANNEL:\tSTATE:\n");
seq_printf(s, "--------\t------\n");
list_for_each_entry(chan, &pl08x->memcpy.channels, chan.device_node) {
- seq_printf(s, "%s\t\t\%s\n", chan->name,
+ seq_printf(s, "%s\t\t%s\n", chan->name,
pl08x_state_str(chan->state));
}
@@ -1906,7 +1799,7 @@ static int pl08x_debugfs_show(struct seq_file *s, void *data)
seq_printf(s, "CHANNEL:\tSTATE:\n");
seq_printf(s, "--------\t------\n");
list_for_each_entry(chan, &pl08x->slave.channels, chan.device_node) {
- seq_printf(s, "%s\t\t\%s\n", chan->name,
+ seq_printf(s, "%s\t\t%s\n", chan->name,
pl08x_state_str(chan->state));
}
@@ -1942,7 +1835,7 @@ static inline void init_pl08x_debugfs(struct pl08x_driver_data *pl08x)
static int pl08x_probe(struct amba_device *adev, struct amba_id *id)
{
struct pl08x_driver_data *pl08x;
- struct vendor_data *vd = id->data;
+ const struct vendor_data *vd = id->data;
int ret = 0;
int i;
@@ -1990,6 +1883,14 @@ static int pl08x_probe(struct amba_device *adev, struct amba_id *id)
pl08x->adev = adev;
pl08x->vd = vd;
+ /* By default, AHB1 only. If dualmaster, from platform */
+ pl08x->lli_buses = PL08X_AHB1;
+ pl08x->mem_buses = PL08X_AHB1;
+ if (pl08x->vd->dualmaster) {
+ pl08x->lli_buses = pl08x->pd->lli_buses;
+ pl08x->mem_buses = pl08x->pd->mem_buses;
+ }
+
/* A DMA memory pool for LLIs, align on 1-byte boundary */
pl08x->pool = dma_pool_create(DRIVER_NAME, &pl08x->adev->dev,
PL08X_LLI_TSFR_SIZE, PL08X_ALIGN, 0);
@@ -2009,14 +1910,12 @@ static int pl08x_probe(struct amba_device *adev, struct amba_id *id)
/* Turn on the PL08x */
pl08x_ensure_on(pl08x);
- /*
- * Attach the interrupt handler
- */
+ /* Attach the interrupt handler */
writel(0x000000FF, pl08x->base + PL080_ERR_CLEAR);
writel(0x000000FF, pl08x->base + PL080_TC_CLEAR);
ret = request_irq(adev->irq[0], pl08x_irq, IRQF_DISABLED,
- vd->name, pl08x);
+ DRIVER_NAME, pl08x);
if (ret) {
dev_err(&adev->dev, "%s failed to request interrupt %d\n",
__func__, adev->irq[0]);
@@ -2087,8 +1986,9 @@ static int pl08x_probe(struct amba_device *adev, struct amba_id *id)
amba_set_drvdata(adev, pl08x);
init_pl08x_debugfs(pl08x);
- dev_info(&pl08x->adev->dev, "ARM(R) %s DMA block initialized @%08x\n",
- vd->name, adev->res.start);
+ dev_info(&pl08x->adev->dev, "DMA: PL%03x rev%u at 0x%08llx irq %d\n",
+ amba_part(adev), amba_rev(adev),
+ (unsigned long long)adev->res.start, adev->irq[0]);
return 0;
out_no_slave_reg:
@@ -2115,13 +2015,11 @@ out_no_pl08x:
/* PL080 has 8 channels and the PL080 have just 2 */
static struct vendor_data vendor_pl080 = {
- .name = "PL080",
.channels = 8,
.dualmaster = true,
};
static struct vendor_data vendor_pl081 = {
- .name = "PL081",
.channels = 2,
.dualmaster = false,
};
@@ -2160,7 +2058,7 @@ static int __init pl08x_init(void)
retval = amba_driver_register(&pl08x_amba_driver);
if (retval)
printk(KERN_WARNING DRIVER_NAME
- "failed to register as an amba device (%d)\n",
+ "failed to register as an AMBA device (%d)\n",
retval);
return retval;
}
diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c
index ea0ee81..3d7d705 100644
--- a/drivers/dma/at_hdmac.c
+++ b/drivers/dma/at_hdmac.c
@@ -253,7 +253,7 @@ atc_chain_complete(struct at_dma_chan *atchan, struct at_desc *desc)
/* move myself to free_list */
list_move(&desc->desc_node, &atchan->free_list);
- /* unmap dma addresses */
+ /* unmap dma addresses (not on slave channels) */
if (!atchan->chan_common.private) {
struct device *parent = chan2parent(&atchan->chan_common);
if (!(txd->flags & DMA_COMPL_SKIP_DEST_UNMAP)) {
@@ -583,7 +583,6 @@ atc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
desc->lli.ctrlb = ctrlb;
desc->txd.cookie = 0;
- async_tx_ack(&desc->txd);
if (!first) {
first = desc;
@@ -604,7 +603,7 @@ atc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
/* set end-of-link to the last link descriptor of list*/
set_desc_eol(desc);
- desc->txd.flags = flags; /* client is in control of this ack */
+ first->txd.flags = flags; /* client is in control of this ack */
return &first->txd;
@@ -670,7 +669,7 @@ atc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
if (!desc)
goto err_desc_get;
- mem = sg_phys(sg);
+ mem = sg_dma_address(sg);
len = sg_dma_len(sg);
mem_width = 2;
if (unlikely(mem & 3 || len & 3))
@@ -712,7 +711,7 @@ atc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
if (!desc)
goto err_desc_get;
- mem = sg_phys(sg);
+ mem = sg_dma_address(sg);
len = sg_dma_len(sg);
mem_width = 2;
if (unlikely(mem & 3 || len & 3))
@@ -749,8 +748,8 @@ atc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
first->txd.cookie = -EBUSY;
first->len = total_len;
- /* last link descriptor of list is responsible of flags */
- prev->txd.flags = flags; /* client is in control of this ack */
+ /* first link descriptor of list is responsible of flags */
+ first->txd.flags = flags; /* client is in control of this ack */
return &first->txd;
@@ -854,11 +853,11 @@ static void atc_issue_pending(struct dma_chan *chan)
dev_vdbg(chan2dev(chan), "issue_pending\n");
+ spin_lock_bh(&atchan->lock);
if (!atc_chan_is_enabled(atchan)) {
- spin_lock_bh(&atchan->lock);
atc_advance_work(atchan);
- spin_unlock_bh(&atchan->lock);
}
+ spin_unlock_bh(&atchan->lock);
}
/**
@@ -1210,7 +1209,7 @@ static int __init at_dma_init(void)
{
return platform_driver_probe(&at_dma_driver, at_dma_probe);
}
-module_init(at_dma_init);
+subsys_initcall(at_dma_init);
static void __exit at_dma_exit(void)
{
diff --git a/drivers/dma/fsldma.c b/drivers/dma/fsldma.c
index e5e172d2..4de947a 100644
--- a/drivers/dma/fsldma.c
+++ b/drivers/dma/fsldma.c
@@ -1,7 +1,7 @@
/*
* Freescale MPC85xx, MPC83xx DMA Engine support
*
- * Copyright (C) 2007 Freescale Semiconductor, Inc. All rights reserved.
+ * Copyright (C) 2007-2010 Freescale Semiconductor, Inc. All rights reserved.
*
* Author:
* Zhang Wei <wei.zhang@freescale.com>, Jul 2007
@@ -1324,6 +1324,8 @@ static int __devinit fsldma_of_probe(struct platform_device *op,
fdev->common.device_control = fsl_dma_device_control;
fdev->common.dev = &op->dev;
+ dma_set_mask(&(op->dev), DMA_BIT_MASK(36));
+
dev_set_drvdata(&op->dev, fdev);
/*
diff --git a/drivers/dma/intel_mid_dma.c b/drivers/dma/intel_mid_dma.c
index 7826638..798f46a 100644
--- a/drivers/dma/intel_mid_dma.c
+++ b/drivers/dma/intel_mid_dma.c
@@ -664,11 +664,20 @@ static struct dma_async_tx_descriptor *intel_mid_dma_prep_memcpy(
/*calculate CTL_LO*/
ctl_lo.ctl_lo = 0;
ctl_lo.ctlx.int_en = 1;
- ctl_lo.ctlx.dst_tr_width = mids->dma_slave.dst_addr_width;
- ctl_lo.ctlx.src_tr_width = mids->dma_slave.src_addr_width;
ctl_lo.ctlx.dst_msize = mids->dma_slave.src_maxburst;
ctl_lo.ctlx.src_msize = mids->dma_slave.dst_maxburst;
+ /*
+ * Here we need some translation from "enum dma_slave_buswidth"
+ * to the format for our dma controller
+ * standard intel_mid_dmac's format
+ * 1 Byte 0b000
+ * 2 Bytes 0b001
+ * 4 Bytes 0b010
+ */
+ ctl_lo.ctlx.dst_tr_width = mids->dma_slave.dst_addr_width / 2;
+ ctl_lo.ctlx.src_tr_width = mids->dma_slave.src_addr_width / 2;
+
if (mids->cfg_mode == LNW_DMA_MEM_TO_MEM) {
ctl_lo.ctlx.tt_fc = 0;
ctl_lo.ctlx.sinc = 0;
@@ -746,8 +755,18 @@ static struct dma_async_tx_descriptor *intel_mid_dma_prep_slave_sg(
BUG_ON(!mids);
if (!midc->dma->pimr_mask) {
- pr_debug("MDMA: SG list is not supported by this controller\n");
- return NULL;
+ /* We can still handle sg list with only one item */
+ if (sg_len == 1) {
+ txd = intel_mid_dma_prep_memcpy(chan,
+ mids->dma_slave.dst_addr,
+ mids->dma_slave.src_addr,
+ sgl->length,
+ flags);
+ return txd;
+ } else {
+ pr_warn("MDMA: SG list is not supported by this controller\n");
+ return NULL;
+ }
}
pr_debug("MDMA: SG Length = %d, direction = %d, Flags = %#lx\n",
@@ -758,6 +777,7 @@ static struct dma_async_tx_descriptor *intel_mid_dma_prep_slave_sg(
pr_err("MDMA: Prep memcpy failed\n");
return NULL;
}
+
desc = to_intel_mid_dma_desc(txd);
desc->dirn = direction;
ctl_lo.ctl_lo = desc->ctl_lo;
@@ -1021,11 +1041,6 @@ static irqreturn_t intel_mid_dma_interrupt(int irq, void *data)
/*DMA Interrupt*/
pr_debug("MDMA:Got an interrupt on irq %d\n", irq);
- if (!mid) {
- pr_err("ERR_MDMA:null pointer mid\n");
- return -EINVAL;
- }
-
pr_debug("MDMA: Status %x, Mask %x\n", tfr_status, mid->intr_mask);
tfr_status &= mid->intr_mask;
if (tfr_status) {
diff --git a/drivers/dma/iop-adma.c b/drivers/dma/iop-adma.c
index 161c452..c6b01f5 100644
--- a/drivers/dma/iop-adma.c
+++ b/drivers/dma/iop-adma.c
@@ -1261,7 +1261,7 @@ out:
return err;
}
-#ifdef CONFIG_MD_RAID6_PQ
+#ifdef CONFIG_RAID6_PQ
static int __devinit
iop_adma_pq_zero_sum_self_test(struct iop_adma_device *device)
{
@@ -1584,7 +1584,7 @@ static int __devinit iop_adma_probe(struct platform_device *pdev)
if (dma_has_cap(DMA_PQ, dma_dev->cap_mask) &&
dma_has_cap(DMA_PQ_VAL, dma_dev->cap_mask)) {
- #ifdef CONFIG_MD_RAID6_PQ
+ #ifdef CONFIG_RAID6_PQ
ret = iop_adma_pq_zero_sum_self_test(adev);
dev_dbg(&pdev->dev, "pq self test returned %d\n", ret);
#else
diff --git a/drivers/dma/pch_dma.c b/drivers/dma/pch_dma.c
index c064c89..1c38418 100644
--- a/drivers/dma/pch_dma.c
+++ b/drivers/dma/pch_dma.c
@@ -1,6 +1,7 @@
/*
* Topcliff PCH DMA controller driver
* Copyright (c) 2010 Intel Corporation
+ * Copyright (C) 2011 OKI SEMICONDUCTOR CO., LTD.
*
* 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
@@ -921,12 +922,19 @@ static void __devexit pch_dma_remove(struct pci_dev *pdev)
}
/* PCI Device ID of DMA device */
-#define PCI_DEVICE_ID_PCH_DMA_8CH 0x8810
-#define PCI_DEVICE_ID_PCH_DMA_4CH 0x8815
+#define PCI_VENDOR_ID_ROHM 0x10DB
+#define PCI_DEVICE_ID_EG20T_PCH_DMA_8CH 0x8810
+#define PCI_DEVICE_ID_EG20T_PCH_DMA_4CH 0x8815
+#define PCI_DEVICE_ID_ML7213_DMA1_8CH 0x8026
+#define PCI_DEVICE_ID_ML7213_DMA2_8CH 0x802B
+#define PCI_DEVICE_ID_ML7213_DMA3_4CH 0x8034
static const struct pci_device_id pch_dma_id_table[] = {
- { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_PCH_DMA_8CH), 8 },
- { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_PCH_DMA_4CH), 4 },
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_EG20T_PCH_DMA_8CH), 8 },
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_EG20T_PCH_DMA_4CH), 4 },
+ { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7213_DMA1_8CH), 8}, /* UART Video */
+ { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7213_DMA2_8CH), 8}, /* PCMIF SPI */
+ { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7213_DMA3_4CH), 4}, /* FPGA */
{ 0, },
};
@@ -954,6 +962,7 @@ static void __exit pch_dma_exit(void)
module_init(pch_dma_init);
module_exit(pch_dma_exit);
-MODULE_DESCRIPTION("Topcliff PCH DMA controller driver");
+MODULE_DESCRIPTION("Intel EG20T PCH / OKI SEMICONDUCTOR ML7213 IOH "
+ "DMA controller driver");
MODULE_AUTHOR("Yong Wang <yong.y.wang@intel.com>");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/dma/ste_dma40.c b/drivers/dma/ste_dma40.c
index fab68a5..6e1d46a 100644
--- a/drivers/dma/ste_dma40.c
+++ b/drivers/dma/ste_dma40.c
@@ -1,5 +1,6 @@
/*
- * Copyright (C) ST-Ericsson SA 2007-2010
+ * Copyright (C) Ericsson AB 2007-2008
+ * Copyright (C) ST-Ericsson SA 2008-2010
* Author: Per Forlin <per.forlin@stericsson.com> for ST-Ericsson
* Author: Jonas Aaberg <jonas.aberg@stericsson.com> for ST-Ericsson
* License terms: GNU General Public License (GPL) version 2
@@ -554,8 +555,66 @@ static struct d40_desc *d40_last_queued(struct d40_chan *d40c)
return d;
}
-/* Support functions for logical channels */
+static int d40_psize_2_burst_size(bool is_log, int psize)
+{
+ if (is_log) {
+ if (psize == STEDMA40_PSIZE_LOG_1)
+ return 1;
+ } else {
+ if (psize == STEDMA40_PSIZE_PHY_1)
+ return 1;
+ }
+
+ return 2 << psize;
+}
+
+/*
+ * The dma only supports transmitting packages up to
+ * STEDMA40_MAX_SEG_SIZE << data_width. Calculate the total number of
+ * dma elements required to send the entire sg list
+ */
+static int d40_size_2_dmalen(int size, u32 data_width1, u32 data_width2)
+{
+ int dmalen;
+ u32 max_w = max(data_width1, data_width2);
+ u32 min_w = min(data_width1, data_width2);
+ u32 seg_max = ALIGN(STEDMA40_MAX_SEG_SIZE << min_w, 1 << max_w);
+
+ if (seg_max > STEDMA40_MAX_SEG_SIZE)
+ seg_max -= (1 << max_w);
+
+ if (!IS_ALIGNED(size, 1 << max_w))
+ return -EINVAL;
+
+ if (size <= seg_max)
+ dmalen = 1;
+ else {
+ dmalen = size / seg_max;
+ if (dmalen * seg_max < size)
+ dmalen++;
+ }
+ return dmalen;
+}
+
+static int d40_sg_2_dmalen(struct scatterlist *sgl, int sg_len,
+ u32 data_width1, u32 data_width2)
+{
+ struct scatterlist *sg;
+ int i;
+ int len = 0;
+ int ret;
+
+ for_each_sg(sgl, sg, sg_len, i) {
+ ret = d40_size_2_dmalen(sg_dma_len(sg),
+ data_width1, data_width2);
+ if (ret < 0)
+ return ret;
+ len += ret;
+ }
+ return len;
+}
+/* Support functions for logical channels */
static int d40_channel_execute_command(struct d40_chan *d40c,
enum d40_command command)
@@ -1241,6 +1300,21 @@ static int d40_validate_conf(struct d40_chan *d40c,
res = -EINVAL;
}
+ if (d40_psize_2_burst_size(is_log, conf->src_info.psize) *
+ (1 << conf->src_info.data_width) !=
+ d40_psize_2_burst_size(is_log, conf->dst_info.psize) *
+ (1 << conf->dst_info.data_width)) {
+ /*
+ * The DMAC hardware only supports
+ * src (burst x width) == dst (burst x width)
+ */
+
+ dev_err(&d40c->chan.dev->device,
+ "[%s] src (burst x width) != dst (burst x width)\n",
+ __func__);
+ res = -EINVAL;
+ }
+
return res;
}
@@ -1638,13 +1712,21 @@ struct dma_async_tx_descriptor *stedma40_memcpy_sg(struct dma_chan *chan,
if (d40d == NULL)
goto err;
- d40d->lli_len = sgl_len;
+ d40d->lli_len = d40_sg_2_dmalen(sgl_dst, sgl_len,
+ d40c->dma_cfg.src_info.data_width,
+ d40c->dma_cfg.dst_info.data_width);
+ if (d40d->lli_len < 0) {
+ dev_err(&d40c->chan.dev->device,
+ "[%s] Unaligned size\n", __func__);
+ goto err;
+ }
+
d40d->lli_current = 0;
d40d->txd.flags = dma_flags;
if (d40c->log_num != D40_PHY_CHAN) {
- if (d40_pool_lli_alloc(d40d, sgl_len, true) < 0) {
+ if (d40_pool_lli_alloc(d40d, d40d->lli_len, true) < 0) {
dev_err(&d40c->chan.dev->device,
"[%s] Out of memory\n", __func__);
goto err;
@@ -1654,15 +1736,17 @@ struct dma_async_tx_descriptor *stedma40_memcpy_sg(struct dma_chan *chan,
sgl_len,
d40d->lli_log.src,
d40c->log_def.lcsp1,
- d40c->dma_cfg.src_info.data_width);
+ d40c->dma_cfg.src_info.data_width,
+ d40c->dma_cfg.dst_info.data_width);
(void) d40_log_sg_to_lli(sgl_dst,
sgl_len,
d40d->lli_log.dst,
d40c->log_def.lcsp3,
- d40c->dma_cfg.dst_info.data_width);
+ d40c->dma_cfg.dst_info.data_width,
+ d40c->dma_cfg.src_info.data_width);
} else {
- if (d40_pool_lli_alloc(d40d, sgl_len, false) < 0) {
+ if (d40_pool_lli_alloc(d40d, d40d->lli_len, false) < 0) {
dev_err(&d40c->chan.dev->device,
"[%s] Out of memory\n", __func__);
goto err;
@@ -1675,6 +1759,7 @@ struct dma_async_tx_descriptor *stedma40_memcpy_sg(struct dma_chan *chan,
virt_to_phys(d40d->lli_phy.src),
d40c->src_def_cfg,
d40c->dma_cfg.src_info.data_width,
+ d40c->dma_cfg.dst_info.data_width,
d40c->dma_cfg.src_info.psize);
if (res < 0)
@@ -1687,6 +1772,7 @@ struct dma_async_tx_descriptor *stedma40_memcpy_sg(struct dma_chan *chan,
virt_to_phys(d40d->lli_phy.dst),
d40c->dst_def_cfg,
d40c->dma_cfg.dst_info.data_width,
+ d40c->dma_cfg.src_info.data_width,
d40c->dma_cfg.dst_info.psize);
if (res < 0)
@@ -1826,7 +1912,6 @@ static struct dma_async_tx_descriptor *d40_prep_memcpy(struct dma_chan *chan,
struct d40_chan *d40c = container_of(chan, struct d40_chan,
chan);
unsigned long flags;
- int err = 0;
if (d40c->phy_chan == NULL) {
dev_err(&d40c->chan.dev->device,
@@ -1844,6 +1929,15 @@ static struct dma_async_tx_descriptor *d40_prep_memcpy(struct dma_chan *chan,
}
d40d->txd.flags = dma_flags;
+ d40d->lli_len = d40_size_2_dmalen(size,
+ d40c->dma_cfg.src_info.data_width,
+ d40c->dma_cfg.dst_info.data_width);
+ if (d40d->lli_len < 0) {
+ dev_err(&d40c->chan.dev->device,
+ "[%s] Unaligned size\n", __func__);
+ goto err;
+ }
+
dma_async_tx_descriptor_init(&d40d->txd, chan);
@@ -1851,37 +1945,40 @@ static struct dma_async_tx_descriptor *d40_prep_memcpy(struct dma_chan *chan,
if (d40c->log_num != D40_PHY_CHAN) {
- if (d40_pool_lli_alloc(d40d, 1, true) < 0) {
+ if (d40_pool_lli_alloc(d40d, d40d->lli_len, true) < 0) {
dev_err(&d40c->chan.dev->device,
"[%s] Out of memory\n", __func__);
goto err;
}
- d40d->lli_len = 1;
d40d->lli_current = 0;
- d40_log_fill_lli(d40d->lli_log.src,
- src,
- size,
- d40c->log_def.lcsp1,
- d40c->dma_cfg.src_info.data_width,
- true);
+ if (d40_log_buf_to_lli(d40d->lli_log.src,
+ src,
+ size,
+ d40c->log_def.lcsp1,
+ d40c->dma_cfg.src_info.data_width,
+ d40c->dma_cfg.dst_info.data_width,
+ true) == NULL)
+ goto err;
- d40_log_fill_lli(d40d->lli_log.dst,
- dst,
- size,
- d40c->log_def.lcsp3,
- d40c->dma_cfg.dst_info.data_width,
- true);
+ if (d40_log_buf_to_lli(d40d->lli_log.dst,
+ dst,
+ size,
+ d40c->log_def.lcsp3,
+ d40c->dma_cfg.dst_info.data_width,
+ d40c->dma_cfg.src_info.data_width,
+ true) == NULL)
+ goto err;
} else {
- if (d40_pool_lli_alloc(d40d, 1, false) < 0) {
+ if (d40_pool_lli_alloc(d40d, d40d->lli_len, false) < 0) {
dev_err(&d40c->chan.dev->device,
"[%s] Out of memory\n", __func__);
goto err;
}
- err = d40_phy_fill_lli(d40d->lli_phy.src,
+ if (d40_phy_buf_to_lli(d40d->lli_phy.src,
src,
size,
d40c->dma_cfg.src_info.psize,
@@ -1889,11 +1986,11 @@ static struct dma_async_tx_descriptor *d40_prep_memcpy(struct dma_chan *chan,
d40c->src_def_cfg,
true,
d40c->dma_cfg.src_info.data_width,
- false);
- if (err)
- goto err_fill_lli;
+ d40c->dma_cfg.dst_info.data_width,
+ false) == NULL)
+ goto err;
- err = d40_phy_fill_lli(d40d->lli_phy.dst,
+ if (d40_phy_buf_to_lli(d40d->lli_phy.dst,
dst,
size,
d40c->dma_cfg.dst_info.psize,
@@ -1901,10 +1998,9 @@ static struct dma_async_tx_descriptor *d40_prep_memcpy(struct dma_chan *chan,
d40c->dst_def_cfg,
true,
d40c->dma_cfg.dst_info.data_width,
- false);
-
- if (err)
- goto err_fill_lli;
+ d40c->dma_cfg.src_info.data_width,
+ false) == NULL)
+ goto err;
(void) dma_map_single(d40c->base->dev, d40d->lli_phy.src,
d40d->lli_pool.size, DMA_TO_DEVICE);
@@ -1913,9 +2009,6 @@ static struct dma_async_tx_descriptor *d40_prep_memcpy(struct dma_chan *chan,
spin_unlock_irqrestore(&d40c->lock, flags);
return &d40d->txd;
-err_fill_lli:
- dev_err(&d40c->chan.dev->device,
- "[%s] Failed filling in PHY LLI\n", __func__);
err:
if (d40d)
d40_desc_free(d40c, d40d);
@@ -1945,13 +2038,21 @@ static int d40_prep_slave_sg_log(struct d40_desc *d40d,
dma_addr_t dev_addr = 0;
int total_size;
- if (d40_pool_lli_alloc(d40d, sg_len, true) < 0) {
+ d40d->lli_len = d40_sg_2_dmalen(sgl, sg_len,
+ d40c->dma_cfg.src_info.data_width,
+ d40c->dma_cfg.dst_info.data_width);
+ if (d40d->lli_len < 0) {
+ dev_err(&d40c->chan.dev->device,
+ "[%s] Unaligned size\n", __func__);
+ return -EINVAL;
+ }
+
+ if (d40_pool_lli_alloc(d40d, d40d->lli_len, true) < 0) {
dev_err(&d40c->chan.dev->device,
"[%s] Out of memory\n", __func__);
return -ENOMEM;
}
- d40d->lli_len = sg_len;
d40d->lli_current = 0;
if (direction == DMA_FROM_DEVICE)
@@ -1993,13 +2094,21 @@ static int d40_prep_slave_sg_phy(struct d40_desc *d40d,
dma_addr_t dst_dev_addr;
int res;
- if (d40_pool_lli_alloc(d40d, sgl_len, false) < 0) {
+ d40d->lli_len = d40_sg_2_dmalen(sgl, sgl_len,
+ d40c->dma_cfg.src_info.data_width,
+ d40c->dma_cfg.dst_info.data_width);
+ if (d40d->lli_len < 0) {
+ dev_err(&d40c->chan.dev->device,
+ "[%s] Unaligned size\n", __func__);
+ return -EINVAL;
+ }
+
+ if (d40_pool_lli_alloc(d40d, d40d->lli_len, false) < 0) {
dev_err(&d40c->chan.dev->device,
"[%s] Out of memory\n", __func__);
return -ENOMEM;
}
- d40d->lli_len = sgl_len;
d40d->lli_current = 0;
if (direction == DMA_FROM_DEVICE) {
@@ -2024,6 +2133,7 @@ static int d40_prep_slave_sg_phy(struct d40_desc *d40d,
virt_to_phys(d40d->lli_phy.src),
d40c->src_def_cfg,
d40c->dma_cfg.src_info.data_width,
+ d40c->dma_cfg.dst_info.data_width,
d40c->dma_cfg.src_info.psize);
if (res < 0)
return res;
@@ -2035,6 +2145,7 @@ static int d40_prep_slave_sg_phy(struct d40_desc *d40d,
virt_to_phys(d40d->lli_phy.dst),
d40c->dst_def_cfg,
d40c->dma_cfg.dst_info.data_width,
+ d40c->dma_cfg.src_info.data_width,
d40c->dma_cfg.dst_info.psize);
if (res < 0)
return res;
@@ -2244,6 +2355,8 @@ static void d40_set_runtime_config(struct dma_chan *chan,
psize = STEDMA40_PSIZE_PHY_8;
else if (config_maxburst >= 4)
psize = STEDMA40_PSIZE_PHY_4;
+ else if (config_maxburst >= 2)
+ psize = STEDMA40_PSIZE_PHY_2;
else
psize = STEDMA40_PSIZE_PHY_1;
}
diff --git a/drivers/dma/ste_dma40_ll.c b/drivers/dma/ste_dma40_ll.c
index 8557cb8..0b096a3 100644
--- a/drivers/dma/ste_dma40_ll.c
+++ b/drivers/dma/ste_dma40_ll.c
@@ -1,6 +1,6 @@
/*
* Copyright (C) ST-Ericsson SA 2007-2010
- * Author: Per Friden <per.friden@stericsson.com> for ST-Ericsson
+ * Author: Per Forlin <per.forlin@stericsson.com> for ST-Ericsson
* Author: Jonas Aaberg <jonas.aberg@stericsson.com> for ST-Ericsson
* License terms: GNU General Public License (GPL) version 2
*/
@@ -122,15 +122,15 @@ void d40_phy_cfg(struct stedma40_chan_cfg *cfg,
*dst_cfg = dst;
}
-int d40_phy_fill_lli(struct d40_phy_lli *lli,
- dma_addr_t data,
- u32 data_size,
- int psize,
- dma_addr_t next_lli,
- u32 reg_cfg,
- bool term_int,
- u32 data_width,
- bool is_device)
+static int d40_phy_fill_lli(struct d40_phy_lli *lli,
+ dma_addr_t data,
+ u32 data_size,
+ int psize,
+ dma_addr_t next_lli,
+ u32 reg_cfg,
+ bool term_int,
+ u32 data_width,
+ bool is_device)
{
int num_elems;
@@ -139,13 +139,6 @@ int d40_phy_fill_lli(struct d40_phy_lli *lli,
else
num_elems = 2 << psize;
- /*
- * Size is 16bit. data_width is 8, 16, 32 or 64 bit
- * Block large than 64 KiB must be split.
- */
- if (data_size > (0xffff << data_width))
- return -EINVAL;
-
/* Must be aligned */
if (!IS_ALIGNED(data, 0x1 << data_width))
return -EINVAL;
@@ -187,55 +180,118 @@ int d40_phy_fill_lli(struct d40_phy_lli *lli,
return 0;
}
+static int d40_seg_size(int size, int data_width1, int data_width2)
+{
+ u32 max_w = max(data_width1, data_width2);
+ u32 min_w = min(data_width1, data_width2);
+ u32 seg_max = ALIGN(STEDMA40_MAX_SEG_SIZE << min_w, 1 << max_w);
+
+ if (seg_max > STEDMA40_MAX_SEG_SIZE)
+ seg_max -= (1 << max_w);
+
+ if (size <= seg_max)
+ return size;
+
+ if (size <= 2 * seg_max)
+ return ALIGN(size / 2, 1 << max_w);
+
+ return seg_max;
+}
+
+struct d40_phy_lli *d40_phy_buf_to_lli(struct d40_phy_lli *lli,
+ dma_addr_t addr,
+ u32 size,
+ int psize,
+ dma_addr_t lli_phys,
+ u32 reg_cfg,
+ bool term_int,
+ u32 data_width1,
+ u32 data_width2,
+ bool is_device)
+{
+ int err;
+ dma_addr_t next = lli_phys;
+ int size_rest = size;
+ int size_seg = 0;
+
+ do {
+ size_seg = d40_seg_size(size_rest, data_width1, data_width2);
+ size_rest -= size_seg;
+
+ if (term_int && size_rest == 0)
+ next = 0;
+ else
+ next = ALIGN(next + sizeof(struct d40_phy_lli),
+ D40_LLI_ALIGN);
+
+ err = d40_phy_fill_lli(lli,
+ addr,
+ size_seg,
+ psize,
+ next,
+ reg_cfg,
+ !next,
+ data_width1,
+ is_device);
+
+ if (err)
+ goto err;
+
+ lli++;
+ if (!is_device)
+ addr += size_seg;
+ } while (size_rest);
+
+ return lli;
+
+ err:
+ return NULL;
+}
+
int d40_phy_sg_to_lli(struct scatterlist *sg,
int sg_len,
dma_addr_t target,
- struct d40_phy_lli *lli,
+ struct d40_phy_lli *lli_sg,
dma_addr_t lli_phys,
u32 reg_cfg,
- u32 data_width,
+ u32 data_width1,
+ u32 data_width2,
int psize)
{
int total_size = 0;
int i;
struct scatterlist *current_sg = sg;
- dma_addr_t next_lli_phys;
dma_addr_t dst;
- int err = 0;
+ struct d40_phy_lli *lli = lli_sg;
+ dma_addr_t l_phys = lli_phys;
for_each_sg(sg, current_sg, sg_len, i) {
total_size += sg_dma_len(current_sg);
- /* If this scatter list entry is the last one, no next link */
- if (sg_len - 1 == i)
- next_lli_phys = 0;
- else
- next_lli_phys = ALIGN(lli_phys + (i + 1) *
- sizeof(struct d40_phy_lli),
- D40_LLI_ALIGN);
-
if (target)
dst = target;
else
dst = sg_phys(current_sg);
- err = d40_phy_fill_lli(&lli[i],
- dst,
- sg_dma_len(current_sg),
- psize,
- next_lli_phys,
- reg_cfg,
- !next_lli_phys,
- data_width,
- target == dst);
- if (err)
- goto err;
+ l_phys = ALIGN(lli_phys + (lli - lli_sg) *
+ sizeof(struct d40_phy_lli), D40_LLI_ALIGN);
+
+ lli = d40_phy_buf_to_lli(lli,
+ dst,
+ sg_dma_len(current_sg),
+ psize,
+ l_phys,
+ reg_cfg,
+ sg_len - 1 == i,
+ data_width1,
+ data_width2,
+ target == dst);
+ if (lli == NULL)
+ return -EINVAL;
}
return total_size;
-err:
- return err;
}
@@ -315,17 +371,20 @@ void d40_log_lli_lcla_write(struct d40_log_lli *lcla,
writel(lli_dst->lcsp13, &lcla[1].lcsp13);
}
-void d40_log_fill_lli(struct d40_log_lli *lli,
- dma_addr_t data, u32 data_size,
- u32 reg_cfg,
- u32 data_width,
- bool addr_inc)
+static void d40_log_fill_lli(struct d40_log_lli *lli,
+ dma_addr_t data, u32 data_size,
+ u32 reg_cfg,
+ u32 data_width,
+ bool addr_inc)
{
lli->lcsp13 = reg_cfg;
/* The number of elements to transfer */
lli->lcsp02 = ((data_size >> data_width) <<
D40_MEM_LCSP0_ECNT_POS) & D40_MEM_LCSP0_ECNT_MASK;
+
+ BUG_ON((data_size >> data_width) > STEDMA40_MAX_SEG_SIZE);
+
/* 16 LSBs address of the current element */
lli->lcsp02 |= data & D40_MEM_LCSP0_SPTR_MASK;
/* 16 MSBs address of the current element */
@@ -348,55 +407,94 @@ int d40_log_sg_to_dev(struct scatterlist *sg,
int total_size = 0;
struct scatterlist *current_sg = sg;
int i;
+ struct d40_log_lli *lli_src = lli->src;
+ struct d40_log_lli *lli_dst = lli->dst;
for_each_sg(sg, current_sg, sg_len, i) {
total_size += sg_dma_len(current_sg);
if (direction == DMA_TO_DEVICE) {
- d40_log_fill_lli(&lli->src[i],
- sg_phys(current_sg),
- sg_dma_len(current_sg),
- lcsp->lcsp1, src_data_width,
- true);
- d40_log_fill_lli(&lli->dst[i],
- dev_addr,
- sg_dma_len(current_sg),
- lcsp->lcsp3, dst_data_width,
- false);
+ lli_src =
+ d40_log_buf_to_lli(lli_src,
+ sg_phys(current_sg),
+ sg_dma_len(current_sg),
+ lcsp->lcsp1, src_data_width,
+ dst_data_width,
+ true);
+ lli_dst =
+ d40_log_buf_to_lli(lli_dst,
+ dev_addr,
+ sg_dma_len(current_sg),
+ lcsp->lcsp3, dst_data_width,
+ src_data_width,
+ false);
} else {
- d40_log_fill_lli(&lli->dst[i],
- sg_phys(current_sg),
- sg_dma_len(current_sg),
- lcsp->lcsp3, dst_data_width,
- true);
- d40_log_fill_lli(&lli->src[i],
- dev_addr,
- sg_dma_len(current_sg),
- lcsp->lcsp1, src_data_width,
- false);
+ lli_dst =
+ d40_log_buf_to_lli(lli_dst,
+ sg_phys(current_sg),
+ sg_dma_len(current_sg),
+ lcsp->lcsp3, dst_data_width,
+ src_data_width,
+ true);
+ lli_src =
+ d40_log_buf_to_lli(lli_src,
+ dev_addr,
+ sg_dma_len(current_sg),
+ lcsp->lcsp1, src_data_width,
+ dst_data_width,
+ false);
}
}
return total_size;
}
+struct d40_log_lli *d40_log_buf_to_lli(struct d40_log_lli *lli_sg,
+ dma_addr_t addr,
+ int size,
+ u32 lcsp13, /* src or dst*/
+ u32 data_width1,
+ u32 data_width2,
+ bool addr_inc)
+{
+ struct d40_log_lli *lli = lli_sg;
+ int size_rest = size;
+ int size_seg = 0;
+
+ do {
+ size_seg = d40_seg_size(size_rest, data_width1, data_width2);
+ size_rest -= size_seg;
+
+ d40_log_fill_lli(lli,
+ addr,
+ size_seg,
+ lcsp13, data_width1,
+ addr_inc);
+ if (addr_inc)
+ addr += size_seg;
+ lli++;
+ } while (size_rest);
+
+ return lli;
+}
+
int d40_log_sg_to_lli(struct scatterlist *sg,
int sg_len,
struct d40_log_lli *lli_sg,
u32 lcsp13, /* src or dst*/
- u32 data_width)
+ u32 data_width1, u32 data_width2)
{
int total_size = 0;
struct scatterlist *current_sg = sg;
int i;
+ struct d40_log_lli *lli = lli_sg;
for_each_sg(sg, current_sg, sg_len, i) {
total_size += sg_dma_len(current_sg);
-
- d40_log_fill_lli(&lli_sg[i],
- sg_phys(current_sg),
- sg_dma_len(current_sg),
- lcsp13, data_width,
- true);
+ lli = d40_log_buf_to_lli(lli,
+ sg_phys(current_sg),
+ sg_dma_len(current_sg),
+ lcsp13,
+ data_width1, data_width2, true);
}
return total_size;
}
diff --git a/drivers/dma/ste_dma40_ll.h b/drivers/dma/ste_dma40_ll.h
index 9e419b9..9cc4349 100644
--- a/drivers/dma/ste_dma40_ll.h
+++ b/drivers/dma/ste_dma40_ll.h
@@ -292,18 +292,20 @@ int d40_phy_sg_to_lli(struct scatterlist *sg,
struct d40_phy_lli *lli,
dma_addr_t lli_phys,
u32 reg_cfg,
- u32 data_width,
+ u32 data_width1,
+ u32 data_width2,
int psize);
-int d40_phy_fill_lli(struct d40_phy_lli *lli,
- dma_addr_t data,
- u32 data_size,
- int psize,
- dma_addr_t next_lli,
- u32 reg_cfg,
- bool term_int,
- u32 data_width,
- bool is_device);
+struct d40_phy_lli *d40_phy_buf_to_lli(struct d40_phy_lli *lli,
+ dma_addr_t data,
+ u32 data_size,
+ int psize,
+ dma_addr_t next_lli,
+ u32 reg_cfg,
+ bool term_int,
+ u32 data_width1,
+ u32 data_width2,
+ bool is_device);
void d40_phy_lli_write(void __iomem *virtbase,
u32 phy_chan_num,
@@ -312,12 +314,12 @@ void d40_phy_lli_write(void __iomem *virtbase,
/* Logical channels */
-void d40_log_fill_lli(struct d40_log_lli *lli,
- dma_addr_t data,
- u32 data_size,
- u32 reg_cfg,
- u32 data_width,
- bool addr_inc);
+struct d40_log_lli *d40_log_buf_to_lli(struct d40_log_lli *lli_sg,
+ dma_addr_t addr,
+ int size,
+ u32 lcsp13, /* src or dst*/
+ u32 data_width1, u32 data_width2,
+ bool addr_inc);
int d40_log_sg_to_dev(struct scatterlist *sg,
int sg_len,
@@ -332,7 +334,7 @@ int d40_log_sg_to_lli(struct scatterlist *sg,
int sg_len,
struct d40_log_lli *lli_sg,
u32 lcsp13, /* src or dst*/
- u32 data_width);
+ u32 data_width1, u32 data_width2);
void d40_log_lli_lcpa_write(struct d40_log_lli_full *lcpa,
struct d40_log_lli *lli_dst,
diff --git a/drivers/firewire/Kconfig b/drivers/firewire/Kconfig
index 68f942c..0c56989 100644
--- a/drivers/firewire/Kconfig
+++ b/drivers/firewire/Kconfig
@@ -49,15 +49,13 @@ config FIREWIRE_SBP2
configuration section.
config FIREWIRE_NET
- tristate "IP networking over 1394 (EXPERIMENTAL)"
- depends on FIREWIRE && INET && EXPERIMENTAL
+ tristate "IP networking over 1394"
+ depends on FIREWIRE && INET
help
This enables IPv4 over IEEE 1394, providing IP connectivity with
other implementations of RFC 2734 as found on several operating
systems. Multicast support is currently limited.
- NOTE, this driver is not stable yet!
-
To compile this driver as a module, say M here: The module will be
called firewire-net.
diff --git a/drivers/firewire/core-card.c b/drivers/firewire/core-card.c
index be04923..24ff355 100644
--- a/drivers/firewire/core-card.c
+++ b/drivers/firewire/core-card.c
@@ -75,6 +75,8 @@ static size_t config_rom_length = 1 + 4 + 1 + 1;
#define BIB_IRMC ((1) << 31)
#define NODE_CAPABILITIES 0x0c0083c0 /* per IEEE 1394 clause 8.3.2.6.5.2 */
+#define CANON_OUI 0x000085
+
static void generate_config_rom(struct fw_card *card, __be32 *config_rom)
{
struct fw_descriptor *desc;
@@ -284,6 +286,7 @@ static void bm_work(struct work_struct *work)
bool root_device_is_running;
bool root_device_is_cmc;
bool irm_is_1394_1995_only;
+ bool keep_this_irm;
spin_lock_irq(&card->lock);
@@ -305,6 +308,10 @@ static void bm_work(struct work_struct *work)
irm_is_1394_1995_only = irm_device && irm_device->config_rom &&
(irm_device->config_rom[2] & 0x000000f0) == 0;
+ /* Canon MV5i works unreliably if it is not root node. */
+ keep_this_irm = irm_device && irm_device->config_rom &&
+ irm_device->config_rom[3] >> 8 == CANON_OUI;
+
root_id = root_node->node_id;
irm_id = card->irm_node->node_id;
local_id = card->local_node->node_id;
@@ -333,7 +340,7 @@ static void bm_work(struct work_struct *work)
goto pick_me;
}
- if (irm_is_1394_1995_only) {
+ if (irm_is_1394_1995_only && !keep_this_irm) {
new_root_id = local_id;
fw_notify("%s, making local node (%02x) root.\n",
"IRM is not 1394a compliant", new_root_id);
@@ -382,7 +389,7 @@ static void bm_work(struct work_struct *work)
spin_lock_irq(&card->lock);
- if (rcode != RCODE_COMPLETE) {
+ if (rcode != RCODE_COMPLETE && !keep_this_irm) {
/*
* The lock request failed, maybe the IRM
* isn't really IRM capable after all. Let's
diff --git a/drivers/firewire/net.c b/drivers/firewire/net.c
index c2e194c..7ed08fd1 100644
--- a/drivers/firewire/net.c
+++ b/drivers/firewire/net.c
@@ -191,6 +191,7 @@ struct fwnet_peer {
struct fwnet_device *dev;
u64 guid;
u64 fifo;
+ __be32 ip;
/* guarded by dev->lock */
struct list_head pd_list; /* received partial datagrams */
@@ -570,6 +571,8 @@ static int fwnet_finish_incoming_packet(struct net_device *net,
peer->speed = sspd;
if (peer->max_payload > max_payload)
peer->max_payload = max_payload;
+
+ peer->ip = arp1394->sip;
}
spin_unlock_irqrestore(&dev->lock, flags);
@@ -1470,6 +1473,7 @@ static int fwnet_add_peer(struct fwnet_device *dev,
peer->dev = dev;
peer->guid = (u64)device->config_rom[3] << 32 | device->config_rom[4];
peer->fifo = FWNET_NO_FIFO_ADDR;
+ peer->ip = 0;
INIT_LIST_HEAD(&peer->pd_list);
peer->pdg_size = 0;
peer->datagram_label = 0;
@@ -1589,10 +1593,13 @@ static int fwnet_remove(struct device *_dev)
mutex_lock(&fwnet_device_mutex);
+ net = dev->netdev;
+ if (net && peer->ip)
+ arp_invalidate(net, peer->ip);
+
fwnet_remove_peer(peer, dev);
if (list_empty(&dev->peer_list)) {
- net = dev->netdev;
unregister_netdev(net);
if (dev->local_fifo != FWNET_NO_FIFO_ADDR)
diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig
index e8b6a13..e710424 100644
--- a/drivers/firmware/Kconfig
+++ b/drivers/firmware/Kconfig
@@ -27,7 +27,7 @@ config EDD_OFF
using the kernel parameter 'edd={on|skipmbr|off}'.
config FIRMWARE_MEMMAP
- bool "Add firmware-provided memory map to sysfs" if EMBEDDED
+ bool "Add firmware-provided memory map to sysfs" if EXPERT
default X86
help
Add the firmware-provided (unmodified) memory map to /sys/firmware/memmap.
diff --git a/drivers/gpio/cs5535-gpio.c b/drivers/gpio/cs5535-gpio.c
index 815d98b2..0d05ea7 100644
--- a/drivers/gpio/cs5535-gpio.c
+++ b/drivers/gpio/cs5535-gpio.c
@@ -11,14 +11,13 @@
#include <linux/kernel.h>
#include <linux/spinlock.h>
#include <linux/module.h>
-#include <linux/pci.h>
+#include <linux/platform_device.h>
#include <linux/gpio.h>
#include <linux/io.h>
#include <linux/cs5535.h>
#include <asm/msr.h>
#define DRV_NAME "cs5535-gpio"
-#define GPIO_BAR 1
/*
* Some GPIO pins
@@ -47,7 +46,7 @@ static struct cs5535_gpio_chip {
struct gpio_chip chip;
resource_size_t base;
- struct pci_dev *pdev;
+ struct platform_device *pdev;
spinlock_t lock;
} cs5535_gpio_chip;
@@ -301,10 +300,10 @@ static struct cs5535_gpio_chip cs5535_gpio_chip = {
},
};
-static int __init cs5535_gpio_probe(struct pci_dev *pdev,
- const struct pci_device_id *pci_id)
+static int __devinit cs5535_gpio_probe(struct platform_device *pdev)
{
- int err;
+ struct resource *res;
+ int err = -EIO;
ulong mask_orig = mask;
/* There are two ways to get the GPIO base address; one is by
@@ -314,25 +313,23 @@ static int __init cs5535_gpio_probe(struct pci_dev *pdev,
* it turns out to be unreliable in the face of crappy BIOSes, we
* can always go back to using MSRs.. */
- err = pci_enable_device_io(pdev);
- if (err) {
- dev_err(&pdev->dev, "can't enable device IO\n");
+ res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "can't fetch device resource info\n");
goto done;
}
- err = pci_request_region(pdev, GPIO_BAR, DRV_NAME);
- if (err) {
- dev_err(&pdev->dev, "can't alloc PCI BAR #%d\n", GPIO_BAR);
+ if (!request_region(res->start, resource_size(res), pdev->name)) {
+ dev_err(&pdev->dev, "can't request region\n");
goto done;
}
/* set up the driver-specific struct */
- cs5535_gpio_chip.base = pci_resource_start(pdev, GPIO_BAR);
+ cs5535_gpio_chip.base = res->start;
cs5535_gpio_chip.pdev = pdev;
spin_lock_init(&cs5535_gpio_chip.lock);
- dev_info(&pdev->dev, "allocated PCI BAR #%d: base 0x%llx\n", GPIO_BAR,
- (unsigned long long) cs5535_gpio_chip.base);
+ dev_info(&pdev->dev, "reserved resource region %pR\n", res);
/* mask out reserved pins */
mask &= 0x1F7FFFFF;
@@ -350,78 +347,49 @@ static int __init cs5535_gpio_probe(struct pci_dev *pdev,
if (err)
goto release_region;
- dev_info(&pdev->dev, DRV_NAME ": GPIO support successfully loaded.\n");
+ dev_info(&pdev->dev, "GPIO support successfully loaded.\n");
return 0;
release_region:
- pci_release_region(pdev, GPIO_BAR);
+ release_region(res->start, resource_size(res));
done:
return err;
}
-static void __exit cs5535_gpio_remove(struct pci_dev *pdev)
+static int __devexit cs5535_gpio_remove(struct platform_device *pdev)
{
+ struct resource *r;
int err;
err = gpiochip_remove(&cs5535_gpio_chip.chip);
if (err) {
/* uhh? */
dev_err(&pdev->dev, "unable to remove gpio_chip?\n");
+ return err;
}
- pci_release_region(pdev, GPIO_BAR);
-}
-
-static struct pci_device_id cs5535_gpio_pci_tbl[] = {
- { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_CS5535_ISA) },
- { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_ISA) },
- { 0, },
-};
-MODULE_DEVICE_TABLE(pci, cs5535_gpio_pci_tbl);
-/*
- * We can't use the standard PCI driver registration stuff here, since
- * that allows only one driver to bind to each PCI device (and we want
- * multiple drivers to be able to bind to the device). Instead, manually
- * scan for the PCI device, request a single region, and keep track of the
- * devices that we're using.
- */
-
-static int __init cs5535_gpio_scan_pci(void)
-{
- struct pci_dev *pdev;
- int err = -ENODEV;
- int i;
-
- for (i = 0; i < ARRAY_SIZE(cs5535_gpio_pci_tbl); i++) {
- pdev = pci_get_device(cs5535_gpio_pci_tbl[i].vendor,
- cs5535_gpio_pci_tbl[i].device, NULL);
- if (pdev) {
- err = cs5535_gpio_probe(pdev, &cs5535_gpio_pci_tbl[i]);
- if (err)
- pci_dev_put(pdev);
-
- /* we only support a single CS5535/6 southbridge */
- break;
- }
- }
-
- return err;
+ r = platform_get_resource(pdev, IORESOURCE_IO, 0);
+ release_region(r->start, resource_size(r));
+ return 0;
}
-static void __exit cs5535_gpio_free_pci(void)
-{
- cs5535_gpio_remove(cs5535_gpio_chip.pdev);
- pci_dev_put(cs5535_gpio_chip.pdev);
-}
+static struct platform_driver cs5535_gpio_drv = {
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ },
+ .probe = cs5535_gpio_probe,
+ .remove = __devexit_p(cs5535_gpio_remove),
+};
static int __init cs5535_gpio_init(void)
{
- return cs5535_gpio_scan_pci();
+ return platform_driver_register(&cs5535_gpio_drv);
}
static void __exit cs5535_gpio_exit(void)
{
- cs5535_gpio_free_pci();
+ platform_driver_unregister(&cs5535_gpio_drv);
}
module_init(cs5535_gpio_init);
@@ -430,3 +398,4 @@ module_exit(cs5535_gpio_exit);
MODULE_AUTHOR("Andres Salomon <dilinger@queued.net>");
MODULE_DESCRIPTION("AMD CS5535/CS5536 GPIO driver");
MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/drivers/gpio/timbgpio.c b/drivers/gpio/timbgpio.c
index 349131e..58c8f30 100644
--- a/drivers/gpio/timbgpio.c
+++ b/drivers/gpio/timbgpio.c
@@ -193,13 +193,13 @@ out:
return ret;
}
-static void timbgpio_irq(struct irq_data *d, struct irq_desc *desc)
+static void timbgpio_irq(unsigned int irq, struct irq_desc *desc)
{
- struct timbgpio *tgpio = irq_data_get_irq_data(d);
+ struct timbgpio *tgpio = get_irq_data(irq);
unsigned long ipr;
int offset;
- desc->irq_data.chip->ack(irq_get_irq_data(d));
+ desc->irq_data.chip->irq_ack(irq_get_irq_data(irq));
ipr = ioread32(tgpio->membase + TGPIO_IPR);
iowrite32(ipr, tgpio->membase + TGPIO_ICR);
diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index 7af4436..0902d44 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -23,7 +23,7 @@ config DRM_KMS_HELPER
tristate
depends on DRM
select FB
- select FRAMEBUFFER_CONSOLE if !EMBEDDED
+ select FRAMEBUFFER_CONSOLE if !EXPERT
help
FB and CRTC helpers for KMS drivers.
@@ -100,14 +100,16 @@ config DRM_I830
config DRM_I915
tristate "i915 driver"
depends on AGP_INTEL
+ # we need shmfs for the swappable backing store, and in particular
+ # the shmem_readpage() which depends upon tmpfs
select SHMEM
+ select TMPFS
select DRM_KMS_HELPER
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
# i915 depends on ACPI_VIDEO when ACPI is enabled
# but for select to work, need to select ACPI_VIDEO's dependencies, ick
- select VIDEO_OUTPUT_CONTROL if ACPI
select BACKLIGHT_CLASS_DEVICE if ACPI
select INPUT if ACPI
select ACPI_VIDEO if ACPI
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index 0307d60..6977a1c 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -607,25 +607,6 @@ void drm_fb_helper_fini(struct drm_fb_helper *fb_helper)
}
EXPORT_SYMBOL(drm_fb_helper_fini);
-void drm_fb_helper_fill_fix(struct fb_info *info, struct drm_framebuffer *fb)
-{
- info->fix.type = FB_TYPE_PACKED_PIXELS;
- info->fix.visual = fb->depth == 8 ? FB_VISUAL_PSEUDOCOLOR :
- FB_VISUAL_TRUECOLOR;
- info->fix.mmio_start = 0;
- info->fix.mmio_len = 0;
- info->fix.type_aux = 0;
- info->fix.xpanstep = 1; /* doing it in hw */
- info->fix.ypanstep = 1; /* doing it in hw */
- info->fix.ywrapstep = 0;
- info->fix.accel = FB_ACCEL_NONE;
- info->fix.type_aux = 0;
-
- info->fix.line_length = fb->pitch;
- return;
-}
-EXPORT_SYMBOL(drm_fb_helper_fill_fix);
-
static int setcolreg(struct drm_crtc *crtc, u16 red, u16 green,
u16 blue, u16 regno, struct fb_info *info)
{
@@ -835,7 +816,6 @@ int drm_fb_helper_set_par(struct fb_info *info)
mutex_unlock(&dev->mode_config.mutex);
return ret;
}
- drm_fb_helper_fill_fix(info, fb_helper->fb);
}
mutex_unlock(&dev->mode_config.mutex);
@@ -973,7 +953,6 @@ int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
if (new_fb) {
info->var.pixclock = 0;
- drm_fb_helper_fill_fix(info, fb_helper->fb);
if (register_framebuffer(info) < 0) {
return -EINVAL;
}
@@ -1000,6 +979,26 @@ int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
}
EXPORT_SYMBOL(drm_fb_helper_single_fb_probe);
+void drm_fb_helper_fill_fix(struct fb_info *info, uint32_t pitch,
+ uint32_t depth)
+{
+ info->fix.type = FB_TYPE_PACKED_PIXELS;
+ info->fix.visual = depth == 8 ? FB_VISUAL_PSEUDOCOLOR :
+ FB_VISUAL_TRUECOLOR;
+ info->fix.mmio_start = 0;
+ info->fix.mmio_len = 0;
+ info->fix.type_aux = 0;
+ info->fix.xpanstep = 1; /* doing it in hw */
+ info->fix.ypanstep = 1; /* doing it in hw */
+ info->fix.ywrapstep = 0;
+ info->fix.accel = FB_ACCEL_NONE;
+ info->fix.type_aux = 0;
+
+ info->fix.line_length = pitch;
+ return;
+}
+EXPORT_SYMBOL(drm_fb_helper_fill_fix);
+
void drm_fb_helper_fill_var(struct fb_info *info, struct drm_fb_helper *fb_helper,
uint32_t fb_width, uint32_t fb_height)
{
@@ -1534,11 +1533,11 @@ bool drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper)
}
EXPORT_SYMBOL(drm_fb_helper_hotplug_event);
-/* The Kconfig DRM_KMS_HELPER selects FRAMEBUFFER_CONSOLE (if !EMBEDDED)
+/* The Kconfig DRM_KMS_HELPER selects FRAMEBUFFER_CONSOLE (if !EXPERT)
* but the module doesn't depend on any fb console symbols. At least
* attempt to load fbcon to avoid leaving the system without a usable console.
*/
-#if defined(CONFIG_FRAMEBUFFER_CONSOLE_MODULE) && !defined(CONFIG_EMBEDDED)
+#if defined(CONFIG_FRAMEBUFFER_CONSOLE_MODULE) && !defined(CONFIG_EXPERT)
static int __init drm_fb_helper_modinit(void)
{
const char *name = "fbcon";
diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
index 19a3d58..3601466 100644
--- a/drivers/gpu/drm/i915/i915_debugfs.c
+++ b/drivers/gpu/drm/i915/i915_debugfs.c
@@ -703,7 +703,7 @@ static void print_error_buffers(struct seq_file *m,
seq_printf(m, "%s [%d]:\n", name, count);
while (count--) {
- seq_printf(m, " %08x %8zd %04x %04x %08x%s%s%s%s%s%s",
+ seq_printf(m, " %08x %8u %04x %04x %08x%s%s%s%s%s%s",
err->gtt_offset,
err->size,
err->read_domains,
diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
index 844f3c9..17bd766 100644
--- a/drivers/gpu/drm/i915/i915_dma.c
+++ b/drivers/gpu/drm/i915/i915_dma.c
@@ -152,7 +152,7 @@ static int i915_initialize(struct drm_device * dev, drm_i915_init_t * init)
{
drm_i915_private_t *dev_priv = dev->dev_private;
struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv;
- struct intel_ring_buffer *ring = LP_RING(dev_priv);
+ int ret;
master_priv->sarea = drm_getsarea(dev);
if (master_priv->sarea) {
@@ -163,33 +163,22 @@ static int i915_initialize(struct drm_device * dev, drm_i915_init_t * init)
}
if (init->ring_size != 0) {
- if (ring->obj != NULL) {
+ if (LP_RING(dev_priv)->obj != NULL) {
i915_dma_cleanup(dev);
DRM_ERROR("Client tried to initialize ringbuffer in "
"GEM mode\n");
return -EINVAL;
}
- ring->size = init->ring_size;
-
- ring->map.offset = init->ring_start;
- ring->map.size = init->ring_size;
- ring->map.type = 0;
- ring->map.flags = 0;
- ring->map.mtrr = 0;
-
- drm_core_ioremap_wc(&ring->map, dev);
-
- if (ring->map.handle == NULL) {
+ ret = intel_render_ring_init_dri(dev,
+ init->ring_start,
+ init->ring_size);
+ if (ret) {
i915_dma_cleanup(dev);
- DRM_ERROR("can not ioremap virtual address for"
- " ring buffer\n");
- return -ENOMEM;
+ return ret;
}
}
- ring->virtual_start = ring->map.handle;
-
dev_priv->cpp = init->cpp;
dev_priv->back_offset = init->back_offset;
dev_priv->front_offset = init->front_offset;
@@ -1226,9 +1215,15 @@ static int i915_load_modeset_init(struct drm_device *dev)
if (ret)
DRM_INFO("failed to find VBIOS tables\n");
- /* if we have > 1 VGA cards, then disable the radeon VGA resources */
+ /* If we have > 1 VGA cards, then we need to arbitrate access
+ * to the common VGA resources.
+ *
+ * If we are a secondary display controller (!PCI_DISPLAY_CLASS_VGA),
+ * then we do not take part in VGA arbitration and the
+ * vga_client_register() fails with -ENODEV.
+ */
ret = vga_client_register(dev->pdev, dev, NULL, i915_vga_set_decode);
- if (ret)
+ if (ret && ret != -ENODEV)
goto cleanup_ringbuffer;
intel_register_dsm_handler();
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
index 0de75a2..66796bb 100644
--- a/drivers/gpu/drm/i915/i915_drv.c
+++ b/drivers/gpu/drm/i915/i915_drv.c
@@ -49,6 +49,9 @@ module_param_named(powersave, i915_powersave, int, 0600);
unsigned int i915_lvds_downclock = 0;
module_param_named(lvds_downclock, i915_lvds_downclock, int, 0400);
+unsigned int i915_panel_use_ssc = 1;
+module_param_named(lvds_use_ssc, i915_panel_use_ssc, int, 0600);
+
bool i915_try_reset = true;
module_param_named(reset, i915_try_reset, bool, 0600);
@@ -57,7 +60,7 @@ extern int intel_agp_enabled;
#define INTEL_VGA_DEVICE(id, info) { \
.class = PCI_CLASS_DISPLAY_VGA << 8, \
- .class_mask = 0xffff00, \
+ .class_mask = 0xff0000, \
.vendor = 0x8086, \
.device = id, \
.subvendor = PCI_ANY_ID, \
@@ -749,6 +752,9 @@ static int __init i915_init(void)
driver.driver_features &= ~DRIVER_MODESET;
#endif
+ if (!(driver.driver_features & DRIVER_MODESET))
+ driver.get_vblank_timestamp = NULL;
+
return drm_init(&driver);
}
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 385fc7e..a0149c6 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -543,8 +543,11 @@ typedef struct drm_i915_private {
/** List of all objects in gtt_space. Used to restore gtt
* mappings on resume */
struct list_head gtt_list;
- /** End of mappable part of GTT */
+
+ /** Usable portion of the GTT for GEM */
+ unsigned long gtt_start;
unsigned long gtt_mappable_end;
+ unsigned long gtt_end;
struct io_mapping *gtt_mapping;
int gtt_mtrr;
@@ -954,6 +957,7 @@ extern int i915_max_ioctl;
extern unsigned int i915_fbpercrtc;
extern unsigned int i915_powersave;
extern unsigned int i915_lvds_downclock;
+extern unsigned int i915_panel_use_ssc;
extern int i915_suspend(struct drm_device *dev, pm_message_t state);
extern int i915_resume(struct drm_device *dev);
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index 3dfc848..cf4f74c 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -140,12 +140,16 @@ void i915_gem_do_init(struct drm_device *dev,
{
drm_i915_private_t *dev_priv = dev->dev_private;
- drm_mm_init(&dev_priv->mm.gtt_space, start,
- end - start);
+ drm_mm_init(&dev_priv->mm.gtt_space, start, end - start);
+ dev_priv->mm.gtt_start = start;
+ dev_priv->mm.gtt_mappable_end = mappable_end;
+ dev_priv->mm.gtt_end = end;
dev_priv->mm.gtt_total = end - start;
dev_priv->mm.mappable_gtt_total = min(end, mappable_end) - start;
- dev_priv->mm.gtt_mappable_end = mappable_end;
+
+ /* Take over this portion of the GTT */
+ intel_gtt_clear_range(start / PAGE_SIZE, (end-start) / PAGE_SIZE);
}
int
@@ -1857,7 +1861,7 @@ i915_gem_retire_requests_ring(struct drm_device *dev,
seqno = ring->get_seqno(ring);
- for (i = 0; i < I915_NUM_RINGS; i++)
+ for (i = 0; i < ARRAY_SIZE(ring->sync_seqno); i++)
if (seqno >= ring->sync_seqno[i])
ring->sync_seqno[i] = 0;
diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c
index e698343..d2f445e 100644
--- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c
+++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c
@@ -464,8 +464,6 @@ i915_gem_execbuffer_relocate(struct drm_device *dev,
int ret;
list_for_each_entry(obj, objects, exec_list) {
- obj->base.pending_read_domains = 0;
- obj->base.pending_write_domain = 0;
ret = i915_gem_execbuffer_relocate_object(obj, eb);
if (ret)
return ret;
@@ -505,6 +503,9 @@ i915_gem_execbuffer_reserve(struct intel_ring_buffer *ring,
list_move(&obj->exec_list, &ordered_objects);
else
list_move_tail(&obj->exec_list, &ordered_objects);
+
+ obj->base.pending_read_domains = 0;
+ obj->base.pending_write_domain = 0;
}
list_splice(&ordered_objects, objects);
@@ -636,6 +637,7 @@ i915_gem_execbuffer_relocate_slow(struct drm_device *dev,
{
struct drm_i915_gem_relocation_entry *reloc;
struct drm_i915_gem_object *obj;
+ int *reloc_offset;
int i, total, ret;
/* We may process another execbuffer during the unlock... */
@@ -653,8 +655,11 @@ i915_gem_execbuffer_relocate_slow(struct drm_device *dev,
for (i = 0; i < count; i++)
total += exec[i].relocation_count;
+ reloc_offset = drm_malloc_ab(count, sizeof(*reloc_offset));
reloc = drm_malloc_ab(total, sizeof(*reloc));
- if (reloc == NULL) {
+ if (reloc == NULL || reloc_offset == NULL) {
+ drm_free_large(reloc);
+ drm_free_large(reloc_offset);
mutex_lock(&dev->struct_mutex);
return -ENOMEM;
}
@@ -672,6 +677,7 @@ i915_gem_execbuffer_relocate_slow(struct drm_device *dev,
goto err;
}
+ reloc_offset[i] = total;
total += exec[i].relocation_count;
}
@@ -705,17 +711,12 @@ i915_gem_execbuffer_relocate_slow(struct drm_device *dev,
if (ret)
goto err;
- total = 0;
list_for_each_entry(obj, objects, exec_list) {
- obj->base.pending_read_domains = 0;
- obj->base.pending_write_domain = 0;
+ int offset = obj->exec_entry - exec;
ret = i915_gem_execbuffer_relocate_object_slow(obj, eb,
- reloc + total);
+ reloc + reloc_offset[offset]);
if (ret)
goto err;
-
- total += exec->relocation_count;
- exec++;
}
/* Leave the user relocations as are, this is the painfully slow path,
@@ -726,6 +727,7 @@ i915_gem_execbuffer_relocate_slow(struct drm_device *dev,
err:
drm_free_large(reloc);
+ drm_free_large(reloc_offset);
return ret;
}
@@ -770,7 +772,8 @@ i915_gem_execbuffer_sync_rings(struct drm_i915_gem_object *obj,
if (from == NULL || to == from)
return 0;
- if (INTEL_INFO(obj->base.dev)->gen < 6)
+ /* XXX gpu semaphores are currently causing hard hangs on SNB mobile */
+ if (INTEL_INFO(obj->base.dev)->gen < 6 || IS_MOBILE(obj->base.dev))
return i915_gem_object_wait_rendering(obj, true);
idx = intel_ring_sync_index(from, to);
@@ -1172,7 +1175,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
goto err;
seqno = i915_gem_next_request_seqno(dev, ring);
- for (i = 0; i < I915_NUM_RINGS-1; i++) {
+ for (i = 0; i < ARRAY_SIZE(ring->sync_seqno); i++) {
if (seqno < ring->sync_seqno[i]) {
/* The GPU can not handle its semaphore value wrapping,
* so every billion or so execbuffers, we need to stall
diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c
index 70433ae..b0abdc6 100644
--- a/drivers/gpu/drm/i915/i915_gem_gtt.c
+++ b/drivers/gpu/drm/i915/i915_gem_gtt.c
@@ -34,6 +34,10 @@ void i915_gem_restore_gtt_mappings(struct drm_device *dev)
struct drm_i915_private *dev_priv = dev->dev_private;
struct drm_i915_gem_object *obj;
+ /* First fill our portion of the GTT with scratch pages */
+ intel_gtt_clear_range(dev_priv->mm.gtt_start / PAGE_SIZE,
+ (dev_priv->mm.gtt_end - dev_priv->mm.gtt_start) / PAGE_SIZE);
+
list_for_each_entry(obj, &dev_priv->mm.gtt_list, gtt_list) {
i915_gem_clflush_object(obj);
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index e418e8b..062f353 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -274,24 +274,35 @@ int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe,
return ret;
}
-int i915_get_vblank_timestamp(struct drm_device *dev, int crtc,
+int i915_get_vblank_timestamp(struct drm_device *dev, int pipe,
int *max_error,
struct timeval *vblank_time,
unsigned flags)
{
- struct drm_crtc *drmcrtc;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct drm_crtc *crtc;
- if (crtc < 0 || crtc >= dev->num_crtcs) {
- DRM_ERROR("Invalid crtc %d\n", crtc);
+ if (pipe < 0 || pipe >= dev_priv->num_pipe) {
+ DRM_ERROR("Invalid crtc %d\n", pipe);
return -EINVAL;
}
/* Get drm_crtc to timestamp: */
- drmcrtc = intel_get_crtc_for_pipe(dev, crtc);
+ crtc = intel_get_crtc_for_pipe(dev, pipe);
+ if (crtc == NULL) {
+ DRM_ERROR("Invalid crtc %d\n", pipe);
+ return -EINVAL;
+ }
+
+ if (!crtc->enabled) {
+ DRM_DEBUG_KMS("crtc %d is disabled\n", pipe);
+ return -EBUSY;
+ }
/* Helper routine in DRM core does all the work: */
- return drm_calc_vbltimestamp_from_scanoutpos(dev, crtc, max_error,
- vblank_time, flags, drmcrtc);
+ return drm_calc_vbltimestamp_from_scanoutpos(dev, pipe, max_error,
+ vblank_time, flags,
+ crtc);
}
/*
@@ -348,8 +359,12 @@ static void notify_ring(struct drm_device *dev,
struct intel_ring_buffer *ring)
{
struct drm_i915_private *dev_priv = dev->dev_private;
- u32 seqno = ring->get_seqno(ring);
+ u32 seqno;
+ if (ring->obj == NULL)
+ return;
+
+ seqno = ring->get_seqno(ring);
trace_i915_gem_request_complete(dev, seqno);
ring->irq_seqno = seqno;
@@ -720,7 +735,7 @@ i915_error_first_batchbuffer(struct drm_i915_private *dev_priv,
if (obj->ring != ring)
continue;
- if (!i915_seqno_passed(obj->last_rendering_seqno, seqno))
+ if (i915_seqno_passed(seqno, obj->last_rendering_seqno))
continue;
if ((obj->base.read_domains & I915_GEM_DOMAIN_COMMAND) == 0)
@@ -831,6 +846,8 @@ static void i915_capture_error_state(struct drm_device *dev)
i++;
error->pinned_bo_count = i - error->active_bo_count;
+ error->active_bo = NULL;
+ error->pinned_bo = NULL;
if (i) {
error->active_bo = kmalloc(sizeof(*error->active_bo)*i,
GFP_ATOMIC);
@@ -1278,12 +1295,12 @@ static int i915_wait_irq(struct drm_device * dev, int irq_nr)
if (master_priv->sarea_priv)
master_priv->sarea_priv->perf_boxes |= I915_BOX_WAIT;
- ret = -ENODEV;
if (ring->irq_get(ring)) {
DRM_WAIT_ON(ret, ring->irq_queue, 3 * DRM_HZ,
READ_BREADCRUMB(dev_priv) >= irq_nr);
ring->irq_put(ring);
- }
+ } else if (wait_for(READ_BREADCRUMB(dev_priv) >= irq_nr, 3000))
+ ret = -EBUSY;
if (ret == -EBUSY) {
DRM_ERROR("EBUSY -- rec: %d emitted: %d\n",
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index 40a407f..5cfc689 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -513,6 +513,10 @@
#define GEN6_BLITTER_SYNC_STATUS (1 << 24)
#define GEN6_BLITTER_USER_INTERRUPT (1 << 22)
+#define GEN6_BLITTER_ECOSKPD 0x221d0
+#define GEN6_BLITTER_LOCK_SHIFT 16
+#define GEN6_BLITTER_FBC_NOTIFY (1<<3)
+
#define GEN6_BSD_SLEEP_PSMI_CONTROL 0x12050
#define GEN6_BSD_SLEEP_PSMI_CONTROL_RC_ILDL_MESSAGE_MODIFY_MASK (1 << 16)
#define GEN6_BSD_SLEEP_PSMI_CONTROL_RC_ILDL_MESSAGE_DISABLE (1 << 0)
@@ -2626,6 +2630,8 @@
#define DISPLAY_PORT_PLL_BIOS_2 0x46014
#define PCH_DSPCLK_GATE_D 0x42020
+# define DPFCUNIT_CLOCK_GATE_DISABLE (1 << 9)
+# define DPFCRUNIT_CLOCK_GATE_DISABLE (1 << 8)
# define DPFDUNIT_CLOCK_GATE_DISABLE (1 << 7)
# define DPARBUNIT_CLOCK_GATE_DISABLE (1 << 5)
diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c
index b0b1200..0b44956 100644
--- a/drivers/gpu/drm/i915/intel_bios.c
+++ b/drivers/gpu/drm/i915/intel_bios.c
@@ -264,17 +264,12 @@ parse_general_features(struct drm_i915_private *dev_priv,
dev_priv->int_crt_support = general->int_crt_support;
dev_priv->lvds_use_ssc = general->enable_ssc;
- if (dev_priv->lvds_use_ssc) {
- if (IS_I85X(dev))
- dev_priv->lvds_ssc_freq =
- general->ssc_freq ? 66 : 48;
- else if (IS_GEN5(dev) || IS_GEN6(dev))
- dev_priv->lvds_ssc_freq =
- general->ssc_freq ? 100 : 120;
- else
- dev_priv->lvds_ssc_freq =
- general->ssc_freq ? 100 : 96;
- }
+ if (IS_I85X(dev))
+ dev_priv->lvds_ssc_freq = general->ssc_freq ? 66 : 48;
+ else if (IS_GEN5(dev) || IS_GEN6(dev))
+ dev_priv->lvds_ssc_freq = general->ssc_freq ? 100 : 120;
+ else
+ dev_priv->lvds_ssc_freq = general->ssc_freq ? 100 : 96;
}
}
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 25d9688..d7f237d 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -1213,6 +1213,26 @@ static bool g4x_fbc_enabled(struct drm_device *dev)
return I915_READ(DPFC_CONTROL) & DPFC_CTL_EN;
}
+static void sandybridge_blit_fbc_update(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ u32 blt_ecoskpd;
+
+ /* Make sure blitter notifies FBC of writes */
+ __gen6_force_wake_get(dev_priv);
+ blt_ecoskpd = I915_READ(GEN6_BLITTER_ECOSKPD);
+ blt_ecoskpd |= GEN6_BLITTER_FBC_NOTIFY <<
+ GEN6_BLITTER_LOCK_SHIFT;
+ I915_WRITE(GEN6_BLITTER_ECOSKPD, blt_ecoskpd);
+ blt_ecoskpd |= GEN6_BLITTER_FBC_NOTIFY;
+ I915_WRITE(GEN6_BLITTER_ECOSKPD, blt_ecoskpd);
+ blt_ecoskpd &= ~(GEN6_BLITTER_FBC_NOTIFY <<
+ GEN6_BLITTER_LOCK_SHIFT);
+ I915_WRITE(GEN6_BLITTER_ECOSKPD, blt_ecoskpd);
+ POSTING_READ(GEN6_BLITTER_ECOSKPD);
+ __gen6_force_wake_put(dev_priv);
+}
+
static void ironlake_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
{
struct drm_device *dev = crtc->dev;
@@ -1266,6 +1286,7 @@ static void ironlake_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
I915_WRITE(SNB_DPFC_CTL_SA,
SNB_CPU_FENCE_ENABLE | dev_priv->cfb_fence);
I915_WRITE(DPFC_CPU_FENCE_OFFSET, crtc->y);
+ sandybridge_blit_fbc_update(dev);
}
DRM_DEBUG_KMS("enabled fbc on plane %d\n", intel_crtc->plane);
@@ -3822,6 +3843,11 @@ static void intel_update_watermarks(struct drm_device *dev)
sr_hdisplay, sr_htotal, pixel_size);
}
+static inline bool intel_panel_use_ssc(struct drm_i915_private *dev_priv)
+{
+ return dev_priv->lvds_use_ssc && i915_panel_use_ssc;
+}
+
static int intel_crtc_mode_set(struct drm_crtc *crtc,
struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode,
@@ -3884,7 +3910,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
num_connectors++;
}
- if (is_lvds && dev_priv->lvds_use_ssc && num_connectors < 2) {
+ 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);
@@ -4059,7 +4085,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
udelay(200);
if (has_edp_encoder) {
- if (dev_priv->lvds_use_ssc) {
+ if (intel_panel_use_ssc(dev_priv)) {
temp |= DREF_SSC1_ENABLE;
I915_WRITE(PCH_DREF_CONTROL, temp);
@@ -4070,13 +4096,13 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
/* Enable CPU source on CPU attached eDP */
if (!intel_encoder_is_pch_edp(&has_edp_encoder->base)) {
- if (dev_priv->lvds_use_ssc)
+ if (intel_panel_use_ssc(dev_priv))
temp |= DREF_CPU_SOURCE_OUTPUT_DOWNSPREAD;
else
temp |= DREF_CPU_SOURCE_OUTPUT_NONSPREAD;
} else {
/* Enable SSC on PCH eDP if needed */
- if (dev_priv->lvds_use_ssc) {
+ if (intel_panel_use_ssc(dev_priv)) {
DRM_ERROR("enabling SSC on PCH\n");
temp |= DREF_SUPERSPREAD_SOURCE_ENABLE;
}
@@ -4104,7 +4130,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
int factor = 21;
if (is_lvds) {
- if ((dev_priv->lvds_use_ssc &&
+ if ((intel_panel_use_ssc(dev_priv) &&
dev_priv->lvds_ssc_freq == 100) ||
(I915_READ(PCH_LVDS) & LVDS_CLKB_POWER_MASK) == LVDS_CLKB_POWER_UP)
factor = 25;
@@ -4183,7 +4209,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
/* XXX: just matching BIOS for now */
/* dpll |= PLL_REF_INPUT_TVCLKINBC; */
dpll |= 3;
- else if (is_lvds && dev_priv->lvds_use_ssc && num_connectors < 2)
+ else if (is_lvds && intel_panel_use_ssc(dev_priv) && num_connectors < 2)
dpll |= PLLB_REF_INPUT_SPREADSPECTRUMIN;
else
dpll |= PLL_REF_INPUT_DREFCLK;
@@ -6281,7 +6307,9 @@ void intel_enable_clock_gating(struct drm_device *dev)
if (IS_GEN5(dev)) {
/* Required for FBC */
- dspclk_gate |= DPFDUNIT_CLOCK_GATE_DISABLE;
+ dspclk_gate |= DPFCUNIT_CLOCK_GATE_DISABLE |
+ DPFCRUNIT_CLOCK_GATE_DISABLE |
+ DPFDUNIT_CLOCK_GATE_DISABLE;
/* Required for CxSR */
dspclk_gate |= DPARBUNIT_CLOCK_GATE_DISABLE;
diff --git a/drivers/gpu/drm/i915/intel_fb.c b/drivers/gpu/drm/i915/intel_fb.c
index ee145a2..5127827 100644
--- a/drivers/gpu/drm/i915/intel_fb.c
+++ b/drivers/gpu/drm/i915/intel_fb.c
@@ -148,6 +148,7 @@ static int intelfb_create(struct intel_fbdev *ifbdev,
// memset(info->screen_base, 0, size);
+ drm_fb_helper_fill_fix(info, fb->pitch, fb->depth);
drm_fb_helper_fill_var(info, &ifbdev->helper, sizes->fb_width, sizes->fb_height);
info->pixmap.size = 64*1024;
diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c
index 8f4f6bd..ace8d5d 100644
--- a/drivers/gpu/drm/i915/intel_lvds.c
+++ b/drivers/gpu/drm/i915/intel_lvds.c
@@ -704,6 +704,14 @@ static const struct dmi_system_id intel_no_lvds[] = {
},
{
.callback = intel_no_lvds_dmi_callback,
+ .ident = "AOpen i915GMm-HFS",
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "AOpen"),
+ DMI_MATCH(DMI_BOARD_NAME, "i915GMm-HFS"),
+ },
+ },
+ {
+ .callback = intel_no_lvds_dmi_callback,
.ident = "Aopen i945GTt-VFA",
.matches = {
DMI_MATCH(DMI_PRODUCT_VERSION, "AO00001JW"),
diff --git a/drivers/gpu/drm/i915/intel_opregion.c b/drivers/gpu/drm/i915/intel_opregion.c
index f295a7a..64fd644 100644
--- a/drivers/gpu/drm/i915/intel_opregion.c
+++ b/drivers/gpu/drm/i915/intel_opregion.c
@@ -26,6 +26,7 @@
*/
#include <linux/acpi.h>
+#include <linux/acpi_io.h>
#include <acpi/video.h>
#include "drmP.h"
@@ -476,7 +477,7 @@ int intel_opregion_setup(struct drm_device *dev)
return -ENOTSUPP;
}
- base = ioremap(asls, OPREGION_SIZE);
+ base = acpi_os_ioremap(asls, OPREGION_SIZE);
if (!base)
return -ENOMEM;
diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c
index e00d200..c65992d 100644
--- a/drivers/gpu/drm/i915/intel_panel.c
+++ b/drivers/gpu/drm/i915/intel_panel.c
@@ -278,6 +278,6 @@ void intel_panel_setup_backlight(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
- dev_priv->backlight_level = intel_panel_get_max_backlight(dev);
+ dev_priv->backlight_level = intel_panel_get_backlight(dev);
dev_priv->backlight_enabled = dev_priv->backlight_level != 0;
}
diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c
index 03e3370..6218fa9 100644
--- a/drivers/gpu/drm/i915/intel_ringbuffer.c
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.c
@@ -34,6 +34,14 @@
#include "i915_trace.h"
#include "intel_drv.h"
+static inline int ring_space(struct intel_ring_buffer *ring)
+{
+ int space = (ring->head & HEAD_ADDR) - (ring->tail + 8);
+ if (space < 0)
+ space += ring->size;
+ return space;
+}
+
static u32 i915_gem_get_seqno(struct drm_device *dev)
{
drm_i915_private_t *dev_priv = dev->dev_private;
@@ -204,11 +212,9 @@ static int init_ring_common(struct intel_ring_buffer *ring)
if (!drm_core_check_feature(ring->dev, DRIVER_MODESET))
i915_kernel_lost_context(ring->dev);
else {
- ring->head = I915_READ_HEAD(ring) & HEAD_ADDR;
+ ring->head = I915_READ_HEAD(ring);
ring->tail = I915_READ_TAIL(ring) & TAIL_ADDR;
- ring->space = ring->head - (ring->tail + 8);
- if (ring->space < 0)
- ring->space += ring->size;
+ ring->space = ring_space(ring);
}
return 0;
@@ -921,7 +927,7 @@ static int intel_wrap_ring_buffer(struct intel_ring_buffer *ring)
}
ring->tail = 0;
- ring->space = ring->head - 8;
+ ring->space = ring_space(ring);
return 0;
}
@@ -933,20 +939,22 @@ int intel_wait_ring_buffer(struct intel_ring_buffer *ring, int n)
unsigned long end;
u32 head;
+ /* If the reported head position has wrapped or hasn't advanced,
+ * fallback to the slow and accurate path.
+ */
+ head = intel_read_status_page(ring, 4);
+ if (head > ring->head) {
+ ring->head = head;
+ ring->space = ring_space(ring);
+ if (ring->space >= n)
+ return 0;
+ }
+
trace_i915_ring_wait_begin (dev);
end = jiffies + 3 * HZ;
do {
- /* If the reported head position has wrapped or hasn't advanced,
- * fallback to the slow and accurate path.
- */
- head = intel_read_status_page(ring, 4);
- if (head < ring->actual_head)
- head = I915_READ_HEAD(ring);
- ring->actual_head = head;
- ring->head = head & HEAD_ADDR;
- ring->space = ring->head - (ring->tail + 8);
- if (ring->space < 0)
- ring->space += ring->size;
+ ring->head = I915_READ_HEAD(ring);
+ ring->space = ring_space(ring);
if (ring->space >= n) {
trace_i915_ring_wait_end(dev);
return 0;
@@ -1291,6 +1299,48 @@ int intel_init_render_ring_buffer(struct drm_device *dev)
return intel_init_ring_buffer(dev, ring);
}
+int intel_render_ring_init_dri(struct drm_device *dev, u64 start, u32 size)
+{
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ struct intel_ring_buffer *ring = &dev_priv->ring[RCS];
+
+ *ring = render_ring;
+ if (INTEL_INFO(dev)->gen >= 6) {
+ ring->add_request = gen6_add_request;
+ ring->irq_get = gen6_render_ring_get_irq;
+ ring->irq_put = gen6_render_ring_put_irq;
+ } else if (IS_GEN5(dev)) {
+ ring->add_request = pc_render_add_request;
+ ring->get_seqno = pc_render_get_seqno;
+ }
+
+ ring->dev = dev;
+ INIT_LIST_HEAD(&ring->active_list);
+ INIT_LIST_HEAD(&ring->request_list);
+ INIT_LIST_HEAD(&ring->gpu_write_list);
+
+ ring->size = size;
+ ring->effective_size = ring->size;
+ if (IS_I830(ring->dev))
+ ring->effective_size -= 128;
+
+ ring->map.offset = start;
+ ring->map.size = size;
+ ring->map.type = 0;
+ ring->map.flags = 0;
+ ring->map.mtrr = 0;
+
+ drm_core_ioremap_wc(&ring->map, dev);
+ if (ring->map.handle == NULL) {
+ DRM_ERROR("can not ioremap virtual address for"
+ " ring buffer\n");
+ return -ENOMEM;
+ }
+
+ ring->virtual_start = (void __force __iomem *)ring->map.handle;
+ return 0;
+}
+
int intel_init_bsd_ring_buffer(struct drm_device *dev)
{
drm_i915_private_t *dev_priv = dev->dev_private;
diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h
index be9087e..6d6fde8 100644
--- a/drivers/gpu/drm/i915/intel_ringbuffer.h
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.h
@@ -47,7 +47,6 @@ struct intel_ring_buffer {
struct drm_device *dev;
struct drm_i915_gem_object *obj;
- u32 actual_head;
u32 head;
u32 tail;
int space;
@@ -167,4 +166,7 @@ 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);
+/* DRI warts */
+int intel_render_ring_init_dri(struct drm_device *dev, u64 start, u32 size);
+
#endif /* _INTEL_RINGBUFFER_H_ */
diff --git a/drivers/gpu/drm/nouveau/Kconfig b/drivers/gpu/drm/nouveau/Kconfig
index 21d6c29..de70959 100644
--- a/drivers/gpu/drm/nouveau/Kconfig
+++ b/drivers/gpu/drm/nouveau/Kconfig
@@ -8,7 +8,7 @@ config DRM_NOUVEAU
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
select FB
- select FRAMEBUFFER_CONSOLE if !EMBEDDED
+ select FRAMEBUFFER_CONSOLE if !EXPERT
select FB_BACKLIGHT if DRM_NOUVEAU_BACKLIGHT
select ACPI_VIDEO if ACPI && X86 && BACKLIGHT_CLASS_DEVICE && VIDEO_OUTPUT_CONTROL && INPUT
help
diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h
index 46e3257..01bffc4 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drv.h
+++ b/drivers/gpu/drm/nouveau/nouveau_drv.h
@@ -160,6 +160,7 @@ enum nouveau_flags {
#define NVOBJ_FLAG_ZERO_ALLOC (1 << 1)
#define NVOBJ_FLAG_ZERO_FREE (1 << 2)
#define NVOBJ_FLAG_VM (1 << 3)
+#define NVOBJ_FLAG_VM_USER (1 << 4)
#define NVOBJ_CINST_GLOBAL 0xdeadbeef
@@ -1576,6 +1577,20 @@ nv_match_device(struct drm_device *dev, unsigned device,
dev->pdev->subsystem_device == sub_device;
}
+/* returns 1 if device is one of the nv4x using the 0x4497 object class,
+ * helpful to determine a number of other hardware features
+ */
+static inline int
+nv44_graph_class(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+
+ if ((dev_priv->chipset & 0xf0) == 0x60)
+ return 1;
+
+ return !(0x0baf & (1 << (dev_priv->chipset & 0x0f)));
+}
+
/* memory type/access flags, do not match hardware values */
#define NV_MEM_ACCESS_RO 1
#define NV_MEM_ACCESS_WO 2
diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.c b/drivers/gpu/drm/nouveau/nouveau_fbcon.c
index a26d047..60769d2 100644
--- a/drivers/gpu/drm/nouveau/nouveau_fbcon.c
+++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.c
@@ -352,13 +352,14 @@ nouveau_fbcon_create(struct nouveau_fbdev *nfbdev,
FBINFO_HWACCEL_IMAGEBLIT;
info->flags |= FBINFO_CAN_FORCE_OUTPUT;
info->fbops = &nouveau_fbcon_sw_ops;
- info->fix.smem_start = dev->mode_config.fb_base +
- (nvbo->bo.mem.start << PAGE_SHIFT);
+ info->fix.smem_start = nvbo->bo.mem.bus.base +
+ nvbo->bo.mem.bus.offset;
info->fix.smem_len = size;
info->screen_base = nvbo_kmap_obj_iovirtual(nouveau_fb->nvbo);
info->screen_size = size;
+ drm_fb_helper_fill_fix(info, fb->pitch, fb->depth);
drm_fb_helper_fill_var(info, &nfbdev->helper, sizes->fb_width, sizes->fb_height);
/* Set aperture base/size for vesafb takeover */
diff --git a/drivers/gpu/drm/nouveau/nouveau_mem.c b/drivers/gpu/drm/nouveau/nouveau_mem.c
index 69044eb..26347b7 100644
--- a/drivers/gpu/drm/nouveau/nouveau_mem.c
+++ b/drivers/gpu/drm/nouveau/nouveau_mem.c
@@ -742,30 +742,24 @@ nouveau_vram_manager_debug(struct ttm_mem_type_manager *man, const char *prefix)
{
struct nouveau_mm *mm = man->priv;
struct nouveau_mm_node *r;
- u64 total = 0, ttotal[3] = {}, tused[3] = {}, tfree[3] = {};
- int i;
+ u32 total = 0, free = 0;
mutex_lock(&mm->mutex);
list_for_each_entry(r, &mm->nodes, nl_entry) {
- printk(KERN_DEBUG "%s %s-%d: 0x%010llx 0x%010llx\n",
- prefix, r->free ? "free" : "used", r->type,
- ((u64)r->offset << 12),
+ printk(KERN_DEBUG "%s %d: 0x%010llx 0x%010llx\n",
+ prefix, r->type, ((u64)r->offset << 12),
(((u64)r->offset + r->length) << 12));
+
total += r->length;
- ttotal[r->type] += r->length;
- if (r->free)
- tfree[r->type] += r->length;
- else
- tused[r->type] += r->length;
+ if (!r->type)
+ free += r->length;
}
mutex_unlock(&mm->mutex);
- printk(KERN_DEBUG "%s total: 0x%010llx\n", prefix, total << 12);
- for (i = 0; i < 3; i++) {
- printk(KERN_DEBUG "%s type %d: 0x%010llx, "
- "used 0x%010llx, free 0x%010llx\n", prefix,
- i, ttotal[i] << 12, tused[i] << 12, tfree[i] << 12);
- }
+ printk(KERN_DEBUG "%s total: 0x%010llx free: 0x%010llx\n",
+ prefix, (u64)total << 12, (u64)free << 12);
+ printk(KERN_DEBUG "%s block: 0x%08x\n",
+ prefix, mm->block_size << 12);
}
const struct ttm_mem_type_manager_func nouveau_vram_manager = {
diff --git a/drivers/gpu/drm/nouveau/nouveau_mm.c b/drivers/gpu/drm/nouveau/nouveau_mm.c
index cdbb11e..8844b50 100644
--- a/drivers/gpu/drm/nouveau/nouveau_mm.c
+++ b/drivers/gpu/drm/nouveau/nouveau_mm.c
@@ -48,175 +48,76 @@ region_split(struct nouveau_mm *rmm, struct nouveau_mm_node *a, u32 size)
b->offset = a->offset;
b->length = size;
- b->free = a->free;
b->type = a->type;
a->offset += size;
a->length -= size;
list_add_tail(&b->nl_entry, &a->nl_entry);
- if (b->free)
+ if (b->type == 0)
list_add_tail(&b->fl_entry, &a->fl_entry);
return b;
}
-static struct nouveau_mm_node *
-nouveau_mm_merge(struct nouveau_mm *rmm, struct nouveau_mm_node *this)
-{
- struct nouveau_mm_node *prev, *next;
-
- /* try to merge with free adjacent entries of same type */
- prev = list_entry(this->nl_entry.prev, struct nouveau_mm_node, nl_entry);
- if (this->nl_entry.prev != &rmm->nodes) {
- if (prev->free && prev->type == this->type) {
- prev->length += this->length;
- region_put(rmm, this);
- this = prev;
- }
- }
-
- next = list_entry(this->nl_entry.next, struct nouveau_mm_node, nl_entry);
- if (this->nl_entry.next != &rmm->nodes) {
- if (next->free && next->type == this->type) {
- next->offset = this->offset;
- next->length += this->length;
- region_put(rmm, this);
- this = next;
- }
- }
-
- return this;
-}
+#define node(root, dir) ((root)->nl_entry.dir == &rmm->nodes) ? NULL : \
+ list_entry((root)->nl_entry.dir, struct nouveau_mm_node, nl_entry)
void
nouveau_mm_put(struct nouveau_mm *rmm, struct nouveau_mm_node *this)
{
- u32 block_s, block_l;
+ struct nouveau_mm_node *prev = node(this, prev);
+ struct nouveau_mm_node *next = node(this, next);
- this->free = true;
list_add(&this->fl_entry, &rmm->free);
- this = nouveau_mm_merge(rmm, this);
-
- /* any entirely free blocks now? we'll want to remove typing
- * on them now so they can be use for any memory allocation
- */
- block_s = roundup(this->offset, rmm->block_size);
- if (block_s + rmm->block_size > this->offset + this->length)
- return;
+ this->type = 0;
- /* split off any still-typed region at the start */
- if (block_s != this->offset) {
- if (!region_split(rmm, this, block_s - this->offset))
- return;
+ if (prev && prev->type == 0) {
+ prev->length += this->length;
+ region_put(rmm, this);
+ this = prev;
}
- /* split off the soon-to-be-untyped block(s) */
- block_l = rounddown(this->length, rmm->block_size);
- if (block_l != this->length) {
- this = region_split(rmm, this, block_l);
- if (!this)
- return;
+ if (next && next->type == 0) {
+ next->offset = this->offset;
+ next->length += this->length;
+ region_put(rmm, this);
}
-
- /* mark as having no type, and retry merge with any adjacent
- * untyped blocks
- */
- this->type = 0;
- nouveau_mm_merge(rmm, this);
}
int
nouveau_mm_get(struct nouveau_mm *rmm, int type, u32 size, u32 size_nc,
u32 align, struct nouveau_mm_node **pnode)
{
- struct nouveau_mm_node *this, *tmp, *next;
- u32 splitoff, avail, alloc;
-
- list_for_each_entry_safe(this, tmp, &rmm->free, fl_entry) {
- next = list_entry(this->nl_entry.next, struct nouveau_mm_node, nl_entry);
- if (this->nl_entry.next == &rmm->nodes)
- next = NULL;
-
- /* skip wrongly typed blocks */
- if (this->type && this->type != type)
+ struct nouveau_mm_node *prev, *this, *next;
+ u32 min = size_nc ? size_nc : size;
+ u32 align_mask = align - 1;
+ u32 splitoff;
+ u32 s, e;
+
+ list_for_each_entry(this, &rmm->free, fl_entry) {
+ e = this->offset + this->length;
+ s = this->offset;
+
+ prev = node(this, prev);
+ if (prev && prev->type != type)
+ s = roundup(s, rmm->block_size);
+
+ next = node(this, next);
+ if (next && next->type != type)
+ e = rounddown(e, rmm->block_size);
+
+ s = (s + align_mask) & ~align_mask;
+ e &= ~align_mask;
+ if (s > e || e - s < min)
continue;
- /* account for alignment */
- splitoff = this->offset & (align - 1);
- if (splitoff)
- splitoff = align - splitoff;
-
- if (this->length <= splitoff)
- continue;
-
- /* determine total memory available from this, and
- * the next block (if appropriate)
- */
- avail = this->length;
- if (next && next->free && (!next->type || next->type == type))
- avail += next->length;
-
- avail -= splitoff;
-
- /* determine allocation size */
- if (size_nc) {
- alloc = min(avail, size);
- alloc = rounddown(alloc, size_nc);
- if (alloc == 0)
- continue;
- } else {
- alloc = size;
- if (avail < alloc)
- continue;
- }
-
- /* untyped block, split off a chunk that's a multiple
- * of block_size and type it
- */
- if (!this->type) {
- u32 block = roundup(alloc + splitoff, rmm->block_size);
- if (this->length < block)
- continue;
-
- this = region_split(rmm, this, block);
- if (!this)
- return -ENOMEM;
-
- this->type = type;
- }
-
- /* stealing memory from adjacent block */
- if (alloc > this->length) {
- u32 amount = alloc - (this->length - splitoff);
-
- if (!next->type) {
- amount = roundup(amount, rmm->block_size);
-
- next = region_split(rmm, next, amount);
- if (!next)
- return -ENOMEM;
-
- next->type = type;
- }
-
- this->length += amount;
- next->offset += amount;
- next->length -= amount;
- if (!next->length) {
- list_del(&next->nl_entry);
- list_del(&next->fl_entry);
- kfree(next);
- }
- }
-
- if (splitoff) {
- if (!region_split(rmm, this, splitoff))
- return -ENOMEM;
- }
+ splitoff = s - this->offset;
+ if (splitoff && !region_split(rmm, this, splitoff))
+ return -ENOMEM;
- this = region_split(rmm, this, alloc);
- if (this == NULL)
+ this = region_split(rmm, this, min(size, e - s));
+ if (!this)
return -ENOMEM;
- this->free = false;
+ this->type = type;
list_del(&this->fl_entry);
*pnode = this;
return 0;
@@ -234,7 +135,6 @@ nouveau_mm_init(struct nouveau_mm **prmm, u32 offset, u32 length, u32 block)
heap = kzalloc(sizeof(*heap), GFP_KERNEL);
if (!heap)
return -ENOMEM;
- heap->free = true;
heap->offset = roundup(offset, block);
heap->length = rounddown(offset + length, block) - heap->offset;
diff --git a/drivers/gpu/drm/nouveau/nouveau_mm.h b/drivers/gpu/drm/nouveau/nouveau_mm.h
index af38449..798eaf3 100644
--- a/drivers/gpu/drm/nouveau/nouveau_mm.h
+++ b/drivers/gpu/drm/nouveau/nouveau_mm.h
@@ -30,9 +30,7 @@ struct nouveau_mm_node {
struct list_head fl_entry;
struct list_head rl_entry;
- bool free;
- int type;
-
+ u8 type;
u32 offset;
u32 length;
};
diff --git a/drivers/gpu/drm/nouveau/nv40_graph.c b/drivers/gpu/drm/nouveau/nv40_graph.c
index 19ef92a..8870d72 100644
--- a/drivers/gpu/drm/nouveau/nv40_graph.c
+++ b/drivers/gpu/drm/nouveau/nv40_graph.c
@@ -451,8 +451,7 @@ nv40_graph_register(struct drm_device *dev)
NVOBJ_CLASS(dev, 0x309e, GR); /* swzsurf */
/* curie */
- if (dev_priv->chipset >= 0x60 ||
- 0x00005450 & (1 << (dev_priv->chipset & 0x0f)))
+ if (nv44_graph_class(dev))
NVOBJ_CLASS(dev, 0x4497, GR);
else
NVOBJ_CLASS(dev, 0x4097, GR);
diff --git a/drivers/gpu/drm/nouveau/nv40_grctx.c b/drivers/gpu/drm/nouveau/nv40_grctx.c
index ce58509..f70447d 100644
--- a/drivers/gpu/drm/nouveau/nv40_grctx.c
+++ b/drivers/gpu/drm/nouveau/nv40_grctx.c
@@ -118,17 +118,6 @@
*/
static int
-nv40_graph_4097(struct drm_device *dev)
-{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
-
- if ((dev_priv->chipset & 0xf0) == 0x60)
- return 0;
-
- return !!(0x0baf & (1 << dev_priv->chipset));
-}
-
-static int
nv40_graph_vs_count(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
@@ -219,7 +208,7 @@ nv40_graph_construct_general(struct nouveau_grctx *ctx)
gr_def(ctx, 0x4009dc, 0x80000000);
} else {
cp_ctx(ctx, 0x400840, 20);
- if (!nv40_graph_4097(ctx->dev)) {
+ if (nv44_graph_class(ctx->dev)) {
for (i = 0; i < 8; i++)
gr_def(ctx, 0x400860 + (i * 4), 0x00000001);
}
@@ -228,7 +217,7 @@ nv40_graph_construct_general(struct nouveau_grctx *ctx)
gr_def(ctx, 0x400888, 0x00000040);
cp_ctx(ctx, 0x400894, 11);
gr_def(ctx, 0x400894, 0x00000040);
- if (nv40_graph_4097(ctx->dev)) {
+ if (!nv44_graph_class(ctx->dev)) {
for (i = 0; i < 8; i++)
gr_def(ctx, 0x4008a0 + (i * 4), 0x80000000);
}
@@ -546,7 +535,7 @@ nv40_graph_construct_state3d_2(struct nouveau_grctx *ctx)
static void
nv40_graph_construct_state3d_3(struct nouveau_grctx *ctx)
{
- int len = nv40_graph_4097(ctx->dev) ? 0x0684 : 0x0084;
+ int len = nv44_graph_class(ctx->dev) ? 0x0084 : 0x0684;
cp_out (ctx, 0x300000);
cp_lsr (ctx, len - 4);
@@ -582,11 +571,11 @@ nv40_graph_construct_shader(struct nouveau_grctx *ctx)
} else {
b0_offset = 0x1d40/4; /* 2200 */
b1_offset = 0x3f40/4; /* 0b00 : 0a40 */
- vs_len = nv40_graph_4097(dev) ? 0x4a40/4 : 0x4980/4;
+ vs_len = nv44_graph_class(dev) ? 0x4980/4 : 0x4a40/4;
}
cp_lsr(ctx, vs_len * vs_nr + 0x300/4);
- cp_out(ctx, nv40_graph_4097(dev) ? 0x800041 : 0x800029);
+ cp_out(ctx, nv44_graph_class(dev) ? 0x800029 : 0x800041);
offset = ctx->ctxvals_pos;
ctx->ctxvals_pos += (0x0300/4 + (vs_nr * vs_len));
diff --git a/drivers/gpu/drm/nouveau/nv40_mc.c b/drivers/gpu/drm/nouveau/nv40_mc.c
index e4e72c1..03c0d4c 100644
--- a/drivers/gpu/drm/nouveau/nv40_mc.c
+++ b/drivers/gpu/drm/nouveau/nv40_mc.c
@@ -6,27 +6,17 @@
int
nv40_mc_init(struct drm_device *dev)
{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- uint32_t tmp;
-
/* Power up everything, resetting each individual unit will
* be done later if needed.
*/
nv_wr32(dev, NV03_PMC_ENABLE, 0xFFFFFFFF);
- switch (dev_priv->chipset) {
- case 0x44:
- case 0x46: /* G72 */
- case 0x4e:
- case 0x4c: /* C51_G7X */
- tmp = nv_rd32(dev, NV04_PFB_FIFO_DATA);
+ if (nv44_graph_class(dev)) {
+ u32 tmp = nv_rd32(dev, NV04_PFB_FIFO_DATA);
nv_wr32(dev, NV40_PMC_1700, tmp);
nv_wr32(dev, NV40_PMC_1704, 0);
nv_wr32(dev, NV40_PMC_1708, 0);
nv_wr32(dev, NV40_PMC_170C, tmp);
- break;
- default:
- break;
}
return 0;
diff --git a/drivers/gpu/drm/nouveau/nv50_instmem.c b/drivers/gpu/drm/nouveau/nv50_instmem.c
index 2e1b1cd..ea00418 100644
--- a/drivers/gpu/drm/nouveau/nv50_instmem.c
+++ b/drivers/gpu/drm/nouveau/nv50_instmem.c
@@ -332,8 +332,11 @@ nv50_instmem_get(struct nouveau_gpuobj *gpuobj, u32 size, u32 align)
gpuobj->vinst = node->vram->offset;
if (gpuobj->flags & NVOBJ_FLAG_VM) {
- ret = nouveau_vm_get(dev_priv->chan_vm, size, 12,
- NV_MEM_ACCESS_RW | NV_MEM_ACCESS_SYS,
+ u32 flags = NV_MEM_ACCESS_RW;
+ if (!(gpuobj->flags & NVOBJ_FLAG_VM_USER))
+ flags |= NV_MEM_ACCESS_SYS;
+
+ ret = nouveau_vm_get(dev_priv->chan_vm, size, 12, flags,
&node->chan_vma);
if (ret) {
vram->put(dev, &node->vram);
diff --git a/drivers/gpu/drm/nouveau/nvc0_graph.c b/drivers/gpu/drm/nouveau/nvc0_graph.c
index 5feacd5..e6ea7d8 100644
--- a/drivers/gpu/drm/nouveau/nvc0_graph.c
+++ b/drivers/gpu/drm/nouveau/nvc0_graph.c
@@ -105,7 +105,8 @@ nvc0_graph_create_context_mmio_list(struct nouveau_channel *chan)
if (ret)
return ret;
- ret = nouveau_gpuobj_new(dev, NULL, 384 * 1024, 4096, NVOBJ_FLAG_VM,
+ ret = nouveau_gpuobj_new(dev, NULL, 384 * 1024, 4096,
+ NVOBJ_FLAG_VM | NVOBJ_FLAG_VM_USER,
&grch->unk418810);
if (ret)
return ret;
diff --git a/drivers/gpu/drm/nouveau/nvc0_vm.c b/drivers/gpu/drm/nouveau/nvc0_vm.c
index 4b9251b..e4e83c2 100644
--- a/drivers/gpu/drm/nouveau/nvc0_vm.c
+++ b/drivers/gpu/drm/nouveau/nvc0_vm.c
@@ -48,8 +48,8 @@ nvc0_vm_addr(struct nouveau_vma *vma, u64 phys, u32 memtype, u32 target)
phys >>= 8;
phys |= 0x00000001; /* present */
-// if (vma->access & NV_MEM_ACCESS_SYS)
-// phys |= 0x00000002;
+ if (vma->access & NV_MEM_ACCESS_SYS)
+ phys |= 0x00000002;
phys |= ((u64)target << 32);
phys |= ((u64)memtype << 36);
diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c
index b0ab185..d3ca170 100644
--- a/drivers/gpu/drm/radeon/atombios_crtc.c
+++ b/drivers/gpu/drm/radeon/atombios_crtc.c
@@ -606,14 +606,9 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc,
args.v1.usPixelClock = cpu_to_le16(mode->clock / 10);
args.v1.ucTransmitterID = radeon_encoder->encoder_id;
args.v1.ucEncodeMode = encoder_mode;
- if (encoder_mode == ATOM_ENCODER_MODE_DP) {
- if (ss_enabled)
- args.v1.ucConfig |=
- ADJUST_DISPLAY_CONFIG_SS_ENABLE;
- } else if (encoder_mode == ATOM_ENCODER_MODE_LVDS) {
+ if (ss_enabled)
args.v1.ucConfig |=
ADJUST_DISPLAY_CONFIG_SS_ENABLE;
- }
atom_execute_table(rdev->mode_info.atom_context,
index, (uint32_t *)&args);
@@ -624,12 +619,12 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc,
args.v3.sInput.ucTransmitterID = radeon_encoder->encoder_id;
args.v3.sInput.ucEncodeMode = encoder_mode;
args.v3.sInput.ucDispPllConfig = 0;
+ if (ss_enabled)
+ args.v3.sInput.ucDispPllConfig |=
+ DISPPLL_CONFIG_SS_ENABLE;
if (radeon_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) {
struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
if (encoder_mode == ATOM_ENCODER_MODE_DP) {
- if (ss_enabled)
- args.v3.sInput.ucDispPllConfig |=
- DISPPLL_CONFIG_SS_ENABLE;
args.v3.sInput.ucDispPllConfig |=
DISPPLL_CONFIG_COHERENT_MODE;
/* 16200 or 27000 */
@@ -649,18 +644,11 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc,
}
} else if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) {
if (encoder_mode == ATOM_ENCODER_MODE_DP) {
- if (ss_enabled)
- args.v3.sInput.ucDispPllConfig |=
- DISPPLL_CONFIG_SS_ENABLE;
args.v3.sInput.ucDispPllConfig |=
DISPPLL_CONFIG_COHERENT_MODE;
/* 16200 or 27000 */
args.v3.sInput.usPixelClock = cpu_to_le16(dp_clock / 10);
- } else if (encoder_mode == ATOM_ENCODER_MODE_LVDS) {
- if (ss_enabled)
- args.v3.sInput.ucDispPllConfig |=
- DISPPLL_CONFIG_SS_ENABLE;
- } else {
+ } else if (encoder_mode != ATOM_ENCODER_MODE_LVDS) {
if (mode->clock > 165000)
args.v3.sInput.ucDispPllConfig |=
DISPPLL_CONFIG_DUAL_LINK;
diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c
index 7fe8ebd..677af91 100644
--- a/drivers/gpu/drm/radeon/evergreen.c
+++ b/drivers/gpu/drm/radeon/evergreen.c
@@ -2201,6 +2201,9 @@ static int evergreen_gpu_soft_reset(struct radeon_device *rdev)
struct evergreen_mc_save save;
u32 grbm_reset = 0;
+ if (!(RREG32(GRBM_STATUS) & GUI_ACTIVE))
+ return 0;
+
dev_info(rdev->dev, "GPU softreset \n");
dev_info(rdev->dev, " GRBM_STATUS=0x%08X\n",
RREG32(GRBM_STATUS));
@@ -3002,31 +3005,6 @@ int evergreen_copy_blit(struct radeon_device *rdev,
return 0;
}
-static bool evergreen_card_posted(struct radeon_device *rdev)
-{
- u32 reg;
-
- /* first check CRTCs */
- if (rdev->flags & RADEON_IS_IGP)
- reg = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET) |
- RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET);
- else
- reg = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET) |
- RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET) |
- RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET) |
- RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET) |
- RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET) |
- RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET);
- if (reg & EVERGREEN_CRTC_MASTER_EN)
- return true;
-
- /* then check MEM_SIZE, in case the crtcs are off */
- if (RREG32(CONFIG_MEMSIZE))
- return true;
-
- return false;
-}
-
/* Plan is to move initialization in that function and use
* helper function so that radeon_device_init pretty much
* do nothing more than calling asic specific function. This
@@ -3063,7 +3041,7 @@ int evergreen_init(struct radeon_device *rdev)
if (radeon_asic_reset(rdev))
dev_warn(rdev->dev, "GPU reset failed !\n");
/* Post card if necessary */
- if (!evergreen_card_posted(rdev)) {
+ if (!radeon_card_posted(rdev)) {
if (!rdev->bios) {
dev_err(rdev->dev, "Card not posted and no BIOS - ignoring\n");
return -EINVAL;
@@ -3158,6 +3136,9 @@ static void evergreen_pcie_gen2_enable(struct radeon_device *rdev)
{
u32 link_width_cntl, speed_cntl;
+ if (radeon_pcie_gen2 == 0)
+ return;
+
if (rdev->flags & RADEON_IS_IGP)
return;
diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c
index f637595..5968dde 100644
--- a/drivers/gpu/drm/radeon/r100.c
+++ b/drivers/gpu/drm/radeon/r100.c
@@ -2086,12 +2086,13 @@ int r100_asic_reset(struct radeon_device *rdev)
{
struct r100_mc_save save;
u32 status, tmp;
+ int ret = 0;
- r100_mc_stop(rdev, &save);
status = RREG32(R_000E40_RBBM_STATUS);
if (!G_000E40_GUI_ACTIVE(status)) {
return 0;
}
+ r100_mc_stop(rdev, &save);
status = RREG32(R_000E40_RBBM_STATUS);
dev_info(rdev->dev, "(%s:%d) RBBM_STATUS=0x%08X\n", __func__, __LINE__, status);
/* stop CP */
@@ -2131,11 +2132,11 @@ int r100_asic_reset(struct radeon_device *rdev)
G_000E40_TAM_BUSY(status) || G_000E40_PB_BUSY(status)) {
dev_err(rdev->dev, "failed to reset GPU\n");
rdev->gpu_lockup = true;
- return -1;
- }
+ ret = -1;
+ } else
+ dev_info(rdev->dev, "GPU reset succeed\n");
r100_mc_resume(rdev, &save);
- dev_info(rdev->dev, "GPU reset succeed\n");
- return 0;
+ return ret;
}
void r100_set_common_regs(struct radeon_device *rdev)
@@ -3521,7 +3522,7 @@ int r100_ring_test(struct radeon_device *rdev)
if (i < rdev->usec_timeout) {
DRM_INFO("ring test succeeded in %d usecs\n", i);
} else {
- DRM_ERROR("radeon: ring test failed (sracth(0x%04X)=0x%08X)\n",
+ DRM_ERROR("radeon: ring test failed (scratch(0x%04X)=0x%08X)\n",
scratch, tmp);
r = -EINVAL;
}
diff --git a/drivers/gpu/drm/radeon/r300.c b/drivers/gpu/drm/radeon/r300.c
index fae5e70..cf862ca 100644
--- a/drivers/gpu/drm/radeon/r300.c
+++ b/drivers/gpu/drm/radeon/r300.c
@@ -405,12 +405,13 @@ int r300_asic_reset(struct radeon_device *rdev)
{
struct r100_mc_save save;
u32 status, tmp;
+ int ret = 0;
- r100_mc_stop(rdev, &save);
status = RREG32(R_000E40_RBBM_STATUS);
if (!G_000E40_GUI_ACTIVE(status)) {
return 0;
}
+ r100_mc_stop(rdev, &save);
status = RREG32(R_000E40_RBBM_STATUS);
dev_info(rdev->dev, "(%s:%d) RBBM_STATUS=0x%08X\n", __func__, __LINE__, status);
/* stop CP */
@@ -451,11 +452,11 @@ int r300_asic_reset(struct radeon_device *rdev)
if (G_000E40_GA_BUSY(status) || G_000E40_VAP_BUSY(status)) {
dev_err(rdev->dev, "failed to reset GPU\n");
rdev->gpu_lockup = true;
- return -1;
- }
+ ret = -1;
+ } else
+ dev_info(rdev->dev, "GPU reset succeed\n");
r100_mc_resume(rdev, &save);
- dev_info(rdev->dev, "GPU reset succeed\n");
- return 0;
+ return ret;
}
/*
diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c
index 6b50716..1e10e3e 100644
--- a/drivers/gpu/drm/radeon/r600.c
+++ b/drivers/gpu/drm/radeon/r600.c
@@ -1287,6 +1287,9 @@ int r600_gpu_soft_reset(struct radeon_device *rdev)
S_008014_CB2_BUSY(1) | S_008014_CB3_BUSY(1);
u32 tmp;
+ if (!(RREG32(GRBM_STATUS) & GUI_ACTIVE))
+ return 0;
+
dev_info(rdev->dev, "GPU softreset \n");
dev_info(rdev->dev, " R_008010_GRBM_STATUS=0x%08X\n",
RREG32(R_008010_GRBM_STATUS));
@@ -2358,24 +2361,6 @@ void r600_clear_surface_reg(struct radeon_device *rdev, int reg)
/* FIXME: implement */
}
-
-bool r600_card_posted(struct radeon_device *rdev)
-{
- uint32_t reg;
-
- /* first check CRTCs */
- reg = RREG32(D1CRTC_CONTROL) |
- RREG32(D2CRTC_CONTROL);
- if (reg & CRTC_EN)
- return true;
-
- /* then check MEM_SIZE, in case the crtcs are off */
- if (RREG32(CONFIG_MEMSIZE))
- return true;
-
- return false;
-}
-
int r600_startup(struct radeon_device *rdev)
{
int r;
@@ -2536,7 +2521,7 @@ int r600_init(struct radeon_device *rdev)
if (r)
return r;
/* Post card if necessary */
- if (!r600_card_posted(rdev)) {
+ if (!radeon_card_posted(rdev)) {
if (!rdev->bios) {
dev_err(rdev->dev, "Card not posted and no BIOS - ignoring\n");
return -EINVAL;
@@ -3658,6 +3643,9 @@ static void r600_pcie_gen2_enable(struct radeon_device *rdev)
u32 link_width_cntl, lanes, speed_cntl, training_cntl, tmp;
u16 link_cntl2;
+ if (radeon_pcie_gen2 == 0)
+ return;
+
if (rdev->flags & RADEON_IS_IGP)
return;
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
index e948663..71d2a55 100644
--- a/drivers/gpu/drm/radeon/radeon.h
+++ b/drivers/gpu/drm/radeon/radeon.h
@@ -92,6 +92,7 @@ extern int radeon_tv;
extern int radeon_audio;
extern int radeon_disp_priority;
extern int radeon_hw_i2c;
+extern int radeon_pcie_gen2;
/*
* Copy from radeon_drv.h so we don't have to include both and have conflicting
diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c
index 1573202..5277790 100644
--- a/drivers/gpu/drm/radeon/radeon_atombios.c
+++ b/drivers/gpu/drm/radeon/radeon_atombios.c
@@ -387,15 +387,11 @@ static bool radeon_atom_apply_quirks(struct drm_device *dev,
*line_mux = 0x90;
}
- /* mac rv630 */
- if ((dev->pdev->device == 0x9588) &&
- (dev->pdev->subsystem_vendor == 0x106b) &&
- (dev->pdev->subsystem_device == 0x00a6)) {
- if ((supported_device == ATOM_DEVICE_TV1_SUPPORT) &&
- (*connector_type == DRM_MODE_CONNECTOR_DVII)) {
- *connector_type = DRM_MODE_CONNECTOR_9PinDIN;
- *line_mux = CONNECTOR_7PIN_DIN_ENUM_ID1;
- }
+ /* mac rv630, rv730, others */
+ if ((supported_device == ATOM_DEVICE_TV1_SUPPORT) &&
+ (*connector_type == DRM_MODE_CONNECTOR_DVII)) {
+ *connector_type = DRM_MODE_CONNECTOR_9PinDIN;
+ *line_mux = CONNECTOR_7PIN_DIN_ENUM_ID1;
}
/* ASUS HD 3600 XT board lists the DVI port as HDMI */
diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c
index be5cb4f..275b26a 100644
--- a/drivers/gpu/drm/radeon/radeon_drv.c
+++ b/drivers/gpu/drm/radeon/radeon_drv.c
@@ -48,7 +48,7 @@
* - 2.5.0 - add get accel 2 to work around ddx breakage for evergreen
* - 2.6.0 - add tiling config query (r6xx+), add initial HiZ support (r300->r500)
* 2.7.0 - fixups for r600 2D tiling support. (no external ABI change), add eg dyn gpr regs
- * 2.8.0 - pageflip support, r500 US_FORMAT regs. r500 ARGB2101010 colorbuf, r300->r500 CMASK
+ * 2.8.0 - pageflip support, r500 US_FORMAT regs. r500 ARGB2101010 colorbuf, r300->r500 CMASK, clock crystal query
*/
#define KMS_DRIVER_MAJOR 2
#define KMS_DRIVER_MINOR 8
@@ -104,6 +104,7 @@ int radeon_tv = 1;
int radeon_audio = 1;
int radeon_disp_priority = 0;
int radeon_hw_i2c = 0;
+int radeon_pcie_gen2 = 0;
MODULE_PARM_DESC(no_wb, "Disable AGP writeback for scratch registers");
module_param_named(no_wb, radeon_no_wb, int, 0444);
@@ -147,6 +148,9 @@ module_param_named(disp_priority, radeon_disp_priority, int, 0444);
MODULE_PARM_DESC(hw_i2c, "hw i2c engine enable (0 = disable)");
module_param_named(hw_i2c, radeon_hw_i2c, int, 0444);
+MODULE_PARM_DESC(pcie_gen2, "PCIE Gen2 mode (1 = enable)");
+module_param_named(pcie_gen2, radeon_pcie_gen2, int, 0444);
+
static int radeon_suspend(struct drm_device *dev, pm_message_t state)
{
drm_radeon_private_t *dev_priv = dev->dev_private;
diff --git a/drivers/gpu/drm/radeon/radeon_fb.c b/drivers/gpu/drm/radeon/radeon_fb.c
index ca32e9c..66324b5 100644
--- a/drivers/gpu/drm/radeon/radeon_fb.c
+++ b/drivers/gpu/drm/radeon/radeon_fb.c
@@ -225,6 +225,8 @@ static int radeonfb_create(struct radeon_fbdev *rfbdev,
strcpy(info->fix.id, "radeondrmfb");
+ drm_fb_helper_fill_fix(info, fb->pitch, fb->depth);
+
info->flags = FBINFO_DEFAULT | FBINFO_CAN_FORCE_OUTPUT;
info->fbops = &radeonfb_ops;
diff --git a/drivers/gpu/drm/radeon/radeon_irq_kms.c b/drivers/gpu/drm/radeon/radeon_irq_kms.c
index a289646..9ec830c 100644
--- a/drivers/gpu/drm/radeon/radeon_irq_kms.c
+++ b/drivers/gpu/drm/radeon/radeon_irq_kms.c
@@ -110,11 +110,14 @@ void radeon_driver_irq_uninstall_kms(struct drm_device *dev)
int radeon_irq_kms_init(struct radeon_device *rdev)
{
+ int i;
int r = 0;
INIT_WORK(&rdev->hotplug_work, radeon_hotplug_work_func);
spin_lock_init(&rdev->irq.sw_lock);
+ for (i = 0; i < rdev->num_crtc; i++)
+ spin_lock_init(&rdev->irq.pflip_lock[i]);
r = drm_vblank_init(rdev->ddev, rdev->num_crtc);
if (r) {
return r;
diff --git a/drivers/gpu/drm/radeon/radeon_kms.c b/drivers/gpu/drm/radeon/radeon_kms.c
index 28a53e4a..9832129 100644
--- a/drivers/gpu/drm/radeon/radeon_kms.c
+++ b/drivers/gpu/drm/radeon/radeon_kms.c
@@ -201,6 +201,10 @@ int radeon_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
}
radeon_set_filp_rights(dev, &rdev->cmask_filp, filp, &value);
break;
+ case RADEON_INFO_CLOCK_CRYSTAL_FREQ:
+ /* return clock value in KHz */
+ value = rdev->clock.spll.reference_freq * 10;
+ break;
default:
DRM_DEBUG_KMS("Invalid request %d\n", info->request);
return -EINVAL;
diff --git a/drivers/gpu/drm/radeon/reg_srcs/evergreen b/drivers/gpu/drm/radeon/reg_srcs/evergreen
index ac40fd3..9177f91 100644
--- a/drivers/gpu/drm/radeon/reg_srcs/evergreen
+++ b/drivers/gpu/drm/radeon/reg_srcs/evergreen
@@ -439,7 +439,7 @@ evergreen 0x9400
0x000286EC SPI_COMPUTE_NUM_THREAD_X
0x000286F0 SPI_COMPUTE_NUM_THREAD_Y
0x000286F4 SPI_COMPUTE_NUM_THREAD_Z
-0x000286F8 GDS_ADDR_SIZE
+0x00028724 GDS_ADDR_SIZE
0x00028780 CB_BLEND0_CONTROL
0x00028784 CB_BLEND1_CONTROL
0x00028788 CB_BLEND2_CONTROL
diff --git a/drivers/gpu/drm/radeon/rs600.c b/drivers/gpu/drm/radeon/rs600.c
index b4192ac..5afe294 100644
--- a/drivers/gpu/drm/radeon/rs600.c
+++ b/drivers/gpu/drm/radeon/rs600.c
@@ -339,16 +339,16 @@ void rs600_bm_disable(struct radeon_device *rdev)
int rs600_asic_reset(struct radeon_device *rdev)
{
- u32 status, tmp;
-
struct rv515_mc_save save;
+ u32 status, tmp;
+ int ret = 0;
- /* Stops all mc clients */
- rv515_mc_stop(rdev, &save);
status = RREG32(R_000E40_RBBM_STATUS);
if (!G_000E40_GUI_ACTIVE(status)) {
return 0;
}
+ /* Stops all mc clients */
+ rv515_mc_stop(rdev, &save);
status = RREG32(R_000E40_RBBM_STATUS);
dev_info(rdev->dev, "(%s:%d) RBBM_STATUS=0x%08X\n", __func__, __LINE__, status);
/* stop CP */
@@ -392,11 +392,11 @@ int rs600_asic_reset(struct radeon_device *rdev)
if (G_000E40_GA_BUSY(status) || G_000E40_VAP_BUSY(status)) {
dev_err(rdev->dev, "failed to reset GPU\n");
rdev->gpu_lockup = true;
- return -1;
- }
+ ret = -1;
+ } else
+ dev_info(rdev->dev, "GPU reset succeed\n");
rv515_mc_resume(rdev, &save);
- dev_info(rdev->dev, "GPU reset succeed\n");
- return 0;
+ return ret;
}
/*
diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c
index 3a264aa..491dc90 100644
--- a/drivers/gpu/drm/radeon/rv770.c
+++ b/drivers/gpu/drm/radeon/rv770.c
@@ -1268,7 +1268,7 @@ int rv770_init(struct radeon_device *rdev)
if (r)
return r;
/* Post card if necessary */
- if (!r600_card_posted(rdev)) {
+ if (!radeon_card_posted(rdev)) {
if (!rdev->bios) {
dev_err(rdev->dev, "Card not posted and no BIOS - ignoring\n");
return -EINVAL;
@@ -1372,6 +1372,9 @@ static void rv770_pcie_gen2_enable(struct radeon_device *rdev)
u32 link_width_cntl, lanes, speed_cntl, tmp;
u16 link_cntl2;
+ if (radeon_pcie_gen2 == 0)
+ return;
+
if (rdev->flags & RADEON_IS_IGP)
return;
diff --git a/drivers/gpu/stub/Kconfig b/drivers/gpu/stub/Kconfig
index 0e1edd7..09aea5f 100644
--- a/drivers/gpu/stub/Kconfig
+++ b/drivers/gpu/stub/Kconfig
@@ -3,7 +3,6 @@ config STUB_POULSBO
depends on PCI
# Poulsbo stub depends on ACPI_VIDEO when ACPI is enabled
# but for select to work, need to select ACPI_VIDEO's dependencies, ick
- select VIDEO_OUTPUT_CONTROL if ACPI
select BACKLIGHT_CLASS_DEVICE if ACPI
select INPUT if ACPI
select ACPI_VIDEO if ACPI
diff --git a/drivers/gpu/vga/Kconfig b/drivers/gpu/vga/Kconfig
index 8d0e31a..96c83a9 100644
--- a/drivers/gpu/vga/Kconfig
+++ b/drivers/gpu/vga/Kconfig
@@ -1,5 +1,5 @@
config VGA_ARB
- bool "VGA Arbitration" if EMBEDDED
+ bool "VGA Arbitration" if EXPERT
default y
depends on PCI
help
diff --git a/drivers/gpu/vga/vgaarb.c b/drivers/gpu/vga/vgaarb.c
index c380c65..ace2b16 100644
--- a/drivers/gpu/vga/vgaarb.c
+++ b/drivers/gpu/vga/vgaarb.c
@@ -636,7 +636,7 @@ int vga_client_register(struct pci_dev *pdev, void *cookie,
void (*irq_set_state)(void *cookie, bool state),
unsigned int (*set_vga_decode)(void *cookie, bool decode))
{
- int ret = -1;
+ int ret = -ENODEV;
struct vga_device *vgadev;
unsigned long flags;
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index 24cca2f..2560f01 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -62,9 +62,9 @@ config HID_3M_PCT
Support for 3M PCT touch screens.
config HID_A4TECH
- tristate "A4 tech mice" if EMBEDDED
+ tristate "A4 tech mice" if EXPERT
depends on USB_HID
- default !EMBEDDED
+ default !EXPERT
---help---
Support for A4 tech X5 and WOP-35 / Trust 450L mice.
@@ -77,9 +77,9 @@ config HID_ACRUX_FF
game controllers.
config HID_APPLE
- tristate "Apple {i,Power,Mac}Books" if EMBEDDED
+ tristate "Apple {i,Power,Mac}Books" if EXPERT
depends on (USB_HID || BT_HIDP)
- default !EMBEDDED
+ default !EXPERT
---help---
Support for some Apple devices which less or more break
HID specification.
@@ -88,9 +88,9 @@ config HID_APPLE
MacBooks, MacBook Pros and Apple Aluminum.
config HID_BELKIN
- tristate "Belkin Flip KVM and Wireless keyboard" if EMBEDDED
+ tristate "Belkin Flip KVM and Wireless keyboard" if EXPERT
depends on USB_HID
- default !EMBEDDED
+ default !EXPERT
---help---
Support for Belkin Flip KVM and Wireless keyboard.
@@ -101,16 +101,16 @@ config HID_CANDO
Support for Cando dual touch panel.
config HID_CHERRY
- tristate "Cherry Cymotion keyboard" if EMBEDDED
+ tristate "Cherry Cymotion keyboard" if EXPERT
depends on USB_HID
- default !EMBEDDED
+ default !EXPERT
---help---
Support for Cherry Cymotion keyboard.
config HID_CHICONY
- tristate "Chicony Tactical pad" if EMBEDDED
+ tristate "Chicony Tactical pad" if EXPERT
depends on USB_HID
- default !EMBEDDED
+ default !EXPERT
---help---
Support for Chicony Tactical pad.
@@ -130,9 +130,9 @@ config HID_PRODIKEYS
and some additional multimedia keys.
config HID_CYPRESS
- tristate "Cypress mouse and barcode readers" if EMBEDDED
+ tristate "Cypress mouse and barcode readers" if EXPERT
depends on USB_HID
- default !EMBEDDED
+ default !EXPERT
---help---
Support for cypress mouse and barcode readers.
@@ -174,16 +174,16 @@ config HID_ELECOM
Support for the ELECOM BM084 (bluetooth mouse).
config HID_EZKEY
- tristate "Ezkey BTC 8193 keyboard" if EMBEDDED
+ tristate "Ezkey BTC 8193 keyboard" if EXPERT
depends on USB_HID
- default !EMBEDDED
+ default !EXPERT
---help---
Support for Ezkey BTC 8193 keyboard.
config HID_KYE
- tristate "Kye/Genius Ergo Mouse" if EMBEDDED
+ tristate "Kye/Genius Ergo Mouse" if EXPERT
depends on USB_HID
- default !EMBEDDED
+ default !EXPERT
---help---
Support for Kye/Genius Ergo Mouse.
@@ -212,16 +212,16 @@ config HID_TWINHAN
Support for Twinhan IR remote control.
config HID_KENSINGTON
- tristate "Kensington Slimblade Trackball" if EMBEDDED
+ tristate "Kensington Slimblade Trackball" if EXPERT
depends on USB_HID
- default !EMBEDDED
+ default !EXPERT
---help---
Support for Kensington Slimblade Trackball.
config HID_LOGITECH
- tristate "Logitech devices" if EMBEDDED
+ tristate "Logitech devices" if EXPERT
depends on USB_HID
- default !EMBEDDED
+ default !EXPERT
---help---
Support for Logitech devices that are not fully compliant with HID standard.
@@ -276,9 +276,9 @@ config HID_MAGICMOUSE
Apple Wireless "Magic" Mouse.
config HID_MICROSOFT
- tristate "Microsoft non-fully HID-compliant devices" if EMBEDDED
+ tristate "Microsoft non-fully HID-compliant devices" if EXPERT
depends on USB_HID
- default !EMBEDDED
+ default !EXPERT
---help---
Support for Microsoft devices that are not fully compliant with HID standard.
@@ -289,9 +289,9 @@ config HID_MOSART
Support for MosArt dual-touch panels.
config HID_MONTEREY
- tristate "Monterey Genius KB29E keyboard" if EMBEDDED
+ tristate "Monterey Genius KB29E keyboard" if EXPERT
depends on USB_HID
- default !EMBEDDED
+ default !EXPERT
---help---
Support for Monterey Genius KB29E.
@@ -365,8 +365,8 @@ config HID_PICOLCD
- IR
config HID_PICOLCD_FB
- bool "Framebuffer support" if EMBEDDED
- default !EMBEDDED
+ bool "Framebuffer support" if EXPERT
+ default !EXPERT
depends on HID_PICOLCD
depends on HID_PICOLCD=FB || FB=y
select FB_DEFERRED_IO
@@ -379,8 +379,8 @@ config HID_PICOLCD_FB
frambuffer device.
config HID_PICOLCD_BACKLIGHT
- bool "Backlight control" if EMBEDDED
- default !EMBEDDED
+ bool "Backlight control" if EXPERT
+ default !EXPERT
depends on HID_PICOLCD
depends on HID_PICOLCD=BACKLIGHT_CLASS_DEVICE || BACKLIGHT_CLASS_DEVICE=y
---help---
@@ -388,16 +388,16 @@ config HID_PICOLCD_BACKLIGHT
class.
config HID_PICOLCD_LCD
- bool "Contrast control" if EMBEDDED
- default !EMBEDDED
+ bool "Contrast control" if EXPERT
+ default !EXPERT
depends on HID_PICOLCD
depends on HID_PICOLCD=LCD_CLASS_DEVICE || LCD_CLASS_DEVICE=y
---help---
Provide access to PicoLCD's LCD contrast via lcd class.
config HID_PICOLCD_LEDS
- bool "GPO via leds class" if EMBEDDED
- default !EMBEDDED
+ bool "GPO via leds class" if EXPERT
+ default !EXPERT
depends on HID_PICOLCD
depends on HID_PICOLCD=LEDS_CLASS || LEDS_CLASS=y
---help---
diff --git a/drivers/hid/usbhid/Kconfig b/drivers/hid/usbhid/Kconfig
index 4edb3be..0f20fd1 100644
--- a/drivers/hid/usbhid/Kconfig
+++ b/drivers/hid/usbhid/Kconfig
@@ -45,7 +45,7 @@ config USB_HIDDEV
If unsure, say Y.
menu "USB HID Boot Protocol drivers"
- depends on USB!=n && USB_HID!=y && EMBEDDED
+ depends on USB!=n && USB_HID!=y && EXPERT
config USB_KBD
tristate "USB HIDBP Keyboard (simple Boot) support"
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 35f00da..773e484 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -618,8 +618,8 @@ config SENSORS_LM93
depends on I2C
select HWMON_VID
help
- If you say yes here you get support for National Semiconductor LM93
- sensor chips.
+ If you say yes here you get support for National Semiconductor LM93,
+ LM94, and compatible sensor chips.
This driver can also be built as a module. If so, the module
will be called lm93.
diff --git a/drivers/hwmon/lm93.c b/drivers/hwmon/lm93.c
index c9ed14e..3b43df4 100644
--- a/drivers/hwmon/lm93.c
+++ b/drivers/hwmon/lm93.c
@@ -135,6 +135,11 @@
#define LM93_MFR_ID 0x73
#define LM93_MFR_ID_PROTOTYPE 0x72
+/* LM94 REGISTER VALUES */
+#define LM94_MFR_ID_2 0x7a
+#define LM94_MFR_ID 0x79
+#define LM94_MFR_ID_PROTOTYPE 0x78
+
/* SMBus capabilities */
#define LM93_SMBUS_FUNC_FULL (I2C_FUNC_SMBUS_BYTE_DATA | \
I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_BLOCK_DATA)
@@ -2504,6 +2509,7 @@ static int lm93_detect(struct i2c_client *client, struct i2c_board_info *info)
{
struct i2c_adapter *adapter = client->adapter;
int mfr, ver;
+ const char *name;
if (!i2c_check_functionality(adapter, LM93_SMBUS_FUNC_MIN))
return -ENODEV;
@@ -2517,13 +2523,23 @@ static int lm93_detect(struct i2c_client *client, struct i2c_board_info *info)
}
ver = lm93_read_byte(client, LM93_REG_VER);
- if (ver != LM93_MFR_ID && ver != LM93_MFR_ID_PROTOTYPE) {
+ switch (ver) {
+ case LM93_MFR_ID:
+ case LM93_MFR_ID_PROTOTYPE:
+ name = "lm93";
+ break;
+ case LM94_MFR_ID_2:
+ case LM94_MFR_ID:
+ case LM94_MFR_ID_PROTOTYPE:
+ name = "lm94";
+ break;
+ default:
dev_dbg(&adapter->dev,
"detect failed, bad version id 0x%02x!\n", ver);
return -ENODEV;
}
- strlcpy(info->type, "lm93", I2C_NAME_SIZE);
+ strlcpy(info->type, name, I2C_NAME_SIZE);
dev_dbg(&adapter->dev,"loading %s at %d,0x%02x\n",
client->name, i2c_adapter_id(client->adapter),
client->addr);
@@ -2602,6 +2618,7 @@ static int lm93_remove(struct i2c_client *client)
static const struct i2c_device_id lm93_id[] = {
{ "lm93", 0 },
+ { "lm94", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, lm93_id);
diff --git a/drivers/i2c/busses/scx200_acb.c b/drivers/i2c/busses/scx200_acb.c
index 53fab51..986e5f6 100644
--- a/drivers/i2c/busses/scx200_acb.c
+++ b/drivers/i2c/busses/scx200_acb.c
@@ -29,6 +29,7 @@
#include <linux/init.h>
#include <linux/i2c.h>
#include <linux/pci.h>
+#include <linux/platform_device.h>
#include <linux/delay.h>
#include <linux/mutex.h>
#include <linux/slab.h>
@@ -40,6 +41,7 @@
MODULE_AUTHOR("Christer Weinigel <wingel@nano-system.com>");
MODULE_DESCRIPTION("NatSemi SCx200 ACCESS.bus Driver");
+MODULE_ALIAS("platform:cs5535-smb");
MODULE_LICENSE("GPL");
#define MAX_DEVICES 4
@@ -84,10 +86,6 @@ struct scx200_acb_iface {
u8 *ptr;
char needs_reset;
unsigned len;
-
- /* PCI device info */
- struct pci_dev *pdev;
- int bar;
};
/* Register Definitions */
@@ -391,7 +389,7 @@ static const struct i2c_algorithm scx200_acb_algorithm = {
static struct scx200_acb_iface *scx200_acb_list;
static DEFINE_MUTEX(scx200_acb_list_mutex);
-static __init int scx200_acb_probe(struct scx200_acb_iface *iface)
+static __devinit int scx200_acb_probe(struct scx200_acb_iface *iface)
{
u8 val;
@@ -427,7 +425,7 @@ static __init int scx200_acb_probe(struct scx200_acb_iface *iface)
return 0;
}
-static __init struct scx200_acb_iface *scx200_create_iface(const char *text,
+static __devinit struct scx200_acb_iface *scx200_create_iface(const char *text,
struct device *dev, int index)
{
struct scx200_acb_iface *iface;
@@ -452,7 +450,7 @@ static __init struct scx200_acb_iface *scx200_create_iface(const char *text,
return iface;
}
-static int __init scx200_acb_create(struct scx200_acb_iface *iface)
+static int __devinit scx200_acb_create(struct scx200_acb_iface *iface)
{
struct i2c_adapter *adapter;
int rc;
@@ -472,183 +470,145 @@ static int __init scx200_acb_create(struct scx200_acb_iface *iface)
return -ENODEV;
}
- mutex_lock(&scx200_acb_list_mutex);
- iface->next = scx200_acb_list;
- scx200_acb_list = iface;
- mutex_unlock(&scx200_acb_list_mutex);
+ if (!adapter->dev.parent) {
+ /* If there's no dev, we're tracking (ISA) ifaces manually */
+ mutex_lock(&scx200_acb_list_mutex);
+ iface->next = scx200_acb_list;
+ scx200_acb_list = iface;
+ mutex_unlock(&scx200_acb_list_mutex);
+ }
return 0;
}
-static __init int scx200_create_pci(const char *text, struct pci_dev *pdev,
- int bar)
+static struct scx200_acb_iface * __devinit scx200_create_dev(const char *text,
+ unsigned long base, int index, struct device *dev)
{
struct scx200_acb_iface *iface;
int rc;
- iface = scx200_create_iface(text, &pdev->dev, 0);
+ iface = scx200_create_iface(text, dev, index);
if (iface == NULL)
- return -ENOMEM;
-
- iface->pdev = pdev;
- iface->bar = bar;
-
- rc = pci_enable_device_io(iface->pdev);
- if (rc)
- goto errout_free;
+ return NULL;
- rc = pci_request_region(iface->pdev, iface->bar, iface->adapter.name);
- if (rc) {
- printk(KERN_ERR NAME ": can't allocate PCI BAR %d\n",
- iface->bar);
+ if (!request_region(base, 8, iface->adapter.name)) {
+ printk(KERN_ERR NAME ": can't allocate io 0x%lx-0x%lx\n",
+ base, base + 8 - 1);
goto errout_free;
}
- iface->base = pci_resource_start(iface->pdev, iface->bar);
+ iface->base = base;
rc = scx200_acb_create(iface);
if (rc == 0)
- return 0;
+ return iface;
- pci_release_region(iface->pdev, iface->bar);
- pci_dev_put(iface->pdev);
+ release_region(base, 8);
errout_free:
kfree(iface);
- return rc;
+ return NULL;
}
-static int __init scx200_create_isa(const char *text, unsigned long base,
- int index)
+static int __devinit scx200_probe(struct platform_device *pdev)
{
struct scx200_acb_iface *iface;
- int rc;
-
- iface = scx200_create_iface(text, NULL, index);
-
- if (iface == NULL)
- return -ENOMEM;
+ struct resource *res;
- if (!request_region(base, 8, iface->adapter.name)) {
- printk(KERN_ERR NAME ": can't allocate io 0x%lx-0x%lx\n",
- base, base + 8 - 1);
- rc = -EBUSY;
- goto errout_free;
+ res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "can't fetch device resource info\n");
+ return -ENODEV;
}
- iface->base = base;
- rc = scx200_acb_create(iface);
+ iface = scx200_create_dev("CS5535", res->start, 0, &pdev->dev);
+ if (!iface)
+ return -EIO;
- if (rc == 0)
- return 0;
+ dev_info(&pdev->dev, "SCx200 device '%s' registered\n",
+ iface->adapter.name);
+ platform_set_drvdata(pdev, iface);
- release_region(base, 8);
- errout_free:
- kfree(iface);
- return rc;
+ return 0;
}
-/* Driver data is an index into the scx200_data array that indicates
- * the name and the BAR where the I/O address resource is located. ISA
- * devices are flagged with a bar value of -1 */
-
-static const struct pci_device_id scx200_pci[] __initconst = {
- { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SCx200_BRIDGE),
- .driver_data = 0 },
- { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SC1100_BRIDGE),
- .driver_data = 0 },
- { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_CS5535_ISA),
- .driver_data = 1 },
- { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_ISA),
- .driver_data = 2 },
- { 0, }
-};
-
-static struct {
- const char *name;
- int bar;
-} scx200_data[] = {
- { "SCx200", -1 },
- { "CS5535", 0 },
- { "CS5536", 0 }
-};
+static void __devexit scx200_cleanup_iface(struct scx200_acb_iface *iface)
+{
+ i2c_del_adapter(&iface->adapter);
+ release_region(iface->base, 8);
+ kfree(iface);
+}
-static __init int scx200_scan_pci(void)
+static int __devexit scx200_remove(struct platform_device *pdev)
{
- int data, dev;
- int rc = -ENODEV;
- struct pci_dev *pdev;
+ struct scx200_acb_iface *iface;
- for(dev = 0; dev < ARRAY_SIZE(scx200_pci); dev++) {
- pdev = pci_get_device(scx200_pci[dev].vendor,
- scx200_pci[dev].device, NULL);
+ iface = platform_get_drvdata(pdev);
+ platform_set_drvdata(pdev, NULL);
+ scx200_cleanup_iface(iface);
- if (pdev == NULL)
- continue;
+ return 0;
+}
- data = scx200_pci[dev].driver_data;
+static struct platform_driver scx200_pci_drv = {
+ .driver = {
+ .name = "cs5535-smb",
+ .owner = THIS_MODULE,
+ },
+ .probe = scx200_probe,
+ .remove = __devexit_p(scx200_remove),
+};
- /* if .bar is greater or equal to zero, this is a
- * PCI device - otherwise, we assume
- that the ports are ISA based
- */
+static const struct pci_device_id scx200_isa[] __initconst = {
+ { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SCx200_BRIDGE) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SC1100_BRIDGE) },
+ { 0, }
+};
- if (scx200_data[data].bar >= 0)
- rc = scx200_create_pci(scx200_data[data].name, pdev,
- scx200_data[data].bar);
- else {
- int i;
+static __init void scx200_scan_isa(void)
+{
+ int i;
- pci_dev_put(pdev);
- for (i = 0; i < MAX_DEVICES; ++i) {
- if (base[i] == 0)
- continue;
+ if (!pci_dev_present(scx200_isa))
+ return;
- rc = scx200_create_isa(scx200_data[data].name,
- base[i],
- i);
- }
- }
+ for (i = 0; i < MAX_DEVICES; ++i) {
+ if (base[i] == 0)
+ continue;
- break;
+ /* XXX: should we care about failures? */
+ scx200_create_dev("SCx200", base[i], i, NULL);
}
-
- return rc;
}
static int __init scx200_acb_init(void)
{
- int rc;
-
pr_debug(NAME ": NatSemi SCx200 ACCESS.bus Driver\n");
- rc = scx200_scan_pci();
+ /* First scan for ISA-based devices */
+ scx200_scan_isa(); /* XXX: should we care about errors? */
/* If at least one bus was created, init must succeed */
if (scx200_acb_list)
return 0;
- return rc;
+
+ /* No ISA devices; register the platform driver for PCI-based devices */
+ return platform_driver_register(&scx200_pci_drv);
}
static void __exit scx200_acb_cleanup(void)
{
struct scx200_acb_iface *iface;
+ platform_driver_unregister(&scx200_pci_drv);
+
mutex_lock(&scx200_acb_list_mutex);
while ((iface = scx200_acb_list) != NULL) {
scx200_acb_list = iface->next;
mutex_unlock(&scx200_acb_list_mutex);
- i2c_del_adapter(&iface->adapter);
-
- if (iface->pdev) {
- pci_release_region(iface->pdev, iface->bar);
- pci_dev_put(iface->pdev);
- }
- else
- release_region(iface->base, 8);
+ scx200_cleanup_iface(iface);
- kfree(iface);
mutex_lock(&scx200_acb_list_mutex);
}
mutex_unlock(&scx200_acb_list_mutex);
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
index c7db698..f0bd5bc 100644
--- a/drivers/i2c/i2c-core.c
+++ b/drivers/i2c/i2c-core.c
@@ -196,88 +196,60 @@ static int i2c_device_pm_suspend(struct device *dev)
{
const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
- if (pm) {
- if (pm_runtime_suspended(dev))
- return 0;
- else
- return pm->suspend ? pm->suspend(dev) : 0;
- }
-
- return i2c_legacy_suspend(dev, PMSG_SUSPEND);
+ if (pm)
+ return pm_generic_suspend(dev);
+ else
+ return i2c_legacy_suspend(dev, PMSG_SUSPEND);
}
static int i2c_device_pm_resume(struct device *dev)
{
const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
- int ret;
if (pm)
- ret = pm->resume ? pm->resume(dev) : 0;
+ return pm_generic_resume(dev);
else
- ret = i2c_legacy_resume(dev);
-
- return ret;
+ return i2c_legacy_resume(dev);
}
static int i2c_device_pm_freeze(struct device *dev)
{
const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
- if (pm) {
- if (pm_runtime_suspended(dev))
- return 0;
- else
- return pm->freeze ? pm->freeze(dev) : 0;
- }
-
- return i2c_legacy_suspend(dev, PMSG_FREEZE);
+ if (pm)
+ return pm_generic_freeze(dev);
+ else
+ return i2c_legacy_suspend(dev, PMSG_FREEZE);
}
static int i2c_device_pm_thaw(struct device *dev)
{
const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
- if (pm) {
- if (pm_runtime_suspended(dev))
- return 0;
- else
- return pm->thaw ? pm->thaw(dev) : 0;
- }
-
- return i2c_legacy_resume(dev);
+ if (pm)
+ return pm_generic_thaw(dev);
+ else
+ return i2c_legacy_resume(dev);
}
static int i2c_device_pm_poweroff(struct device *dev)
{
const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
- if (pm) {
- if (pm_runtime_suspended(dev))
- return 0;
- else
- return pm->poweroff ? pm->poweroff(dev) : 0;
- }
-
- return i2c_legacy_suspend(dev, PMSG_HIBERNATE);
+ if (pm)
+ return pm_generic_poweroff(dev);
+ else
+ return i2c_legacy_suspend(dev, PMSG_HIBERNATE);
}
static int i2c_device_pm_restore(struct device *dev)
{
const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
- int ret;
if (pm)
- ret = pm->restore ? pm->restore(dev) : 0;
+ return pm_generic_restore(dev);
else
- ret = i2c_legacy_resume(dev);
-
- if (!ret) {
- pm_runtime_disable(dev);
- pm_runtime_set_active(dev);
- pm_runtime_enable(dev);
- }
-
- return ret;
+ return i2c_legacy_resume(dev);
}
#else /* !CONFIG_PM_SLEEP */
#define i2c_device_pm_suspend NULL
@@ -1021,6 +993,14 @@ static int i2c_do_del_adapter(struct i2c_driver *driver,
static int __unregister_client(struct device *dev, void *dummy)
{
struct i2c_client *client = i2c_verify_client(dev);
+ if (client && strcmp(client->name, "dummy"))
+ i2c_unregister_device(client);
+ return 0;
+}
+
+static int __unregister_dummy(struct device *dev, void *dummy)
+{
+ struct i2c_client *client = i2c_verify_client(dev);
if (client)
i2c_unregister_device(client);
return 0;
@@ -1075,8 +1055,12 @@ int i2c_del_adapter(struct i2c_adapter *adap)
mutex_unlock(&adap->userspace_clients_lock);
/* Detach any active clients. This can't fail, thus we do not
- checking the returned value. */
+ * check the returned value. This is a two-pass process, because
+ * we can't remove the dummy devices during the first pass: they
+ * could have been instantiated by real devices wishing to clean
+ * them up properly, so we give them a chance to do that first. */
res = device_for_each_child(&adap->dev, NULL, __unregister_client);
+ res = device_for_each_child(&adap->dev, NULL, __unregister_dummy);
#ifdef CONFIG_I2C_COMPAT
class_compat_remove_link(i2c_adapter_compat_class, &adap->dev,
@@ -1140,6 +1124,14 @@ int i2c_register_driver(struct module *owner, struct i2c_driver *driver)
if (res)
return res;
+ /* Drivers should switch to dev_pm_ops instead. */
+ if (driver->suspend)
+ pr_warn("i2c-core: driver [%s] using legacy suspend method\n",
+ driver->driver.name);
+ if (driver->resume)
+ pr_warn("i2c-core: driver [%s] using legacy resume method\n",
+ driver->driver.name);
+
pr_debug("i2c-core: driver [%s] registered\n", driver->driver.name);
INIT_LIST_HEAD(&driver->clients);
diff --git a/drivers/ide/Kconfig b/drivers/ide/Kconfig
index 98ccfeb..9827c5e 100644
--- a/drivers/ide/Kconfig
+++ b/drivers/ide/Kconfig
@@ -134,7 +134,7 @@ config BLK_DEV_IDECD
module will be called ide-cd.
config BLK_DEV_IDECD_VERBOSE_ERRORS
- bool "Verbose error logging for IDE/ATAPI CDROM driver" if EMBEDDED
+ bool "Verbose error logging for IDE/ATAPI CDROM driver" if EXPERT
depends on BLK_DEV_IDECD
default y
help
diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c
index 56ac09d..1fa091e 100644
--- a/drivers/idle/intel_idle.c
+++ b/drivers/idle/intel_idle.c
@@ -59,6 +59,8 @@
#include <linux/hrtimer.h> /* ktime_get_real() */
#include <trace/events/power.h>
#include <linux/sched.h>
+#include <linux/notifier.h>
+#include <linux/cpu.h>
#include <asm/mwait.h>
#define INTEL_IDLE_VERSION "0.4"
@@ -73,6 +75,7 @@ static int max_cstate = MWAIT_MAX_NUM_CSTATES - 1;
static unsigned int mwait_substates;
+#define LAPIC_TIMER_ALWAYS_RELIABLE 0xFFFFFFFF
/* Reliable LAPIC Timer States, bit 1 for C1 etc. */
static unsigned int lapic_timer_reliable_states = (1 << 1); /* Default to only C1 */
@@ -82,6 +85,14 @@ static int intel_idle(struct cpuidle_device *dev, struct cpuidle_state *state);
static struct cpuidle_state *cpuidle_state_table;
/*
+ * Set this flag for states where the HW flushes the TLB for us
+ * and so we don't need cross-calls to keep it consistent.
+ * If this flag is set, SW flushes the TLB, so even if the
+ * HW doesn't do the flushing, this flag is safe to use.
+ */
+#define CPUIDLE_FLAG_TLB_FLUSHED 0x10000
+
+/*
* States are indexed by the cstate number,
* which is also the index into the MWAIT hint array.
* Thus C0 is a dummy.
@@ -122,7 +133,7 @@ static struct cpuidle_state snb_cstates[MWAIT_MAX_NUM_CSTATES] = {
.driver_data = (void *) 0x00,
.flags = CPUIDLE_FLAG_TIME_VALID,
.exit_latency = 1,
- .target_residency = 4,
+ .target_residency = 1,
.enter = &intel_idle },
{ /* MWAIT C2 */
.name = "SNB-C3",
@@ -130,7 +141,7 @@ static struct cpuidle_state snb_cstates[MWAIT_MAX_NUM_CSTATES] = {
.driver_data = (void *) 0x10,
.flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
.exit_latency = 80,
- .target_residency = 160,
+ .target_residency = 211,
.enter = &intel_idle },
{ /* MWAIT C3 */
.name = "SNB-C6",
@@ -138,7 +149,7 @@ static struct cpuidle_state snb_cstates[MWAIT_MAX_NUM_CSTATES] = {
.driver_data = (void *) 0x20,
.flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
.exit_latency = 104,
- .target_residency = 208,
+ .target_residency = 345,
.enter = &intel_idle },
{ /* MWAIT C4 */
.name = "SNB-C7",
@@ -146,7 +157,7 @@ static struct cpuidle_state snb_cstates[MWAIT_MAX_NUM_CSTATES] = {
.driver_data = (void *) 0x30,
.flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
.exit_latency = 109,
- .target_residency = 300,
+ .target_residency = 345,
.enter = &intel_idle },
};
@@ -220,8 +231,6 @@ static int intel_idle(struct cpuidle_device *dev, struct cpuidle_state *state)
kt_before = ktime_get_real();
stop_critical_timings();
- trace_power_start(POWER_CSTATE, (eax >> 4) + 1, cpu);
- trace_cpu_idle((eax >> 4) + 1, cpu);
if (!need_resched()) {
__monitor((void *)&current_thread_info()->flags, 0, 0);
@@ -243,6 +252,35 @@ static int intel_idle(struct cpuidle_device *dev, struct cpuidle_state *state)
return usec_delta;
}
+static void __setup_broadcast_timer(void *arg)
+{
+ unsigned long reason = (unsigned long)arg;
+ int cpu = smp_processor_id();
+
+ reason = reason ?
+ CLOCK_EVT_NOTIFY_BROADCAST_ON : CLOCK_EVT_NOTIFY_BROADCAST_OFF;
+
+ clockevents_notify(reason, &cpu);
+}
+
+static int setup_broadcast_cpuhp_notify(struct notifier_block *n,
+ unsigned long action, void *hcpu)
+{
+ int hotcpu = (unsigned long)hcpu;
+
+ switch (action & 0xf) {
+ case CPU_ONLINE:
+ smp_call_function_single(hotcpu, __setup_broadcast_timer,
+ (void *)true, 1);
+ break;
+ }
+ return NOTIFY_OK;
+}
+
+static struct notifier_block setup_broadcast_notifier = {
+ .notifier_call = setup_broadcast_cpuhp_notify,
+};
+
/*
* intel_idle_probe()
*/
@@ -305,7 +343,11 @@ static int intel_idle_probe(void)
}
if (boot_cpu_has(X86_FEATURE_ARAT)) /* Always Reliable APIC Timer */
- lapic_timer_reliable_states = 0xFFFFFFFF;
+ lapic_timer_reliable_states = LAPIC_TIMER_ALWAYS_RELIABLE;
+ else {
+ smp_call_function(__setup_broadcast_timer, (void *)true, 1);
+ register_cpu_notifier(&setup_broadcast_notifier);
+ }
pr_debug(PREFIX "v" INTEL_IDLE_VERSION
" model 0x%X\n", boot_cpu_data.x86_model);
@@ -403,6 +445,10 @@ static int __init intel_idle_init(void)
{
int retval;
+ /* Do not load intel_idle at all for now if idle= is passed */
+ if (boot_option_idle_override != IDLE_NO_OVERRIDE)
+ return -ENODEV;
+
retval = intel_idle_probe();
if (retval)
return retval;
@@ -428,6 +474,11 @@ static void __exit intel_idle_exit(void)
intel_idle_cpuidle_devices_uninit();
cpuidle_unregister_driver(&intel_idle_driver);
+ if (lapic_timer_reliable_states != LAPIC_TIMER_ALWAYS_RELIABLE) {
+ smp_call_function(__setup_broadcast_timer, (void *)false, 1);
+ unregister_cpu_notifier(&setup_broadcast_notifier);
+ }
+
return;
}
diff --git a/drivers/infiniband/core/cache.c b/drivers/infiniband/core/cache.c
index 6888356..f9ba7d7 100644
--- a/drivers/infiniband/core/cache.c
+++ b/drivers/infiniband/core/cache.c
@@ -308,7 +308,7 @@ static void ib_cache_event(struct ib_event_handler *handler,
INIT_WORK(&work->work, ib_cache_task);
work->device = event->device;
work->port_num = event->element.port_num;
- schedule_work(&work->work);
+ queue_work(ib_wq, &work->work);
}
}
}
@@ -368,7 +368,7 @@ static void ib_cache_cleanup_one(struct ib_device *device)
int p;
ib_unregister_event_handler(&device->cache.event_handler);
- flush_scheduled_work();
+ flush_workqueue(ib_wq);
for (p = 0; p <= end_port(device) - start_port(device); ++p) {
kfree(device->cache.pkey_cache[p]);
diff --git a/drivers/infiniband/core/device.c b/drivers/infiniband/core/device.c
index a19effa..f793bf2 100644
--- a/drivers/infiniband/core/device.c
+++ b/drivers/infiniband/core/device.c
@@ -38,7 +38,6 @@
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/mutex.h>
-#include <linux/workqueue.h>
#include "core_priv.h"
@@ -52,6 +51,9 @@ struct ib_client_data {
void * data;
};
+struct workqueue_struct *ib_wq;
+EXPORT_SYMBOL_GPL(ib_wq);
+
static LIST_HEAD(device_list);
static LIST_HEAD(client_list);
@@ -718,6 +720,10 @@ static int __init ib_core_init(void)
{
int ret;
+ ib_wq = alloc_workqueue("infiniband", 0, 0);
+ if (!ib_wq)
+ return -ENOMEM;
+
ret = ib_sysfs_setup();
if (ret)
printk(KERN_WARNING "Couldn't create InfiniBand device class\n");
@@ -726,6 +732,7 @@ static int __init ib_core_init(void)
if (ret) {
printk(KERN_WARNING "Couldn't set up InfiniBand P_Key/GID cache\n");
ib_sysfs_cleanup();
+ destroy_workqueue(ib_wq);
}
return ret;
@@ -736,7 +743,7 @@ static void __exit ib_core_cleanup(void)
ib_cache_cleanup();
ib_sysfs_cleanup();
/* Make sure that any pending umem accounting work is done. */
- flush_scheduled_work();
+ destroy_workqueue(ib_wq);
}
module_init(ib_core_init);
diff --git a/drivers/infiniband/core/sa_query.c b/drivers/infiniband/core/sa_query.c
index 91a6603..e38be1bc 100644
--- a/drivers/infiniband/core/sa_query.c
+++ b/drivers/infiniband/core/sa_query.c
@@ -425,7 +425,7 @@ static void ib_sa_event(struct ib_event_handler *handler, struct ib_event *event
port->sm_ah = NULL;
spin_unlock_irqrestore(&port->ah_lock, flags);
- schedule_work(&sa_dev->port[event->element.port_num -
+ queue_work(ib_wq, &sa_dev->port[event->element.port_num -
sa_dev->start_port].update_task);
}
}
diff --git a/drivers/infiniband/core/umem.c b/drivers/infiniband/core/umem.c
index 415e186..b645e55 100644
--- a/drivers/infiniband/core/umem.c
+++ b/drivers/infiniband/core/umem.c
@@ -262,7 +262,7 @@ void ib_umem_release(struct ib_umem *umem)
umem->mm = mm;
umem->diff = diff;
- schedule_work(&umem->work);
+ queue_work(ib_wq, &umem->work);
return;
}
} else
diff --git a/drivers/infiniband/hw/amso1100/c2_rnic.c b/drivers/infiniband/hw/amso1100/c2_rnic.c
index 85cfae4..8c81992 100644
--- a/drivers/infiniband/hw/amso1100/c2_rnic.c
+++ b/drivers/infiniband/hw/amso1100/c2_rnic.c
@@ -459,13 +459,12 @@ int __devinit c2_rnic_init(struct c2_dev *c2dev)
IB_DEVICE_MEM_WINDOW);
/* Allocate the qptr_array */
- c2dev->qptr_array = vmalloc(C2_MAX_CQS * sizeof(void *));
+ c2dev->qptr_array = vzalloc(C2_MAX_CQS * sizeof(void *));
if (!c2dev->qptr_array) {
return -ENOMEM;
}
- /* Inialize the qptr_array */
- memset(c2dev->qptr_array, 0, C2_MAX_CQS * sizeof(void *));
+ /* Initialize the qptr_array */
c2dev->qptr_array[0] = (void *) &c2dev->req_vq;
c2dev->qptr_array[1] = (void *) &c2dev->rep_vq;
c2dev->qptr_array[2] = (void *) &c2dev->aeq;
diff --git a/drivers/infiniband/hw/ehca/ipz_pt_fn.c b/drivers/infiniband/hw/ehca/ipz_pt_fn.c
index 1596e30..1898d6e 100644
--- a/drivers/infiniband/hw/ehca/ipz_pt_fn.c
+++ b/drivers/infiniband/hw/ehca/ipz_pt_fn.c
@@ -222,15 +222,14 @@ int ipz_queue_ctor(struct ehca_pd *pd, struct ipz_queue *queue,
queue->small_page = NULL;
/* allocate queue page pointers */
- queue->queue_pages = kmalloc(nr_of_pages * sizeof(void *), GFP_KERNEL);
+ queue->queue_pages = kzalloc(nr_of_pages * sizeof(void *), GFP_KERNEL);
if (!queue->queue_pages) {
- queue->queue_pages = vmalloc(nr_of_pages * sizeof(void *));
+ queue->queue_pages = vzalloc(nr_of_pages * sizeof(void *));
if (!queue->queue_pages) {
ehca_gen_err("Couldn't allocate queue page list");
return 0;
}
}
- memset(queue->queue_pages, 0, nr_of_pages * sizeof(void *));
/* allocate actual queue pages */
if (is_small) {
diff --git a/drivers/infiniband/hw/ipath/ipath_driver.c b/drivers/infiniband/hw/ipath/ipath_driver.c
index b33f045..47db4bf 100644
--- a/drivers/infiniband/hw/ipath/ipath_driver.c
+++ b/drivers/infiniband/hw/ipath/ipath_driver.c
@@ -199,12 +199,11 @@ static struct ipath_devdata *ipath_alloc_devdata(struct pci_dev *pdev)
goto bail;
}
- dd = vmalloc(sizeof(*dd));
+ dd = vzalloc(sizeof(*dd));
if (!dd) {
dd = ERR_PTR(-ENOMEM);
goto bail;
}
- memset(dd, 0, sizeof(*dd));
dd->ipath_unit = -1;
spin_lock_irqsave(&ipath_devs_lock, flags);
@@ -756,7 +755,7 @@ static void __devexit ipath_remove_one(struct pci_dev *pdev)
*/
ipath_shutdown_device(dd);
- flush_scheduled_work();
+ flush_workqueue(ib_wq);
if (dd->verbs_dev)
ipath_unregister_ib_device(dd->verbs_dev);
diff --git a/drivers/infiniband/hw/ipath/ipath_file_ops.c b/drivers/infiniband/hw/ipath/ipath_file_ops.c
index 9292a15..6d4b29c 100644
--- a/drivers/infiniband/hw/ipath/ipath_file_ops.c
+++ b/drivers/infiniband/hw/ipath/ipath_file_ops.c
@@ -1530,7 +1530,7 @@ static int init_subports(struct ipath_devdata *dd,
}
num_subports = uinfo->spu_subport_cnt;
- pd->subport_uregbase = vmalloc(PAGE_SIZE * num_subports);
+ pd->subport_uregbase = vzalloc(PAGE_SIZE * num_subports);
if (!pd->subport_uregbase) {
ret = -ENOMEM;
goto bail;
@@ -1538,13 +1538,13 @@ static int init_subports(struct ipath_devdata *dd,
/* Note: pd->port_rcvhdrq_size isn't initialized yet. */
size = ALIGN(dd->ipath_rcvhdrcnt * dd->ipath_rcvhdrentsize *
sizeof(u32), PAGE_SIZE) * num_subports;
- pd->subport_rcvhdr_base = vmalloc(size);
+ pd->subport_rcvhdr_base = vzalloc(size);
if (!pd->subport_rcvhdr_base) {
ret = -ENOMEM;
goto bail_ureg;
}
- pd->subport_rcvegrbuf = vmalloc(pd->port_rcvegrbuf_chunks *
+ pd->subport_rcvegrbuf = vzalloc(pd->port_rcvegrbuf_chunks *
pd->port_rcvegrbuf_size *
num_subports);
if (!pd->subport_rcvegrbuf) {
@@ -1556,11 +1556,6 @@ static int init_subports(struct ipath_devdata *dd,
pd->port_subport_id = uinfo->spu_subport_id;
pd->active_slaves = 1;
set_bit(IPATH_PORT_MASTER_UNINIT, &pd->port_flag);
- memset(pd->subport_uregbase, 0, PAGE_SIZE * num_subports);
- memset(pd->subport_rcvhdr_base, 0, size);
- memset(pd->subport_rcvegrbuf, 0, pd->port_rcvegrbuf_chunks *
- pd->port_rcvegrbuf_size *
- num_subports);
goto bail;
bail_rhdr:
diff --git a/drivers/infiniband/hw/ipath/ipath_init_chip.c b/drivers/infiniband/hw/ipath/ipath_init_chip.c
index 7769382..fef0f42 100644
--- a/drivers/infiniband/hw/ipath/ipath_init_chip.c
+++ b/drivers/infiniband/hw/ipath/ipath_init_chip.c
@@ -442,7 +442,7 @@ static void init_shadow_tids(struct ipath_devdata *dd)
struct page **pages;
dma_addr_t *addrs;
- pages = vmalloc(dd->ipath_cfgports * dd->ipath_rcvtidcnt *
+ pages = vzalloc(dd->ipath_cfgports * dd->ipath_rcvtidcnt *
sizeof(struct page *));
if (!pages) {
ipath_dev_err(dd, "failed to allocate shadow page * "
@@ -461,9 +461,6 @@ static void init_shadow_tids(struct ipath_devdata *dd)
return;
}
- memset(pages, 0, dd->ipath_cfgports * dd->ipath_rcvtidcnt *
- sizeof(struct page *));
-
dd->ipath_pageshadow = pages;
dd->ipath_physshadow = addrs;
}
diff --git a/drivers/infiniband/hw/ipath/ipath_user_pages.c b/drivers/infiniband/hw/ipath/ipath_user_pages.c
index 5e86d73..bab9f74 100644
--- a/drivers/infiniband/hw/ipath/ipath_user_pages.c
+++ b/drivers/infiniband/hw/ipath/ipath_user_pages.c
@@ -220,7 +220,7 @@ void ipath_release_user_pages_on_close(struct page **p, size_t num_pages)
work->mm = mm;
work->num_pages = num_pages;
- schedule_work(&work->work);
+ queue_work(ib_wq, &work->work);
return;
bail_mm:
diff --git a/drivers/infiniband/hw/mlx4/main.c b/drivers/infiniband/hw/mlx4/main.c
index 4c85224..c7a6213 100644
--- a/drivers/infiniband/hw/mlx4/main.c
+++ b/drivers/infiniband/hw/mlx4/main.c
@@ -623,8 +623,9 @@ static int mlx4_ib_mcg_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
struct mlx4_ib_dev *mdev = to_mdev(ibqp->device);
struct mlx4_ib_qp *mqp = to_mqp(ibqp);
- err = mlx4_multicast_attach(mdev->dev, &mqp->mqp, gid->raw, !!(mqp->flags &
- MLX4_IB_QP_BLOCK_MULTICAST_LOOPBACK));
+ err = mlx4_multicast_attach(mdev->dev, &mqp->mqp, gid->raw,
+ !!(mqp->flags & MLX4_IB_QP_BLOCK_MULTICAST_LOOPBACK),
+ MLX4_PROTOCOL_IB);
if (err)
return err;
@@ -635,7 +636,7 @@ static int mlx4_ib_mcg_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
return 0;
err_add:
- mlx4_multicast_detach(mdev->dev, &mqp->mqp, gid->raw);
+ mlx4_multicast_detach(mdev->dev, &mqp->mqp, gid->raw, MLX4_PROTOCOL_IB);
return err;
}
@@ -665,7 +666,7 @@ static int mlx4_ib_mcg_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
struct mlx4_ib_gid_entry *ge;
err = mlx4_multicast_detach(mdev->dev,
- &mqp->mqp, gid->raw);
+ &mqp->mqp, gid->raw, MLX4_PROTOCOL_IB);
if (err)
return err;
@@ -1005,7 +1006,8 @@ static void *mlx4_ib_add(struct mlx4_dev *dev)
if (mlx4_uar_alloc(dev, &ibdev->priv_uar))
goto err_pd;
- ibdev->uar_map = ioremap(ibdev->priv_uar.pfn << PAGE_SHIFT, PAGE_SIZE);
+ ibdev->uar_map = ioremap((phys_addr_t) ibdev->priv_uar.pfn << PAGE_SHIFT,
+ PAGE_SIZE);
if (!ibdev->uar_map)
goto err_uar;
MLX4_INIT_DOORBELL_LOCK(&ibdev->uar_lock);
diff --git a/drivers/infiniband/hw/mthca/Kconfig b/drivers/infiniband/hw/mthca/Kconfig
index 03efc07..da314c3 100644
--- a/drivers/infiniband/hw/mthca/Kconfig
+++ b/drivers/infiniband/hw/mthca/Kconfig
@@ -7,7 +7,7 @@ config INFINIBAND_MTHCA
("Tavor") and the MT25208 PCI Express HCA ("Arbel").
config INFINIBAND_MTHCA_DEBUG
- bool "Verbose debugging output" if EMBEDDED
+ bool "Verbose debugging output" if EXPERT
depends on INFINIBAND_MTHCA
default y
---help---
diff --git a/drivers/infiniband/hw/mthca/mthca_catas.c b/drivers/infiniband/hw/mthca/mthca_catas.c
index 0aa0110..e4a08c2 100644
--- a/drivers/infiniband/hw/mthca/mthca_catas.c
+++ b/drivers/infiniband/hw/mthca/mthca_catas.c
@@ -146,7 +146,7 @@ static void poll_catas(unsigned long dev_ptr)
void mthca_start_catas_poll(struct mthca_dev *dev)
{
- unsigned long addr;
+ phys_addr_t addr;
init_timer(&dev->catas_err.timer);
dev->catas_err.map = NULL;
@@ -158,7 +158,8 @@ void mthca_start_catas_poll(struct mthca_dev *dev)
dev->catas_err.map = ioremap(addr, dev->catas_err.size * 4);
if (!dev->catas_err.map) {
mthca_warn(dev, "couldn't map catastrophic error region "
- "at 0x%lx/0x%x\n", addr, dev->catas_err.size * 4);
+ "at 0x%llx/0x%x\n", (unsigned long long) addr,
+ dev->catas_err.size * 4);
return;
}
diff --git a/drivers/infiniband/hw/mthca/mthca_cmd.c b/drivers/infiniband/hw/mthca/mthca_cmd.c
index f4ceecd..7bfa2a1 100644
--- a/drivers/infiniband/hw/mthca/mthca_cmd.c
+++ b/drivers/infiniband/hw/mthca/mthca_cmd.c
@@ -713,7 +713,7 @@ int mthca_RUN_FW(struct mthca_dev *dev, u8 *status)
static void mthca_setup_cmd_doorbells(struct mthca_dev *dev, u64 base)
{
- unsigned long addr;
+ phys_addr_t addr;
u16 max_off = 0;
int i;
diff --git a/drivers/infiniband/hw/mthca/mthca_eq.c b/drivers/infiniband/hw/mthca/mthca_eq.c
index 8e8c728..76785c6 100644
--- a/drivers/infiniband/hw/mthca/mthca_eq.c
+++ b/drivers/infiniband/hw/mthca/mthca_eq.c
@@ -653,7 +653,7 @@ static int mthca_map_reg(struct mthca_dev *dev,
unsigned long offset, unsigned long size,
void __iomem **map)
{
- unsigned long base = pci_resource_start(dev->pdev, 0);
+ phys_addr_t base = pci_resource_start(dev->pdev, 0);
*map = ioremap(base + offset, size);
if (!*map)
diff --git a/drivers/infiniband/hw/mthca/mthca_main.c b/drivers/infiniband/hw/mthca/mthca_main.c
index 5eee666..8a40cd53 100644
--- a/drivers/infiniband/hw/mthca/mthca_main.c
+++ b/drivers/infiniband/hw/mthca/mthca_main.c
@@ -790,7 +790,7 @@ static int mthca_setup_hca(struct mthca_dev *dev)
goto err_uar_table_free;
}
- dev->kar = ioremap(dev->driver_uar.pfn << PAGE_SHIFT, PAGE_SIZE);
+ dev->kar = ioremap((phys_addr_t) dev->driver_uar.pfn << PAGE_SHIFT, PAGE_SIZE);
if (!dev->kar) {
mthca_err(dev, "Couldn't map kernel access region, "
"aborting.\n");
diff --git a/drivers/infiniband/hw/mthca/mthca_mr.c b/drivers/infiniband/hw/mthca/mthca_mr.c
index 065b208..44045c8 100644
--- a/drivers/infiniband/hw/mthca/mthca_mr.c
+++ b/drivers/infiniband/hw/mthca/mthca_mr.c
@@ -853,7 +853,7 @@ void mthca_arbel_fmr_unmap(struct mthca_dev *dev, struct mthca_fmr *fmr)
int mthca_init_mr_table(struct mthca_dev *dev)
{
- unsigned long addr;
+ phys_addr_t addr;
int mpts, mtts, err, i;
err = mthca_alloc_init(&dev->mr_table.mpt_alloc,
diff --git a/drivers/infiniband/hw/nes/nes.c b/drivers/infiniband/hw/nes/nes.c
index 0c9f0aa..3b4ec32 100644
--- a/drivers/infiniband/hw/nes/nes.c
+++ b/drivers/infiniband/hw/nes/nes.c
@@ -144,6 +144,7 @@ static int nes_inetaddr_event(struct notifier_block *notifier,
struct nes_device *nesdev;
struct net_device *netdev;
struct nes_vnic *nesvnic;
+ unsigned int is_bonded;
nes_debug(NES_DBG_NETDEV, "nes_inetaddr_event: ip address %pI4, netmask %pI4.\n",
&ifa->ifa_address, &ifa->ifa_mask);
@@ -152,7 +153,8 @@ static int nes_inetaddr_event(struct notifier_block *notifier,
nesdev, nesdev->netdev[0]->name);
netdev = nesdev->netdev[0];
nesvnic = netdev_priv(netdev);
- if (netdev == event_netdev) {
+ is_bonded = (netdev->master == event_netdev);
+ if ((netdev == event_netdev) || is_bonded) {
if (nesvnic->rdma_enabled == 0) {
nes_debug(NES_DBG_NETDEV, "Returning without processing event for %s since"
" RDMA is not enabled.\n",
@@ -169,7 +171,10 @@ static int nes_inetaddr_event(struct notifier_block *notifier,
nes_manage_arp_cache(netdev, netdev->dev_addr,
ntohl(nesvnic->local_ipaddr), NES_ARP_DELETE);
nesvnic->local_ipaddr = 0;
- return NOTIFY_OK;
+ if (is_bonded)
+ continue;
+ else
+ return NOTIFY_OK;
break;
case NETDEV_UP:
nes_debug(NES_DBG_NETDEV, "event:UP\n");
@@ -178,15 +183,24 @@ static int nes_inetaddr_event(struct notifier_block *notifier,
nes_debug(NES_DBG_NETDEV, "Interface already has local_ipaddr\n");
return NOTIFY_OK;
}
+ /* fall through */
+ case NETDEV_CHANGEADDR:
/* Add the address to the IP table */
- nesvnic->local_ipaddr = ifa->ifa_address;
+ if (netdev->master)
+ nesvnic->local_ipaddr =
+ ((struct in_device *)netdev->master->ip_ptr)->ifa_list->ifa_address;
+ else
+ nesvnic->local_ipaddr = ifa->ifa_address;
nes_write_indexed(nesdev,
NES_IDX_DST_IP_ADDR+(0x10*PCI_FUNC(nesdev->pcidev->devfn)),
- ntohl(ifa->ifa_address));
+ ntohl(nesvnic->local_ipaddr));
nes_manage_arp_cache(netdev, netdev->dev_addr,
ntohl(nesvnic->local_ipaddr), NES_ARP_ADD);
- return NOTIFY_OK;
+ if (is_bonded)
+ continue;
+ else
+ return NOTIFY_OK;
break;
default:
break;
@@ -660,6 +674,8 @@ static int __devinit nes_probe(struct pci_dev *pcidev, const struct pci_device_i
}
nes_notifiers_registered++;
+ INIT_DELAYED_WORK(&nesdev->work, nes_recheck_link_status);
+
/* Initialize network devices */
if ((netdev = nes_netdev_init(nesdev, mmio_regs)) == NULL)
goto bail7;
@@ -742,6 +758,7 @@ static void __devexit nes_remove(struct pci_dev *pcidev)
struct nes_device *nesdev = pci_get_drvdata(pcidev);
struct net_device *netdev;
int netdev_index = 0;
+ unsigned long flags;
if (nesdev->netdev_count) {
netdev = nesdev->netdev[netdev_index];
@@ -768,6 +785,14 @@ static void __devexit nes_remove(struct pci_dev *pcidev)
free_irq(pcidev->irq, nesdev);
tasklet_kill(&nesdev->dpc_tasklet);
+ spin_lock_irqsave(&nesdev->nesadapter->phy_lock, flags);
+ if (nesdev->link_recheck) {
+ spin_unlock_irqrestore(&nesdev->nesadapter->phy_lock, flags);
+ cancel_delayed_work_sync(&nesdev->work);
+ } else {
+ spin_unlock_irqrestore(&nesdev->nesadapter->phy_lock, flags);
+ }
+
/* Deallocate the Adapter Structure */
nes_destroy_adapter(nesdev->nesadapter);
diff --git a/drivers/infiniband/hw/nes/nes.h b/drivers/infiniband/hw/nes/nes.h
index b3d145e..6fe7987 100644
--- a/drivers/infiniband/hw/nes/nes.h
+++ b/drivers/infiniband/hw/nes/nes.h
@@ -268,6 +268,9 @@ struct nes_device {
u8 napi_isr_ran;
u8 disable_rx_flow_control;
u8 disable_tx_flow_control;
+
+ struct delayed_work work;
+ u8 link_recheck;
};
@@ -507,6 +510,7 @@ void nes_nic_ce_handler(struct nes_device *, struct nes_hw_nic_cq *);
void nes_iwarp_ce_handler(struct nes_device *, struct nes_hw_cq *);
int nes_destroy_cqp(struct nes_device *);
int nes_nic_cm_xmit(struct sk_buff *, struct net_device *);
+void nes_recheck_link_status(struct work_struct *work);
/* nes_nic.c */
struct net_device *nes_netdev_init(struct nes_device *, void __iomem *);
diff --git a/drivers/infiniband/hw/nes/nes_cm.c b/drivers/infiniband/hw/nes/nes_cm.c
index 25ad0f9..009ec81 100644
--- a/drivers/infiniband/hw/nes/nes_cm.c
+++ b/drivers/infiniband/hw/nes/nes_cm.c
@@ -1107,6 +1107,7 @@ static int nes_addr_resolve_neigh(struct nes_vnic *nesvnic, u32 dst_ip, int arpi
struct flowi fl;
struct neighbour *neigh;
int rc = arpindex;
+ struct net_device *netdev;
struct nes_adapter *nesadapter = nesvnic->nesdev->nesadapter;
memset(&fl, 0, sizeof fl);
@@ -1117,7 +1118,12 @@ static int nes_addr_resolve_neigh(struct nes_vnic *nesvnic, u32 dst_ip, int arpi
return rc;
}
- neigh = neigh_lookup(&arp_tbl, &rt->rt_gateway, nesvnic->netdev);
+ if (nesvnic->netdev->master)
+ netdev = nesvnic->netdev->master;
+ else
+ netdev = nesvnic->netdev;
+
+ neigh = neigh_lookup(&arp_tbl, &rt->rt_gateway, netdev);
if (neigh) {
if (neigh->nud_state & NUD_VALID) {
nes_debug(NES_DBG_CM, "Neighbor MAC address for 0x%08X"
diff --git a/drivers/infiniband/hw/nes/nes_hw.c b/drivers/infiniband/hw/nes/nes_hw.c
index 1980a46..8b606fd 100644
--- a/drivers/infiniband/hw/nes/nes_hw.c
+++ b/drivers/infiniband/hw/nes/nes_hw.c
@@ -2608,6 +2608,13 @@ static void nes_process_mac_intr(struct nes_device *nesdev, u32 mac_number)
netif_start_queue(nesvnic->netdev);
nesvnic->linkup = 1;
netif_carrier_on(nesvnic->netdev);
+
+ spin_lock(&nesvnic->port_ibevent_lock);
+ if (nesdev->iw_status == 0) {
+ nesdev->iw_status = 1;
+ nes_port_ibevent(nesvnic);
+ }
+ spin_unlock(&nesvnic->port_ibevent_lock);
}
}
} else {
@@ -2633,9 +2640,23 @@ static void nes_process_mac_intr(struct nes_device *nesdev, u32 mac_number)
netif_stop_queue(nesvnic->netdev);
nesvnic->linkup = 0;
netif_carrier_off(nesvnic->netdev);
+
+ spin_lock(&nesvnic->port_ibevent_lock);
+ if (nesdev->iw_status == 1) {
+ nesdev->iw_status = 0;
+ nes_port_ibevent(nesvnic);
+ }
+ spin_unlock(&nesvnic->port_ibevent_lock);
}
}
}
+ if (nesadapter->phy_type[mac_index] == NES_PHY_TYPE_SFP_D) {
+ if (nesdev->link_recheck)
+ cancel_delayed_work(&nesdev->work);
+ nesdev->link_recheck = 1;
+ schedule_delayed_work(&nesdev->work,
+ NES_LINK_RECHECK_DELAY);
+ }
}
spin_unlock_irqrestore(&nesadapter->phy_lock, flags);
@@ -2643,6 +2664,80 @@ static void nes_process_mac_intr(struct nes_device *nesdev, u32 mac_number)
nesadapter->mac_sw_state[mac_number] = NES_MAC_SW_IDLE;
}
+void nes_recheck_link_status(struct work_struct *work)
+{
+ unsigned long flags;
+ struct nes_device *nesdev = container_of(work, struct nes_device, work.work);
+ struct nes_adapter *nesadapter = nesdev->nesadapter;
+ struct nes_vnic *nesvnic;
+ u32 mac_index = nesdev->mac_index;
+ u16 phy_data;
+ u16 temp_phy_data;
+
+ spin_lock_irqsave(&nesadapter->phy_lock, flags);
+
+ /* check link status */
+ nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 1, 0x9003);
+ temp_phy_data = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL);
+
+ nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 3, 0x0021);
+ nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL);
+ nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 3, 0x0021);
+ phy_data = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL);
+
+ phy_data = (!temp_phy_data && (phy_data == 0x8000)) ? 0x4 : 0x0;
+
+ nes_debug(NES_DBG_PHY, "%s: Phy data = 0x%04X, link was %s.\n",
+ __func__, phy_data,
+ nesadapter->mac_link_down[mac_index] ? "DOWN" : "UP");
+
+ if (phy_data & 0x0004) {
+ nesadapter->mac_link_down[mac_index] = 0;
+ list_for_each_entry(nesvnic, &nesadapter->nesvnic_list[mac_index], list) {
+ if (nesvnic->linkup == 0) {
+ printk(PFX "The Link is now up for port %s, netdev %p.\n",
+ nesvnic->netdev->name, nesvnic->netdev);
+ if (netif_queue_stopped(nesvnic->netdev))
+ netif_start_queue(nesvnic->netdev);
+ nesvnic->linkup = 1;
+ netif_carrier_on(nesvnic->netdev);
+
+ spin_lock(&nesvnic->port_ibevent_lock);
+ if (nesdev->iw_status == 0) {
+ nesdev->iw_status = 1;
+ nes_port_ibevent(nesvnic);
+ }
+ spin_unlock(&nesvnic->port_ibevent_lock);
+ }
+ }
+
+ } else {
+ nesadapter->mac_link_down[mac_index] = 1;
+ list_for_each_entry(nesvnic, &nesadapter->nesvnic_list[mac_index], list) {
+ if (nesvnic->linkup == 1) {
+ printk(PFX "The Link is now down for port %s, netdev %p.\n",
+ nesvnic->netdev->name, nesvnic->netdev);
+ if (!(netif_queue_stopped(nesvnic->netdev)))
+ netif_stop_queue(nesvnic->netdev);
+ nesvnic->linkup = 0;
+ netif_carrier_off(nesvnic->netdev);
+
+ spin_lock(&nesvnic->port_ibevent_lock);
+ if (nesdev->iw_status == 1) {
+ nesdev->iw_status = 0;
+ nes_port_ibevent(nesvnic);
+ }
+ spin_unlock(&nesvnic->port_ibevent_lock);
+ }
+ }
+ }
+ if (nesdev->link_recheck++ < NES_LINK_RECHECK_MAX)
+ schedule_delayed_work(&nesdev->work, NES_LINK_RECHECK_DELAY);
+ else
+ nesdev->link_recheck = 0;
+
+ spin_unlock_irqrestore(&nesadapter->phy_lock, flags);
+}
static void nes_nic_napi_ce_handler(struct nes_device *nesdev, struct nes_hw_nic_cq *cq)
diff --git a/drivers/infiniband/hw/nes/nes_hw.h b/drivers/infiniband/hw/nes/nes_hw.h
index 1204c34..d2abe07 100644
--- a/drivers/infiniband/hw/nes/nes_hw.h
+++ b/drivers/infiniband/hw/nes/nes_hw.h
@@ -1193,6 +1193,8 @@ struct nes_listener {
struct nes_ib_device;
+#define NES_EVENT_DELAY msecs_to_jiffies(100)
+
struct nes_vnic {
struct nes_ib_device *nesibdev;
u64 sq_full;
@@ -1247,6 +1249,10 @@ struct nes_vnic {
u32 lro_max_aggr;
struct net_lro_mgr lro_mgr;
struct net_lro_desc lro_desc[NES_MAX_LRO_DESCRIPTORS];
+ struct timer_list event_timer;
+ enum ib_event_type delayed_event;
+ enum ib_event_type last_dispatched_event;
+ spinlock_t port_ibevent_lock;
};
struct nes_ib_device {
@@ -1348,6 +1354,10 @@ struct nes_terminate_hdr {
#define BAD_FRAME_OFFSET 64
#define CQE_MAJOR_DRV 0x8000
+/* Used for link status recheck after interrupt processing */
+#define NES_LINK_RECHECK_DELAY msecs_to_jiffies(50)
+#define NES_LINK_RECHECK_MAX 60
+
#define nes_vlan_rx vlan_hwaccel_receive_skb
#define nes_netif_rx netif_receive_skb
diff --git a/drivers/infiniband/hw/nes/nes_nic.c b/drivers/infiniband/hw/nes/nes_nic.c
index 5a4c364..2c9c193 100644
--- a/drivers/infiniband/hw/nes/nes_nic.c
+++ b/drivers/infiniband/hw/nes/nes_nic.c
@@ -144,6 +144,7 @@ static int nes_netdev_open(struct net_device *netdev)
u32 nic_active_bit;
u32 nic_active;
struct list_head *list_pos, *list_temp;
+ unsigned long flags;
assert(nesdev != NULL);
@@ -233,18 +234,36 @@ static int nes_netdev_open(struct net_device *netdev)
first_nesvnic = nesvnic;
}
- if (nesvnic->of_device_registered) {
- nesdev->iw_status = 1;
- nesdev->nesadapter->send_term_ok = 1;
- nes_port_ibevent(nesvnic);
- }
-
if (first_nesvnic->linkup) {
/* Enable network packets */
nesvnic->linkup = 1;
netif_start_queue(netdev);
netif_carrier_on(netdev);
}
+
+ spin_lock_irqsave(&nesdev->nesadapter->phy_lock, flags);
+ if (nesdev->nesadapter->phy_type[nesdev->mac_index] == NES_PHY_TYPE_SFP_D) {
+ if (nesdev->link_recheck)
+ cancel_delayed_work(&nesdev->work);
+ nesdev->link_recheck = 1;
+ schedule_delayed_work(&nesdev->work, NES_LINK_RECHECK_DELAY);
+ }
+ spin_unlock_irqrestore(&nesdev->nesadapter->phy_lock, flags);
+
+ spin_lock_irqsave(&nesvnic->port_ibevent_lock, flags);
+ if (nesvnic->of_device_registered) {
+ nesdev->nesadapter->send_term_ok = 1;
+ if (nesvnic->linkup == 1) {
+ if (nesdev->iw_status == 0) {
+ nesdev->iw_status = 1;
+ nes_port_ibevent(nesvnic);
+ }
+ } else {
+ nesdev->iw_status = 0;
+ }
+ }
+ spin_unlock_irqrestore(&nesvnic->port_ibevent_lock, flags);
+
napi_enable(&nesvnic->napi);
nesvnic->netdev_open = 1;
@@ -263,6 +282,7 @@ static int nes_netdev_stop(struct net_device *netdev)
u32 nic_active;
struct nes_vnic *first_nesvnic = NULL;
struct list_head *list_pos, *list_temp;
+ unsigned long flags;
nes_debug(NES_DBG_SHUTDOWN, "nesvnic=%p, nesdev=%p, netdev=%p %s\n",
nesvnic, nesdev, netdev, netdev->name);
@@ -315,12 +335,17 @@ static int nes_netdev_stop(struct net_device *netdev)
nic_active &= nic_active_mask;
nes_write_indexed(nesdev, NES_IDX_NIC_BROADCAST_ON, nic_active);
-
+ spin_lock_irqsave(&nesvnic->port_ibevent_lock, flags);
if (nesvnic->of_device_registered) {
nesdev->nesadapter->send_term_ok = 0;
nesdev->iw_status = 0;
- nes_port_ibevent(nesvnic);
+ if (nesvnic->linkup == 1)
+ nes_port_ibevent(nesvnic);
}
+ del_timer_sync(&nesvnic->event_timer);
+ nesvnic->event_timer.function = NULL;
+ spin_unlock_irqrestore(&nesvnic->port_ibevent_lock, flags);
+
nes_destroy_nic_qp(nesvnic);
nesvnic->netdev_open = 0;
@@ -1750,7 +1775,10 @@ struct net_device *nes_netdev_init(struct nes_device *nesdev,
nesvnic->rdma_enabled = 0;
}
nesvnic->nic_cq.cq_number = nesvnic->nic.qp_id;
+ init_timer(&nesvnic->event_timer);
+ nesvnic->event_timer.function = NULL;
spin_lock_init(&nesvnic->tx_lock);
+ spin_lock_init(&nesvnic->port_ibevent_lock);
nesdev->netdev[nesdev->netdev_count] = netdev;
nes_debug(NES_DBG_INIT, "Adding nesvnic (%p) to the adapters nesvnic_list for MAC%d.\n",
@@ -1763,8 +1791,11 @@ struct net_device *nes_netdev_init(struct nes_device *nesdev,
(((PCI_FUNC(nesdev->pcidev->devfn) == 1) && (nesdev->mac_index == 2)) ||
((PCI_FUNC(nesdev->pcidev->devfn) == 2) && (nesdev->mac_index == 1)))))) {
u32 u32temp;
- u32 link_mask;
- u32 link_val;
+ u32 link_mask = 0;
+ u32 link_val = 0;
+ u16 temp_phy_data;
+ u16 phy_data = 0;
+ unsigned long flags;
u32temp = nes_read_indexed(nesdev, NES_IDX_PHY_PCS_CONTROL_STATUS0 +
(0x200 * (nesdev->mac_index & 1)));
@@ -1786,6 +1817,23 @@ struct net_device *nes_netdev_init(struct nes_device *nesdev,
link_val = 0x02020000;
}
break;
+ case NES_PHY_TYPE_SFP_D:
+ spin_lock_irqsave(&nesdev->nesadapter->phy_lock, flags);
+ nes_read_10G_phy_reg(nesdev,
+ nesdev->nesadapter->phy_index[nesdev->mac_index],
+ 1, 0x9003);
+ temp_phy_data = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL);
+ nes_read_10G_phy_reg(nesdev,
+ nesdev->nesadapter->phy_index[nesdev->mac_index],
+ 3, 0x0021);
+ nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL);
+ nes_read_10G_phy_reg(nesdev,
+ nesdev->nesadapter->phy_index[nesdev->mac_index],
+ 3, 0x0021);
+ phy_data = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL);
+ spin_unlock_irqrestore(&nesdev->nesadapter->phy_lock, flags);
+ phy_data = (!temp_phy_data && (phy_data == 0x8000)) ? 0x4 : 0x0;
+ break;
default:
link_mask = 0x0f1f0000;
link_val = 0x0f0f0000;
@@ -1795,8 +1843,14 @@ struct net_device *nes_netdev_init(struct nes_device *nesdev,
u32temp = nes_read_indexed(nesdev,
NES_IDX_PHY_PCS_CONTROL_STATUS0 +
(0x200 * (nesdev->mac_index & 1)));
- if ((u32temp & link_mask) == link_val)
- nesvnic->linkup = 1;
+
+ if (phy_type == NES_PHY_TYPE_SFP_D) {
+ if (phy_data & 0x0004)
+ nesvnic->linkup = 1;
+ } else {
+ if ((u32temp & link_mask) == link_val)
+ nesvnic->linkup = 1;
+ }
/* clear the MAC interrupt status, assumes direct logical to physical mapping */
u32temp = nes_read_indexed(nesdev, NES_IDX_MAC_INT_STATUS + (0x200 * nesdev->mac_index));
diff --git a/drivers/infiniband/hw/nes/nes_verbs.c b/drivers/infiniband/hw/nes/nes_verbs.c
index 99933e4..26d8018 100644
--- a/drivers/infiniband/hw/nes/nes_verbs.c
+++ b/drivers/infiniband/hw/nes/nes_verbs.c
@@ -3936,6 +3936,30 @@ struct nes_ib_device *nes_init_ofa_device(struct net_device *netdev)
return nesibdev;
}
+
+/**
+ * nes_handle_delayed_event
+ */
+static void nes_handle_delayed_event(unsigned long data)
+{
+ struct nes_vnic *nesvnic = (void *) data;
+
+ if (nesvnic->delayed_event != nesvnic->last_dispatched_event) {
+ struct ib_event event;
+
+ event.device = &nesvnic->nesibdev->ibdev;
+ if (!event.device)
+ goto stop_timer;
+ event.event = nesvnic->delayed_event;
+ event.element.port_num = nesvnic->logical_port + 1;
+ ib_dispatch_event(&event);
+ }
+
+stop_timer:
+ nesvnic->event_timer.function = NULL;
+}
+
+
void nes_port_ibevent(struct nes_vnic *nesvnic)
{
struct nes_ib_device *nesibdev = nesvnic->nesibdev;
@@ -3944,7 +3968,18 @@ void nes_port_ibevent(struct nes_vnic *nesvnic)
event.device = &nesibdev->ibdev;
event.element.port_num = nesvnic->logical_port + 1;
event.event = nesdev->iw_status ? IB_EVENT_PORT_ACTIVE : IB_EVENT_PORT_ERR;
- ib_dispatch_event(&event);
+
+ if (!nesvnic->event_timer.function) {
+ ib_dispatch_event(&event);
+ nesvnic->last_dispatched_event = event.event;
+ nesvnic->event_timer.function = nes_handle_delayed_event;
+ nesvnic->event_timer.data = (unsigned long) nesvnic;
+ nesvnic->event_timer.expires = jiffies + NES_EVENT_DELAY;
+ add_timer(&nesvnic->event_timer);
+ } else {
+ mod_timer(&nesvnic->event_timer, jiffies + NES_EVENT_DELAY);
+ }
+ nesvnic->delayed_event = event.event;
}
diff --git a/drivers/infiniband/hw/qib/qib_iba7220.c b/drivers/infiniband/hw/qib/qib_iba7220.c
index 127a0d5..de799f1 100644
--- a/drivers/infiniband/hw/qib/qib_iba7220.c
+++ b/drivers/infiniband/hw/qib/qib_iba7220.c
@@ -1692,8 +1692,7 @@ static void qib_7220_quiet_serdes(struct qib_pportdata *ppd)
ppd->lflags &= ~QIBL_IB_AUTONEG_INPROG;
spin_unlock_irqrestore(&ppd->lflags_lock, flags);
wake_up(&ppd->cpspec->autoneg_wait);
- cancel_delayed_work(&ppd->cpspec->autoneg_work);
- flush_scheduled_work();
+ cancel_delayed_work_sync(&ppd->cpspec->autoneg_work);
shutdown_7220_relock_poll(ppd->dd);
val = qib_read_kreg64(ppd->dd, kr_xgxs_cfg);
@@ -3515,8 +3514,8 @@ static void try_7220_autoneg(struct qib_pportdata *ppd)
toggle_7220_rclkrls(ppd->dd);
/* 2 msec is minimum length of a poll cycle */
- schedule_delayed_work(&ppd->cpspec->autoneg_work,
- msecs_to_jiffies(2));
+ queue_delayed_work(ib_wq, &ppd->cpspec->autoneg_work,
+ msecs_to_jiffies(2));
}
/*
diff --git a/drivers/infiniband/hw/qib/qib_iba7322.c b/drivers/infiniband/hw/qib/qib_iba7322.c
index abd409d..50cceb3 100644
--- a/drivers/infiniband/hw/qib/qib_iba7322.c
+++ b/drivers/infiniband/hw/qib/qib_iba7322.c
@@ -2406,10 +2406,9 @@ static void qib_7322_mini_quiet_serdes(struct qib_pportdata *ppd)
ppd->lflags &= ~QIBL_IB_AUTONEG_INPROG;
spin_unlock_irqrestore(&ppd->lflags_lock, flags);
wake_up(&ppd->cpspec->autoneg_wait);
- cancel_delayed_work(&ppd->cpspec->autoneg_work);
+ cancel_delayed_work_sync(&ppd->cpspec->autoneg_work);
if (ppd->dd->cspec->r1)
- cancel_delayed_work(&ppd->cpspec->ipg_work);
- flush_scheduled_work();
+ cancel_delayed_work_sync(&ppd->cpspec->ipg_work);
ppd->cpspec->chase_end = 0;
if (ppd->cpspec->chase_timer.data) /* if initted */
@@ -2706,7 +2705,7 @@ static noinline void unknown_7322_gpio_intr(struct qib_devdata *dd)
if (!(pins & mask)) {
++handled;
qd->t_insert = get_jiffies_64();
- schedule_work(&qd->work);
+ queue_work(ib_wq, &qd->work);
}
}
}
@@ -4990,8 +4989,8 @@ static void try_7322_autoneg(struct qib_pportdata *ppd)
set_7322_ibspeed_fast(ppd, QIB_IB_DDR);
qib_7322_mini_pcs_reset(ppd);
/* 2 msec is minimum length of a poll cycle */
- schedule_delayed_work(&ppd->cpspec->autoneg_work,
- msecs_to_jiffies(2));
+ queue_delayed_work(ib_wq, &ppd->cpspec->autoneg_work,
+ msecs_to_jiffies(2));
}
/*
@@ -5121,7 +5120,8 @@ static void try_7322_ipg(struct qib_pportdata *ppd)
ib_free_send_mad(send_buf);
retry:
delay = 2 << ppd->cpspec->ipg_tries;
- schedule_delayed_work(&ppd->cpspec->ipg_work, msecs_to_jiffies(delay));
+ queue_delayed_work(ib_wq, &ppd->cpspec->ipg_work,
+ msecs_to_jiffies(delay));
}
/*
diff --git a/drivers/infiniband/hw/qib/qib_init.c b/drivers/infiniband/hw/qib/qib_init.c
index 7896afb..ffefb78 100644
--- a/drivers/infiniband/hw/qib/qib_init.c
+++ b/drivers/infiniband/hw/qib/qib_init.c
@@ -80,7 +80,6 @@ unsigned qib_wc_pat = 1; /* default (1) is to use PAT, not MTRR */
module_param_named(wc_pat, qib_wc_pat, uint, S_IRUGO);
MODULE_PARM_DESC(wc_pat, "enable write-combining via PAT mechanism");
-struct workqueue_struct *qib_wq;
struct workqueue_struct *qib_cq_wq;
static void verify_interrupt(unsigned long);
@@ -270,23 +269,20 @@ static void init_shadow_tids(struct qib_devdata *dd)
struct page **pages;
dma_addr_t *addrs;
- pages = vmalloc(dd->cfgctxts * dd->rcvtidcnt * sizeof(struct page *));
+ pages = vzalloc(dd->cfgctxts * dd->rcvtidcnt * sizeof(struct page *));
if (!pages) {
qib_dev_err(dd, "failed to allocate shadow page * "
"array, no expected sends!\n");
goto bail;
}
- addrs = vmalloc(dd->cfgctxts * dd->rcvtidcnt * sizeof(dma_addr_t));
+ addrs = vzalloc(dd->cfgctxts * dd->rcvtidcnt * sizeof(dma_addr_t));
if (!addrs) {
qib_dev_err(dd, "failed to allocate shadow dma handle "
"array, no expected sends!\n");
goto bail_free;
}
- memset(pages, 0, dd->cfgctxts * dd->rcvtidcnt * sizeof(struct page *));
- memset(addrs, 0, dd->cfgctxts * dd->rcvtidcnt * sizeof(dma_addr_t));
-
dd->pageshadow = pages;
dd->physshadow = addrs;
return;
@@ -1047,24 +1043,10 @@ static int __init qlogic_ib_init(void)
if (ret)
goto bail;
- /*
- * We create our own workqueue mainly because we want to be
- * able to flush it when devices are being removed. We can't
- * use schedule_work()/flush_scheduled_work() because both
- * unregister_netdev() and linkwatch_event take the rtnl lock,
- * so flush_scheduled_work() can deadlock during device
- * removal.
- */
- qib_wq = create_workqueue("qib");
- if (!qib_wq) {
- ret = -ENOMEM;
- goto bail_dev;
- }
-
qib_cq_wq = create_singlethread_workqueue("qib_cq");
if (!qib_cq_wq) {
ret = -ENOMEM;
- goto bail_wq;
+ goto bail_dev;
}
/*
@@ -1094,8 +1076,6 @@ bail_unit:
idr_destroy(&qib_unit_table);
bail_cq_wq:
destroy_workqueue(qib_cq_wq);
-bail_wq:
- destroy_workqueue(qib_wq);
bail_dev:
qib_dev_cleanup();
bail:
@@ -1119,7 +1099,6 @@ static void __exit qlogic_ib_cleanup(void)
pci_unregister_driver(&qib_driver);
- destroy_workqueue(qib_wq);
destroy_workqueue(qib_cq_wq);
qib_cpulist_count = 0;
@@ -1292,7 +1271,7 @@ static int __devinit qib_init_one(struct pci_dev *pdev,
if (qib_mini_init || initfail || ret) {
qib_stop_timers(dd);
- flush_scheduled_work();
+ flush_workqueue(ib_wq);
for (pidx = 0; pidx < dd->num_pports; ++pidx)
dd->f_quiet_serdes(dd->pport + pidx);
if (qib_mini_init)
@@ -1341,8 +1320,8 @@ static void __devexit qib_remove_one(struct pci_dev *pdev)
qib_stop_timers(dd);
- /* wait until all of our (qsfp) schedule_work() calls complete */
- flush_scheduled_work();
+ /* wait until all of our (qsfp) queue_work() calls complete */
+ flush_workqueue(ib_wq);
ret = qibfs_remove(dd);
if (ret)
diff --git a/drivers/infiniband/hw/qib/qib_qsfp.c b/drivers/infiniband/hw/qib/qib_qsfp.c
index 35b3604..3374a52 100644
--- a/drivers/infiniband/hw/qib/qib_qsfp.c
+++ b/drivers/infiniband/hw/qib/qib_qsfp.c
@@ -485,7 +485,7 @@ void qib_qsfp_init(struct qib_qsfp_data *qd,
goto bail;
/* We see a module, but it may be unwise to look yet. Just schedule */
qd->t_insert = get_jiffies_64();
- schedule_work(&qd->work);
+ queue_work(ib_wq, &qd->work);
bail:
return;
}
@@ -493,10 +493,9 @@ bail:
void qib_qsfp_deinit(struct qib_qsfp_data *qd)
{
/*
- * There is nothing to do here for now. our
- * work is scheduled with schedule_work(), and
- * flush_scheduled_work() from remove_one will
- * block until all work ssetup with schedule_work()
+ * There is nothing to do here for now. our work is scheduled
+ * with queue_work(), and flush_workqueue() from remove_one
+ * will block until all work setup with queue_work()
* completes.
*/
}
diff --git a/drivers/infiniband/hw/qib/qib_verbs.h b/drivers/infiniband/hw/qib/qib_verbs.h
index 63b22a9..95e5b47 100644
--- a/drivers/infiniband/hw/qib/qib_verbs.h
+++ b/drivers/infiniband/hw/qib/qib_verbs.h
@@ -805,7 +805,6 @@ static inline int qib_send_ok(struct qib_qp *qp)
!(qp->s_flags & QIB_S_ANY_WAIT_SEND));
}
-extern struct workqueue_struct *qib_wq;
extern struct workqueue_struct *qib_cq_wq;
/*
@@ -814,7 +813,7 @@ extern struct workqueue_struct *qib_cq_wq;
static inline void qib_schedule_send(struct qib_qp *qp)
{
if (qib_send_ok(qp))
- queue_work(qib_wq, &qp->s_work);
+ queue_work(ib_wq, &qp->s_work);
}
static inline int qib_pkey_ok(u16 pkey1, u16 pkey2)
diff --git a/drivers/infiniband/ulp/ipoib/Kconfig b/drivers/infiniband/ulp/ipoib/Kconfig
index 55855ee..cda8eac 100644
--- a/drivers/infiniband/ulp/ipoib/Kconfig
+++ b/drivers/infiniband/ulp/ipoib/Kconfig
@@ -24,7 +24,7 @@ config INFINIBAND_IPOIB_CM
unless you limit mtu for these destinations to 2044.
config INFINIBAND_IPOIB_DEBUG
- bool "IP-over-InfiniBand debugging" if EMBEDDED
+ bool "IP-over-InfiniBand debugging" if EXPERT
depends on INFINIBAND_IPOIB
default y
---help---
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_cm.c b/drivers/infiniband/ulp/ipoib/ipoib_cm.c
index c1c49f2..93d5580 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_cm.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_cm.c
@@ -352,15 +352,13 @@ static int ipoib_cm_nonsrq_init_rx(struct net_device *dev, struct ib_cm_id *cm_i
int ret;
int i;
- rx->rx_ring = vmalloc(ipoib_recvq_size * sizeof *rx->rx_ring);
+ rx->rx_ring = vzalloc(ipoib_recvq_size * sizeof *rx->rx_ring);
if (!rx->rx_ring) {
printk(KERN_WARNING "%s: failed to allocate CM non-SRQ ring (%d entries)\n",
priv->ca->name, ipoib_recvq_size);
return -ENOMEM;
}
- memset(rx->rx_ring, 0, ipoib_recvq_size * sizeof *rx->rx_ring);
-
t = kmalloc(sizeof *t, GFP_KERNEL);
if (!t) {
ret = -ENOMEM;
@@ -1097,13 +1095,12 @@ static int ipoib_cm_tx_init(struct ipoib_cm_tx *p, u32 qpn,
struct ipoib_dev_priv *priv = netdev_priv(p->dev);
int ret;
- p->tx_ring = vmalloc(ipoib_sendq_size * sizeof *p->tx_ring);
+ p->tx_ring = vzalloc(ipoib_sendq_size * sizeof *p->tx_ring);
if (!p->tx_ring) {
ipoib_warn(priv, "failed to allocate tx ring\n");
ret = -ENOMEM;
goto err_tx;
}
- memset(p->tx_ring, 0, ipoib_sendq_size * sizeof *p->tx_ring);
p->qp = ipoib_cm_create_tx_qp(p->dev, p);
if (IS_ERR(p->qp)) {
@@ -1521,7 +1518,7 @@ static void ipoib_cm_create_srq(struct net_device *dev, int max_sge)
return;
}
- priv->cm.srq_ring = vmalloc(ipoib_recvq_size * sizeof *priv->cm.srq_ring);
+ priv->cm.srq_ring = vzalloc(ipoib_recvq_size * sizeof *priv->cm.srq_ring);
if (!priv->cm.srq_ring) {
printk(KERN_WARNING "%s: failed to allocate CM SRQ ring (%d entries)\n",
priv->ca->name, ipoib_recvq_size);
@@ -1530,7 +1527,6 @@ static void ipoib_cm_create_srq(struct net_device *dev, int max_sge)
return;
}
- memset(priv->cm.srq_ring, 0, ipoib_recvq_size * sizeof *priv->cm.srq_ring);
}
int ipoib_cm_dev_init(struct net_device *dev)
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c
index 7a07a72..aca3b44 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_main.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c
@@ -916,13 +916,12 @@ int ipoib_dev_init(struct net_device *dev, struct ib_device *ca, int port)
goto out;
}
- priv->tx_ring = vmalloc(ipoib_sendq_size * sizeof *priv->tx_ring);
+ priv->tx_ring = vzalloc(ipoib_sendq_size * sizeof *priv->tx_ring);
if (!priv->tx_ring) {
printk(KERN_WARNING "%s: failed to allocate TX ring (%d entries)\n",
ca->name, ipoib_sendq_size);
goto out_rx_ring_cleanup;
}
- memset(priv->tx_ring, 0, ipoib_sendq_size * sizeof *priv->tx_ring);
/* priv->tx_head, tx_tail & tx_outstanding are already 0 */
diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c
index 4b62105..83664ed 100644
--- a/drivers/infiniband/ulp/srp/ib_srp.c
+++ b/drivers/infiniband/ulp/srp/ib_srp.c
@@ -638,7 +638,7 @@ err:
if (target->state == SRP_TARGET_CONNECTING) {
target->state = SRP_TARGET_DEAD;
INIT_WORK(&target->work, srp_remove_work);
- schedule_work(&target->work);
+ queue_work(ib_wq, &target->work);
}
spin_unlock_irq(&target->lock);
@@ -1132,15 +1132,12 @@ static int srp_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *scmnd)
spin_lock_irqsave(&target->lock, flags);
iu = __srp_get_tx_iu(target, SRP_IU_CMD);
- if (iu) {
- req = list_first_entry(&target->free_reqs, struct srp_request,
- list);
- list_del(&req->list);
- }
- spin_unlock_irqrestore(&target->lock, flags);
-
if (!iu)
- goto err;
+ goto err_unlock;
+
+ req = list_first_entry(&target->free_reqs, struct srp_request, list);
+ list_del(&req->list);
+ spin_unlock_irqrestore(&target->lock, flags);
dev = target->srp_host->srp_dev->dev;
ib_dma_sync_single_for_cpu(dev, iu->dma, srp_max_iu_len,
@@ -1185,6 +1182,8 @@ err_iu:
spin_lock_irqsave(&target->lock, flags);
list_add(&req->list, &target->free_reqs);
+
+err_unlock:
spin_unlock_irqrestore(&target->lock, flags);
err:
@@ -2199,7 +2198,7 @@ static void srp_remove_one(struct ib_device *device)
* started before we marked our target ports as
* removed, and any target port removal tasks.
*/
- flush_scheduled_work();
+ flush_workqueue(ib_wq);
list_for_each_entry_safe(target, tmp_target,
&host->target_list, list) {
diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig
index 07c2cd4..1903c0f 100644
--- a/drivers/input/Kconfig
+++ b/drivers/input/Kconfig
@@ -6,7 +6,7 @@ menu "Input device support"
depends on !S390
config INPUT
- tristate "Generic input layer (needed for keyboard, mouse, ...)" if EMBEDDED
+ tristate "Generic input layer (needed for keyboard, mouse, ...)" if EXPERT
default y
help
Say Y here if you have any input device (mouse, keyboard, tablet,
@@ -67,7 +67,7 @@ config INPUT_SPARSEKMAP
comment "Userland interfaces"
config INPUT_MOUSEDEV
- tristate "Mouse interface" if EMBEDDED
+ tristate "Mouse interface" if EXPERT
default y
help
Say Y here if you want your mouse to be accessible as char devices
@@ -150,7 +150,7 @@ config INPUT_EVBUG
module will be called evbug.
config INPUT_APMPOWER
- tristate "Input Power Event -> APM Bridge" if EMBEDDED
+ tristate "Input Power Event -> APM Bridge" if EXPERT
depends on INPUT && APM_EMULATION
help
Say Y here if you want suspend key events to trigger a user
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig
index 7b3c0b8..4175073 100644
--- a/drivers/input/keyboard/Kconfig
+++ b/drivers/input/keyboard/Kconfig
@@ -2,7 +2,7 @@
# Input core configuration
#
menuconfig INPUT_KEYBOARD
- bool "Keyboards" if EMBEDDED || !X86
+ bool "Keyboards" if EXPERT || !X86
default y
help
Say Y here, and a list of supported keyboards will be displayed.
@@ -57,7 +57,7 @@ config KEYBOARD_ATARI
module will be called atakbd.
config KEYBOARD_ATKBD
- tristate "AT keyboard" if EMBEDDED || !X86
+ tristate "AT keyboard" if EXPERT || !X86
default y
select SERIO
select SERIO_LIBPS2
diff --git a/drivers/input/mouse/Kconfig b/drivers/input/mouse/Kconfig
index bf5fd7f..9c1e6ee 100644
--- a/drivers/input/mouse/Kconfig
+++ b/drivers/input/mouse/Kconfig
@@ -39,7 +39,7 @@ config MOUSE_PS2
module will be called psmouse.
config MOUSE_PS2_ALPS
- bool "ALPS PS/2 mouse protocol extension" if EMBEDDED
+ bool "ALPS PS/2 mouse protocol extension" if EXPERT
default y
depends on MOUSE_PS2
help
@@ -49,7 +49,7 @@ config MOUSE_PS2_ALPS
If unsure, say Y.
config MOUSE_PS2_LOGIPS2PP
- bool "Logitech PS/2++ mouse protocol extension" if EMBEDDED
+ bool "Logitech PS/2++ mouse protocol extension" if EXPERT
default y
depends on MOUSE_PS2
help
@@ -59,7 +59,7 @@ config MOUSE_PS2_LOGIPS2PP
If unsure, say Y.
config MOUSE_PS2_SYNAPTICS
- bool "Synaptics PS/2 mouse protocol extension" if EMBEDDED
+ bool "Synaptics PS/2 mouse protocol extension" if EXPERT
default y
depends on MOUSE_PS2
help
@@ -69,7 +69,7 @@ config MOUSE_PS2_SYNAPTICS
If unsure, say Y.
config MOUSE_PS2_LIFEBOOK
- bool "Fujitsu Lifebook PS/2 mouse protocol extension" if EMBEDDED
+ bool "Fujitsu Lifebook PS/2 mouse protocol extension" if EXPERT
default y
depends on MOUSE_PS2 && X86 && DMI
help
@@ -79,7 +79,7 @@ config MOUSE_PS2_LIFEBOOK
If unsure, say Y.
config MOUSE_PS2_TRACKPOINT
- bool "IBM Trackpoint PS/2 mouse protocol extension" if EMBEDDED
+ bool "IBM Trackpoint PS/2 mouse protocol extension" if EXPERT
default y
depends on MOUSE_PS2
help
diff --git a/drivers/input/serio/Kconfig b/drivers/input/serio/Kconfig
index 307eef7..55f2c22 100644
--- a/drivers/input/serio/Kconfig
+++ b/drivers/input/serio/Kconfig
@@ -2,7 +2,7 @@
# Input core configuration
#
config SERIO
- tristate "Serial I/O support" if EMBEDDED || !X86
+ tristate "Serial I/O support" if EXPERT || !X86
default y
help
Say Yes here if you have any input device that uses serial I/O to
@@ -19,7 +19,7 @@ config SERIO
if SERIO
config SERIO_I8042
- tristate "i8042 PC Keyboard controller" if EMBEDDED || !X86
+ tristate "i8042 PC Keyboard controller" if EXPERT || !X86
default y
depends on !PARISC && (!ARM || ARCH_SHARK || FOOTBRIDGE_HOST) && \
(!SUPERH || SH_CAYMAN) && !M68K && !BLACKFIN
@@ -168,7 +168,7 @@ config SERIO_MACEPS2
module will be called maceps2.
config SERIO_LIBPS2
- tristate "PS/2 driver library" if EMBEDDED
+ tristate "PS/2 driver library" if EXPERT
depends on SERIO_I8042 || SERIO_I8042=n
help
Say Y here if you are using a driver for device connected
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index 0c9f4b1..61834ae 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -540,62 +540,62 @@ config TOUCHSCREEN_MC13783
config TOUCHSCREEN_USB_EGALAX
default y
- bool "eGalax, eTurboTouch CT-410/510/700 device support" if EMBEDDED
+ bool "eGalax, eTurboTouch CT-410/510/700 device support" if EXPERT
depends on TOUCHSCREEN_USB_COMPOSITE
config TOUCHSCREEN_USB_PANJIT
default y
- bool "PanJit device support" if EMBEDDED
+ bool "PanJit device support" if EXPERT
depends on TOUCHSCREEN_USB_COMPOSITE
config TOUCHSCREEN_USB_3M
default y
- bool "3M/Microtouch EX II series device support" if EMBEDDED
+ bool "3M/Microtouch EX II series device support" if EXPERT
depends on TOUCHSCREEN_USB_COMPOSITE
config TOUCHSCREEN_USB_ITM
default y
- bool "ITM device support" if EMBEDDED
+ bool "ITM device support" if EXPERT
depends on TOUCHSCREEN_USB_COMPOSITE
config TOUCHSCREEN_USB_ETURBO
default y
- bool "eTurboTouch (non-eGalax compatible) device support" if EMBEDDED
+ bool "eTurboTouch (non-eGalax compatible) device support" if EXPERT
depends on TOUCHSCREEN_USB_COMPOSITE
config TOUCHSCREEN_USB_GUNZE
default y
- bool "Gunze AHL61 device support" if EMBEDDED
+ bool "Gunze AHL61 device support" if EXPERT
depends on TOUCHSCREEN_USB_COMPOSITE
config TOUCHSCREEN_USB_DMC_TSC10
default y
- bool "DMC TSC-10/25 device support" if EMBEDDED
+ bool "DMC TSC-10/25 device support" if EXPERT
depends on TOUCHSCREEN_USB_COMPOSITE
config TOUCHSCREEN_USB_IRTOUCH
default y
- bool "IRTOUCHSYSTEMS/UNITOP device support" if EMBEDDED
+ bool "IRTOUCHSYSTEMS/UNITOP device support" if EXPERT
depends on TOUCHSCREEN_USB_COMPOSITE
config TOUCHSCREEN_USB_IDEALTEK
default y
- bool "IdealTEK URTC1000 device support" if EMBEDDED
+ bool "IdealTEK URTC1000 device support" if EXPERT
depends on TOUCHSCREEN_USB_COMPOSITE
config TOUCHSCREEN_USB_GENERAL_TOUCH
default y
- bool "GeneralTouch Touchscreen device support" if EMBEDDED
+ bool "GeneralTouch Touchscreen device support" if EXPERT
depends on TOUCHSCREEN_USB_COMPOSITE
config TOUCHSCREEN_USB_GOTOP
default y
- bool "GoTop Super_Q2/GogoPen/PenPower tablet device support" if EMBEDDED
+ bool "GoTop Super_Q2/GogoPen/PenPower tablet device support" if EXPERT
depends on TOUCHSCREEN_USB_COMPOSITE
config TOUCHSCREEN_USB_JASTEC
default y
- bool "JASTEC/DigiTech DTR-02U USB touch controller device support" if EMBEDDED
+ bool "JASTEC/DigiTech DTR-02U USB touch controller device support" if EXPERT
depends on TOUCHSCREEN_USB_COMPOSITE
config TOUCHSCREEN_USB_E2I
@@ -605,17 +605,17 @@ config TOUCHSCREEN_USB_E2I
config TOUCHSCREEN_USB_ZYTRONIC
default y
- bool "Zytronic controller" if EMBEDDED
+ bool "Zytronic controller" if EXPERT
depends on TOUCHSCREEN_USB_COMPOSITE
config TOUCHSCREEN_USB_ETT_TC45USB
default y
- bool "ET&T USB series TC4UM/TC5UH touchscreen controller support" if EMBEDDED
+ bool "ET&T USB series TC4UM/TC5UH touchscreen controller support" if EXPERT
depends on TOUCHSCREEN_USB_COMPOSITE
config TOUCHSCREEN_USB_NEXIO
default y
- bool "NEXIO/iNexio device support" if EMBEDDED
+ bool "NEXIO/iNexio device support" if EXPERT
depends on TOUCHSCREEN_USB_COMPOSITE
config TOUCHSCREEN_TOUCHIT213
diff --git a/drivers/leds/ledtrig-gpio.c b/drivers/leds/ledtrig-gpio.c
index 991d93b..ecc4bf3 100644
--- a/drivers/leds/ledtrig-gpio.c
+++ b/drivers/leds/ledtrig-gpio.c
@@ -99,7 +99,7 @@ static ssize_t gpio_trig_inverted_show(struct device *dev,
struct led_classdev *led = dev_get_drvdata(dev);
struct gpio_trig_data *gpio_data = led->trigger_data;
- return sprintf(buf, "%s\n", gpio_data->inverted ? "yes" : "no");
+ return sprintf(buf, "%u\n", gpio_data->inverted);
}
static ssize_t gpio_trig_inverted_store(struct device *dev,
@@ -107,16 +107,17 @@ static ssize_t gpio_trig_inverted_store(struct device *dev,
{
struct led_classdev *led = dev_get_drvdata(dev);
struct gpio_trig_data *gpio_data = led->trigger_data;
- unsigned inverted;
+ unsigned long inverted;
int ret;
- ret = sscanf(buf, "%u", &inverted);
- if (ret < 1) {
- dev_err(dev, "invalid value\n");
+ ret = strict_strtoul(buf, 10, &inverted);
+ if (ret < 0)
+ return ret;
+
+ if (inverted > 1)
return -EINVAL;
- }
- gpio_data->inverted = !!inverted;
+ gpio_data->inverted = inverted;
/* After inverting, we need to update the LED. */
schedule_work(&gpio_data->work);
diff --git a/drivers/lguest/page_tables.c b/drivers/lguest/page_tables.c
index 04b2212..d21578e 100644
--- a/drivers/lguest/page_tables.c
+++ b/drivers/lguest/page_tables.c
@@ -1137,7 +1137,7 @@ void free_guest_pagetable(struct lguest *lg)
*/
void map_switcher_in_guest(struct lg_cpu *cpu, struct lguest_pages *pages)
{
- pte_t *switcher_pte_page = __get_cpu_var(switcher_pte_pages);
+ pte_t *switcher_pte_page = __this_cpu_read(switcher_pte_pages);
pte_t regs_pte;
#ifdef CONFIG_X86_PAE
diff --git a/drivers/lguest/x86/core.c b/drivers/lguest/x86/core.c
index b4eb675..9f1659c 100644
--- a/drivers/lguest/x86/core.c
+++ b/drivers/lguest/x86/core.c
@@ -90,8 +90,8 @@ static void copy_in_guest_info(struct lg_cpu *cpu, struct lguest_pages *pages)
* meanwhile). If that's not the case, we pretend everything in the
* Guest has changed.
*/
- if (__get_cpu_var(lg_last_cpu) != cpu || cpu->last_pages != pages) {
- __get_cpu_var(lg_last_cpu) = cpu;
+ if (__this_cpu_read(lg_last_cpu) != cpu || cpu->last_pages != pages) {
+ __this_cpu_write(lg_last_cpu, cpu);
cpu->last_pages = pages;
cpu->changed = CHANGED_ALL;
}
diff --git a/drivers/macintosh/therm_pm72.c b/drivers/macintosh/therm_pm72.c
index 2e041fd..f3a29f2 100644
--- a/drivers/macintosh/therm_pm72.c
+++ b/drivers/macintosh/therm_pm72.c
@@ -443,7 +443,7 @@ static int fan_read_reg(int reg, unsigned char *buf, int nb)
tries = 0;
for (;;) {
nr = i2c_master_recv(fcu, buf, nb);
- if (nr > 0 || (nr < 0 && nr != ENODEV) || tries >= 100)
+ if (nr > 0 || (nr < 0 && nr != -ENODEV) || tries >= 100)
break;
msleep(10);
++tries;
@@ -464,7 +464,7 @@ static int fan_write_reg(int reg, const unsigned char *ptr, int nb)
tries = 0;
for (;;) {
nw = i2c_master_send(fcu, buf, nb);
- if (nw > 0 || (nw < 0 && nw != EIO) || tries >= 100)
+ if (nw > 0 || (nw < 0 && nw != -EIO) || tries >= 100)
break;
msleep(10);
++tries;
diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c
index dffa0ac..38e4eb1 100644
--- a/drivers/md/dm-table.c
+++ b/drivers/md/dm-table.c
@@ -350,6 +350,7 @@ static void close_dev(struct dm_dev_internal *d, struct mapped_device *md)
if (!d->dm_dev.bdev)
return;
+ bd_unlink_disk_holder(d->dm_dev.bdev, dm_disk(md));
blkdev_put(d->dm_dev.bdev, d->dm_dev.mode | FMODE_EXCL);
d->dm_dev.bdev = NULL;
}
diff --git a/drivers/md/md.c b/drivers/md/md.c
index cf8594c..b76cfc8 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -1912,6 +1912,7 @@ static void unbind_rdev_from_array(mdk_rdev_t * rdev)
MD_BUG();
return;
}
+ bd_unlink_disk_holder(rdev->bdev, rdev->mddev->gendisk);
list_del_rcu(&rdev->same_set);
printk(KERN_INFO "md: unbind<%s>\n", bdevname(rdev->bdev,b));
rdev->mddev = NULL;
diff --git a/drivers/media/common/saa7146_core.c b/drivers/media/common/saa7146_core.c
index 982f000..9f47e38 100644
--- a/drivers/media/common/saa7146_core.c
+++ b/drivers/media/common/saa7146_core.c
@@ -452,7 +452,7 @@ static int saa7146_init_one(struct pci_dev *pci, const struct pci_device_id *ent
INFO(("found saa7146 @ mem %p (revision %d, irq %d) (0x%04x,0x%04x).\n", dev->mem, dev->revision, pci->irq, pci->subsystem_vendor, pci->subsystem_device));
dev->ext = ext;
- mutex_init(&dev->lock);
+ mutex_init(&dev->v4l2_lock);
spin_lock_init(&dev->int_slock);
spin_lock_init(&dev->slock);
diff --git a/drivers/media/common/saa7146_fops.c b/drivers/media/common/saa7146_fops.c
index e3fedc6..1bd3dd7 100644
--- a/drivers/media/common/saa7146_fops.c
+++ b/drivers/media/common/saa7146_fops.c
@@ -15,18 +15,15 @@ int saa7146_res_get(struct saa7146_fh *fh, unsigned int bit)
}
/* is it free? */
- mutex_lock(&dev->lock);
if (vv->resources & bit) {
DEB_D(("locked! vv->resources:0x%02x, we want:0x%02x\n",vv->resources,bit));
/* no, someone else uses it */
- mutex_unlock(&dev->lock);
return 0;
}
/* it's free, grab it */
fh->resources |= bit;
vv->resources |= bit;
DEB_D(("res: get 0x%02x, cur:0x%02x\n",bit,vv->resources));
- mutex_unlock(&dev->lock);
return 1;
}
@@ -37,11 +34,9 @@ void saa7146_res_free(struct saa7146_fh *fh, unsigned int bits)
BUG_ON((fh->resources & bits) != bits);
- mutex_lock(&dev->lock);
fh->resources &= ~bits;
vv->resources &= ~bits;
DEB_D(("res: put 0x%02x, cur:0x%02x\n",bits,vv->resources));
- mutex_unlock(&dev->lock);
}
@@ -396,7 +391,7 @@ static const struct v4l2_file_operations video_fops =
.write = fops_write,
.poll = fops_poll,
.mmap = fops_mmap,
- .ioctl = video_ioctl2,
+ .unlocked_ioctl = video_ioctl2,
};
static void vv_callback(struct saa7146_dev *dev, unsigned long status)
@@ -505,6 +500,7 @@ int saa7146_register_device(struct video_device **vid, struct saa7146_dev* dev,
vfd->fops = &video_fops;
vfd->ioctl_ops = &dev->ext_vv_data->ops;
vfd->release = video_device_release;
+ vfd->lock = &dev->v4l2_lock;
vfd->tvnorms = 0;
for (i = 0; i < dev->ext_vv_data->num_stds; i++)
vfd->tvnorms |= dev->ext_vv_data->stds[i].id;
diff --git a/drivers/media/common/saa7146_vbi.c b/drivers/media/common/saa7146_vbi.c
index 2d4533a..afe8580 100644
--- a/drivers/media/common/saa7146_vbi.c
+++ b/drivers/media/common/saa7146_vbi.c
@@ -412,7 +412,7 @@ static int vbi_open(struct saa7146_dev *dev, struct file *file)
V4L2_BUF_TYPE_VBI_CAPTURE,
V4L2_FIELD_SEQ_TB, // FIXME: does this really work?
sizeof(struct saa7146_buf),
- file, NULL);
+ file, &dev->v4l2_lock);
init_timer(&fh->vbi_read_timeout);
fh->vbi_read_timeout.function = vbi_read_timeout;
diff --git a/drivers/media/common/saa7146_video.c b/drivers/media/common/saa7146_video.c
index 0ac5c61..9aafa4e 100644
--- a/drivers/media/common/saa7146_video.c
+++ b/drivers/media/common/saa7146_video.c
@@ -553,8 +553,6 @@ static int vidioc_s_fbuf(struct file *file, void *fh, struct v4l2_framebuffer *f
}
}
- mutex_lock(&dev->lock);
-
/* ok, accept it */
vv->ov_fb = *fb;
vv->ov_fmt = fmt;
@@ -563,8 +561,6 @@ static int vidioc_s_fbuf(struct file *file, void *fh, struct v4l2_framebuffer *f
vv->ov_fb.fmt.bytesperline = vv->ov_fb.fmt.width * fmt->depth / 8;
DEB_D(("setting bytesperline to %d\n", vv->ov_fb.fmt.bytesperline));
}
-
- mutex_unlock(&dev->lock);
return 0;
}
@@ -649,8 +645,6 @@ static int vidioc_s_ctrl(struct file *file, void *fh, struct v4l2_control *c)
return -EINVAL;
}
- mutex_lock(&dev->lock);
-
switch (ctrl->type) {
case V4L2_CTRL_TYPE_BOOLEAN:
case V4L2_CTRL_TYPE_MENU:
@@ -693,7 +687,6 @@ static int vidioc_s_ctrl(struct file *file, void *fh, struct v4l2_control *c)
/* fixme: we can support changing VFLIP and HFLIP here... */
if (IS_CAPTURE_ACTIVE(fh) != 0) {
DEB_D(("V4L2_CID_HFLIP while active capture.\n"));
- mutex_unlock(&dev->lock);
return -EBUSY;
}
vv->hflip = c->value;
@@ -701,16 +694,13 @@ static int vidioc_s_ctrl(struct file *file, void *fh, struct v4l2_control *c)
case V4L2_CID_VFLIP:
if (IS_CAPTURE_ACTIVE(fh) != 0) {
DEB_D(("V4L2_CID_VFLIP while active capture.\n"));
- mutex_unlock(&dev->lock);
return -EBUSY;
}
vv->vflip = c->value;
break;
default:
- mutex_unlock(&dev->lock);
return -EINVAL;
}
- mutex_unlock(&dev->lock);
if (IS_OVERLAY_ACTIVE(fh) != 0) {
saa7146_stop_preview(fh);
@@ -902,22 +892,18 @@ static int vidioc_s_fmt_vid_overlay(struct file *file, void *__fh, struct v4l2_f
err = vidioc_try_fmt_vid_overlay(file, fh, f);
if (0 != err)
return err;
- mutex_lock(&dev->lock);
fh->ov.win = f->fmt.win;
fh->ov.nclips = f->fmt.win.clipcount;
if (fh->ov.nclips > 16)
fh->ov.nclips = 16;
if (copy_from_user(fh->ov.clips, f->fmt.win.clips,
sizeof(struct v4l2_clip) * fh->ov.nclips)) {
- mutex_unlock(&dev->lock);
return -EFAULT;
}
/* fh->ov.fh is used to indicate that we have valid overlay informations, too */
fh->ov.fh = fh;
- mutex_unlock(&dev->lock);
-
/* check if our current overlay is active */
if (IS_OVERLAY_ACTIVE(fh) != 0) {
saa7146_stop_preview(fh);
@@ -976,8 +962,6 @@ static int vidioc_s_std(struct file *file, void *fh, v4l2_std_id *id)
}
}
- mutex_lock(&dev->lock);
-
for (i = 0; i < dev->ext_vv_data->num_stds; i++)
if (*id & dev->ext_vv_data->stds[i].id)
break;
@@ -988,8 +972,6 @@ static int vidioc_s_std(struct file *file, void *fh, v4l2_std_id *id)
found = 1;
}
- mutex_unlock(&dev->lock);
-
if (vv->ov_suspend != NULL) {
saa7146_start_preview(vv->ov_suspend);
vv->ov_suspend = NULL;
@@ -1354,7 +1336,7 @@ static int video_open(struct saa7146_dev *dev, struct file *file)
V4L2_BUF_TYPE_VIDEO_CAPTURE,
V4L2_FIELD_INTERLACED,
sizeof(struct saa7146_buf),
- file, NULL);
+ file, &dev->v4l2_lock);
return 0;
}
diff --git a/drivers/media/common/tuners/Kconfig b/drivers/media/common/tuners/Kconfig
index 78b0895..6fc79f1 100644
--- a/drivers/media/common/tuners/Kconfig
+++ b/drivers/media/common/tuners/Kconfig
@@ -34,7 +34,7 @@ config MEDIA_TUNER
config MEDIA_TUNER_CUSTOMISE
bool "Customize analog and hybrid tuner modules to build"
depends on MEDIA_TUNER
- default y if EMBEDDED
+ default y if EXPERT
help
This allows the user to deselect tuner drivers unnecessary
for their hardware from the build. Use this option with care
diff --git a/drivers/media/common/tuners/tda8290.c b/drivers/media/common/tuners/tda8290.c
index c9062ce..bc6a677 100644
--- a/drivers/media/common/tuners/tda8290.c
+++ b/drivers/media/common/tuners/tda8290.c
@@ -95,8 +95,7 @@ static int tda8295_i2c_bridge(struct dvb_frontend *fe, int close)
msleep(20);
} else {
msg = disable;
- tuner_i2c_xfer_send(&priv->i2c_props, msg, 1);
- tuner_i2c_xfer_recv(&priv->i2c_props, &msg[1], 1);
+ tuner_i2c_xfer_send_recv(&priv->i2c_props, msg, 1, &msg[1], 1);
buf[2] = msg[1];
buf[2] &= ~0x04;
@@ -233,19 +232,22 @@ static void tda8290_set_params(struct dvb_frontend *fe,
tuner_i2c_xfer_send(&priv->i2c_props, pll_bw_nom, 2);
}
+
tda8290_i2c_bridge(fe, 1);
if (fe->ops.tuner_ops.set_analog_params)
fe->ops.tuner_ops.set_analog_params(fe, params);
for (i = 0; i < 3; i++) {
- tuner_i2c_xfer_send(&priv->i2c_props, &addr_pll_stat, 1);
- tuner_i2c_xfer_recv(&priv->i2c_props, &pll_stat, 1);
+ tuner_i2c_xfer_send_recv(&priv->i2c_props,
+ &addr_pll_stat, 1, &pll_stat, 1);
if (pll_stat & 0x80) {
- tuner_i2c_xfer_send(&priv->i2c_props, &addr_adc_sat, 1);
- tuner_i2c_xfer_recv(&priv->i2c_props, &adc_sat, 1);
- tuner_i2c_xfer_send(&priv->i2c_props, &addr_agc_stat, 1);
- tuner_i2c_xfer_recv(&priv->i2c_props, &agc_stat, 1);
+ tuner_i2c_xfer_send_recv(&priv->i2c_props,
+ &addr_adc_sat, 1,
+ &adc_sat, 1);
+ tuner_i2c_xfer_send_recv(&priv->i2c_props,
+ &addr_agc_stat, 1,
+ &agc_stat, 1);
tuner_dbg("tda8290 is locked, AGC: %d\n", agc_stat);
break;
} else {
@@ -259,20 +261,22 @@ static void tda8290_set_params(struct dvb_frontend *fe,
agc_stat, adc_sat, pll_stat & 0x80);
tuner_i2c_xfer_send(&priv->i2c_props, gainset_2, 2);
msleep(100);
- tuner_i2c_xfer_send(&priv->i2c_props, &addr_agc_stat, 1);
- tuner_i2c_xfer_recv(&priv->i2c_props, &agc_stat, 1);
- tuner_i2c_xfer_send(&priv->i2c_props, &addr_pll_stat, 1);
- tuner_i2c_xfer_recv(&priv->i2c_props, &pll_stat, 1);
+ tuner_i2c_xfer_send_recv(&priv->i2c_props,
+ &addr_agc_stat, 1, &agc_stat, 1);
+ tuner_i2c_xfer_send_recv(&priv->i2c_props,
+ &addr_pll_stat, 1, &pll_stat, 1);
if ((agc_stat > 115) || !(pll_stat & 0x80)) {
tuner_dbg("adjust gain, step 2. Agc: %d, lock: %d\n",
agc_stat, pll_stat & 0x80);
if (priv->cfg.agcf)
priv->cfg.agcf(fe);
msleep(100);
- tuner_i2c_xfer_send(&priv->i2c_props, &addr_agc_stat, 1);
- tuner_i2c_xfer_recv(&priv->i2c_props, &agc_stat, 1);
- tuner_i2c_xfer_send(&priv->i2c_props, &addr_pll_stat, 1);
- tuner_i2c_xfer_recv(&priv->i2c_props, &pll_stat, 1);
+ tuner_i2c_xfer_send_recv(&priv->i2c_props,
+ &addr_agc_stat, 1,
+ &agc_stat, 1);
+ tuner_i2c_xfer_send_recv(&priv->i2c_props,
+ &addr_pll_stat, 1,
+ &pll_stat, 1);
if((agc_stat > 115) || !(pll_stat & 0x80)) {
tuner_dbg("adjust gain, step 3. Agc: %d\n", agc_stat);
tuner_i2c_xfer_send(&priv->i2c_props, adc_head_12, 2);
@@ -284,10 +288,12 @@ static void tda8290_set_params(struct dvb_frontend *fe,
/* l/ l' deadlock? */
if(priv->tda8290_easy_mode & 0x60) {
- tuner_i2c_xfer_send(&priv->i2c_props, &addr_adc_sat, 1);
- tuner_i2c_xfer_recv(&priv->i2c_props, &adc_sat, 1);
- tuner_i2c_xfer_send(&priv->i2c_props, &addr_pll_stat, 1);
- tuner_i2c_xfer_recv(&priv->i2c_props, &pll_stat, 1);
+ tuner_i2c_xfer_send_recv(&priv->i2c_props,
+ &addr_adc_sat, 1,
+ &adc_sat, 1);
+ tuner_i2c_xfer_send_recv(&priv->i2c_props,
+ &addr_pll_stat, 1,
+ &pll_stat, 1);
if ((adc_sat > 20) || !(pll_stat & 0x80)) {
tuner_dbg("trying to resolve SECAM L deadlock\n");
tuner_i2c_xfer_send(&priv->i2c_props, agc_rst_on, 2);
@@ -307,8 +313,7 @@ static void tda8295_power(struct dvb_frontend *fe, int enable)
struct tda8290_priv *priv = fe->analog_demod_priv;
unsigned char buf[] = { 0x30, 0x00 }; /* clb_stdbt */
- tuner_i2c_xfer_send(&priv->i2c_props, &buf[0], 1);
- tuner_i2c_xfer_recv(&priv->i2c_props, &buf[1], 1);
+ tuner_i2c_xfer_send_recv(&priv->i2c_props, &buf[0], 1, &buf[1], 1);
if (enable)
buf[1] = 0x01;
@@ -323,8 +328,7 @@ static void tda8295_set_easy_mode(struct dvb_frontend *fe, int enable)
struct tda8290_priv *priv = fe->analog_demod_priv;
unsigned char buf[] = { 0x01, 0x00 };
- tuner_i2c_xfer_send(&priv->i2c_props, &buf[0], 1);
- tuner_i2c_xfer_recv(&priv->i2c_props, &buf[1], 1);
+ tuner_i2c_xfer_send_recv(&priv->i2c_props, &buf[0], 1, &buf[1], 1);
if (enable)
buf[1] = 0x01; /* rising edge sets regs 0x02 - 0x23 */
@@ -353,8 +357,7 @@ static void tda8295_agc1_out(struct dvb_frontend *fe, int enable)
struct tda8290_priv *priv = fe->analog_demod_priv;
unsigned char buf[] = { 0x02, 0x00 }; /* DIV_FUNC */
- tuner_i2c_xfer_send(&priv->i2c_props, &buf[0], 1);
- tuner_i2c_xfer_recv(&priv->i2c_props, &buf[1], 1);
+ tuner_i2c_xfer_send_recv(&priv->i2c_props, &buf[0], 1, &buf[1], 1);
if (enable)
buf[1] &= ~0x40;
@@ -370,10 +373,10 @@ static void tda8295_agc2_out(struct dvb_frontend *fe, int enable)
unsigned char set_gpio_cf[] = { 0x44, 0x00 };
unsigned char set_gpio_val[] = { 0x46, 0x00 };
- tuner_i2c_xfer_send(&priv->i2c_props, &set_gpio_cf[0], 1);
- tuner_i2c_xfer_recv(&priv->i2c_props, &set_gpio_cf[1], 1);
- tuner_i2c_xfer_send(&priv->i2c_props, &set_gpio_val[0], 1);
- tuner_i2c_xfer_recv(&priv->i2c_props, &set_gpio_val[1], 1);
+ tuner_i2c_xfer_send_recv(&priv->i2c_props,
+ &set_gpio_cf[0], 1, &set_gpio_cf[1], 1);
+ tuner_i2c_xfer_send_recv(&priv->i2c_props,
+ &set_gpio_val[0], 1, &set_gpio_val[1], 1);
set_gpio_cf[1] &= 0xf0; /* clear GPIO_0 bits 3-0 */
@@ -392,8 +395,7 @@ static int tda8295_has_signal(struct dvb_frontend *fe)
unsigned char hvpll_stat = 0x26;
unsigned char ret;
- tuner_i2c_xfer_send(&priv->i2c_props, &hvpll_stat, 1);
- tuner_i2c_xfer_recv(&priv->i2c_props, &ret, 1);
+ tuner_i2c_xfer_send_recv(&priv->i2c_props, &hvpll_stat, 1, &ret, 1);
return (ret & 0x01) ? 65535 : 0;
}
@@ -413,8 +415,8 @@ static void tda8295_set_params(struct dvb_frontend *fe,
tda8295_power(fe, 1);
tda8295_agc1_out(fe, 1);
- tuner_i2c_xfer_send(&priv->i2c_props, &blanking_mode[0], 1);
- tuner_i2c_xfer_recv(&priv->i2c_props, &blanking_mode[1], 1);
+ tuner_i2c_xfer_send_recv(&priv->i2c_props,
+ &blanking_mode[0], 1, &blanking_mode[1], 1);
tda8295_set_video_std(fe);
@@ -447,8 +449,8 @@ static int tda8290_has_signal(struct dvb_frontend *fe)
unsigned char i2c_get_afc[1] = { 0x1B };
unsigned char afc = 0;
- tuner_i2c_xfer_send(&priv->i2c_props, i2c_get_afc, ARRAY_SIZE(i2c_get_afc));
- tuner_i2c_xfer_recv(&priv->i2c_props, &afc, 1);
+ tuner_i2c_xfer_send_recv(&priv->i2c_props,
+ i2c_get_afc, ARRAY_SIZE(i2c_get_afc), &afc, 1);
return (afc & 0x80)? 65535:0;
}
@@ -654,20 +656,26 @@ static int tda829x_find_tuner(struct dvb_frontend *fe)
static int tda8290_probe(struct tuner_i2c_props *i2c_props)
{
#define TDA8290_ID 0x89
- unsigned char tda8290_id[] = { 0x1f, 0x00 };
+ u8 reg = 0x1f, id;
+ struct i2c_msg msg_read[] = {
+ { .addr = 0x4b, .flags = 0, .len = 1, .buf = &reg },
+ { .addr = 0x4b, .flags = I2C_M_RD, .len = 1, .buf = &id },
+ };
/* detect tda8290 */
- tuner_i2c_xfer_send(i2c_props, &tda8290_id[0], 1);
- tuner_i2c_xfer_recv(i2c_props, &tda8290_id[1], 1);
+ if (i2c_transfer(i2c_props->adap, msg_read, 2) != 2) {
+ printk(KERN_WARNING "%s: tda8290 couldn't read register 0x%02x\n",
+ __func__, reg);
+ return -ENODEV;
+ }
- if (tda8290_id[1] == TDA8290_ID) {
+ if (id == TDA8290_ID) {
if (debug)
printk(KERN_DEBUG "%s: tda8290 detected @ %d-%04x\n",
__func__, i2c_adapter_id(i2c_props->adap),
i2c_props->addr);
return 0;
}
-
return -ENODEV;
}
@@ -675,16 +683,23 @@ static int tda8295_probe(struct tuner_i2c_props *i2c_props)
{
#define TDA8295_ID 0x8a
#define TDA8295C2_ID 0x8b
- unsigned char tda8295_id[] = { 0x2f, 0x00 };
+ u8 reg = 0x2f, id;
+ struct i2c_msg msg_read[] = {
+ { .addr = 0x4b, .flags = 0, .len = 1, .buf = &reg },
+ { .addr = 0x4b, .flags = I2C_M_RD, .len = 1, .buf = &id },
+ };
- /* detect tda8295 */
- tuner_i2c_xfer_send(i2c_props, &tda8295_id[0], 1);
- tuner_i2c_xfer_recv(i2c_props, &tda8295_id[1], 1);
+ /* detect tda8290 */
+ if (i2c_transfer(i2c_props->adap, msg_read, 2) != 2) {
+ printk(KERN_WARNING "%s: tda8290 couldn't read register 0x%02x\n",
+ __func__, reg);
+ return -ENODEV;
+ }
- if ((tda8295_id[1] & 0xfe) == TDA8295_ID) {
+ if ((id & 0xfe) == TDA8295_ID) {
if (debug)
printk(KERN_DEBUG "%s: %s detected @ %d-%04x\n",
- __func__, (tda8295_id[1] == TDA8295_ID) ?
+ __func__, (id == TDA8295_ID) ?
"tda8295c1" : "tda8295c2",
i2c_adapter_id(i2c_props->adap),
i2c_props->addr);
@@ -740,9 +755,11 @@ struct dvb_frontend *tda829x_attach(struct dvb_frontend *fe,
sizeof(struct analog_demod_ops));
}
- if ((!(cfg) || (TDA829X_PROBE_TUNER == cfg->probe_tuner)) &&
- (tda829x_find_tuner(fe) < 0))
- goto fail;
+ if (!(cfg) || (TDA829X_PROBE_TUNER == cfg->probe_tuner)) {
+ tda8295_power(fe, 1);
+ if (tda829x_find_tuner(fe) < 0)
+ goto fail;
+ }
switch (priv->ver) {
case TDA8290:
@@ -786,6 +803,8 @@ struct dvb_frontend *tda829x_attach(struct dvb_frontend *fe,
return fe;
fail:
+ memset(&fe->ops.analog_ops, 0, sizeof(struct analog_demod_ops));
+
tda829x_release(fe);
return NULL;
}
@@ -809,8 +828,8 @@ int tda829x_probe(struct i2c_adapter *i2c_adap, u8 i2c_addr)
int i;
/* rule out tda9887, which would return the same byte repeatedly */
- tuner_i2c_xfer_send(&i2c_props, soft_reset, 1);
- tuner_i2c_xfer_recv(&i2c_props, buf, PROBE_BUFFER_SIZE);
+ tuner_i2c_xfer_send_recv(&i2c_props,
+ soft_reset, 1, buf, PROBE_BUFFER_SIZE);
for (i = 1; i < PROBE_BUFFER_SIZE; i++) {
if (buf[i] != buf[0])
break;
@@ -827,13 +846,12 @@ int tda829x_probe(struct i2c_adapter *i2c_adap, u8 i2c_addr)
/* fall back to old probing method */
tuner_i2c_xfer_send(&i2c_props, easy_mode_b, 2);
tuner_i2c_xfer_send(&i2c_props, soft_reset, 2);
- tuner_i2c_xfer_send(&i2c_props, &addr_dto_lsb, 1);
- tuner_i2c_xfer_recv(&i2c_props, &data, 1);
+ tuner_i2c_xfer_send_recv(&i2c_props, &addr_dto_lsb, 1, &data, 1);
if (data == 0) {
tuner_i2c_xfer_send(&i2c_props, easy_mode_g, 2);
tuner_i2c_xfer_send(&i2c_props, soft_reset, 2);
- tuner_i2c_xfer_send(&i2c_props, &addr_dto_lsb, 1);
- tuner_i2c_xfer_recv(&i2c_props, &data, 1);
+ tuner_i2c_xfer_send_recv(&i2c_props,
+ &addr_dto_lsb, 1, &data, 1);
if (data == 0x7b) {
return 0;
}
diff --git a/drivers/media/dvb/dvb-usb/dib0700_core.c b/drivers/media/dvb/dvb-usb/dib0700_core.c
index 8ca48f7..98ffb40 100644
--- a/drivers/media/dvb/dvb-usb/dib0700_core.c
+++ b/drivers/media/dvb/dvb-usb/dib0700_core.c
@@ -514,8 +514,8 @@ struct dib0700_rc_response {
union {
u16 system16;
struct {
- u8 system;
u8 not_system;
+ u8 system;
};
};
u8 data;
@@ -575,7 +575,7 @@ static void dib0700_rc_urb_completion(struct urb *purb)
if ((poll_reply->system ^ poll_reply->not_system) != 0xff) {
deb_data("NEC extended protocol\n");
/* NEC extended code - 24 bits */
- keycode = poll_reply->system16 << 8 | poll_reply->data;
+ keycode = be16_to_cpu(poll_reply->system16) << 8 | poll_reply->data;
} else {
deb_data("NEC normal protocol\n");
/* normal NEC code - 16 bits */
@@ -587,7 +587,7 @@ static void dib0700_rc_urb_completion(struct urb *purb)
deb_data("RC5 protocol\n");
/* RC5 Protocol */
toggle = poll_reply->report_id;
- keycode = poll_reply->system16 << 8 | poll_reply->data;
+ keycode = poll_reply->system << 8 | poll_reply->data;
break;
}
diff --git a/drivers/media/dvb/firewire/firedtv-rc.c b/drivers/media/dvb/firewire/firedtv-rc.c
index fcf3828..f82d4a9 100644
--- a/drivers/media/dvb/firewire/firedtv-rc.c
+++ b/drivers/media/dvb/firewire/firedtv-rc.c
@@ -172,7 +172,8 @@ void fdtv_unregister_rc(struct firedtv *fdtv)
void fdtv_handle_rc(struct firedtv *fdtv, unsigned int code)
{
- u16 *keycode = fdtv->remote_ctrl_dev->keycode;
+ struct input_dev *idev = fdtv->remote_ctrl_dev;
+ u16 *keycode = idev->keycode;
if (code >= 0x0300 && code <= 0x031f)
code = keycode[code - 0x0300];
@@ -188,6 +189,8 @@ void fdtv_handle_rc(struct firedtv *fdtv, unsigned int code)
return;
}
- input_report_key(fdtv->remote_ctrl_dev, code, 1);
- input_report_key(fdtv->remote_ctrl_dev, code, 0);
+ input_report_key(idev, code, 1);
+ input_sync(idev);
+ input_report_key(idev, code, 0);
+ input_sync(idev);
}
diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig
index ef3e43a..b8519ba 100644
--- a/drivers/media/dvb/frontends/Kconfig
+++ b/drivers/media/dvb/frontends/Kconfig
@@ -1,7 +1,7 @@
config DVB_FE_CUSTOMISE
bool "Customise the frontend modules to build"
depends on DVB_CORE
- default y if EMBEDDED
+ default y if EXPERT
help
This allows the user to select/deselect frontend drivers for their
hardware from the build.
diff --git a/drivers/media/dvb/frontends/af9013.c b/drivers/media/dvb/frontends/af9013.c
index ce22205..ba25fa0 100644
--- a/drivers/media/dvb/frontends/af9013.c
+++ b/drivers/media/dvb/frontends/af9013.c
@@ -334,11 +334,11 @@ static int af9013_set_freq_ctrl(struct af9013_state *state, fe_bandwidth_t bw)
if_sample_freq = 3300000; /* 3.3 MHz */
break;
case BANDWIDTH_7_MHZ:
- if_sample_freq = 3800000; /* 3.8 MHz */
+ if_sample_freq = 3500000; /* 3.5 MHz */
break;
case BANDWIDTH_8_MHZ:
default:
- if_sample_freq = 4300000; /* 4.3 MHz */
+ if_sample_freq = 4000000; /* 4.0 MHz */
break;
}
} else if (state->config.tuner == AF9013_TUNER_TDA18218) {
diff --git a/drivers/media/dvb/frontends/ix2505v.c b/drivers/media/dvb/frontends/ix2505v.c
index 6360c68..6c2e929 100644
--- a/drivers/media/dvb/frontends/ix2505v.c
+++ b/drivers/media/dvb/frontends/ix2505v.c
@@ -311,7 +311,7 @@ struct dvb_frontend *ix2505v_attach(struct dvb_frontend *fe,
return fe;
error:
- ix2505v_release(fe);
+ kfree(state);
return NULL;
}
EXPORT_SYMBOL(ix2505v_attach);
diff --git a/drivers/media/dvb/frontends/mb86a20s.c b/drivers/media/dvb/frontends/mb86a20s.c
index d3ad3e7..cc4acd2 100644
--- a/drivers/media/dvb/frontends/mb86a20s.c
+++ b/drivers/media/dvb/frontends/mb86a20s.c
@@ -43,6 +43,8 @@ struct mb86a20s_state {
const struct mb86a20s_config *config;
struct dvb_frontend frontend;
+
+ bool need_init;
};
struct regdata {
@@ -318,7 +320,7 @@ static int mb86a20s_i2c_writereg(struct mb86a20s_state *state,
rc = i2c_transfer(state->i2c, &msg, 1);
if (rc != 1) {
- printk("%s: writereg rcor(rc == %i, reg == 0x%02x,"
+ printk("%s: writereg error (rc == %i, reg == 0x%02x,"
" data == 0x%02x)\n", __func__, rc, reg, data);
return rc;
}
@@ -353,7 +355,7 @@ static int mb86a20s_i2c_readreg(struct mb86a20s_state *state,
rc = i2c_transfer(state->i2c, msg, 2);
if (rc != 2) {
- rc("%s: reg=0x%x (rcor=%d)\n", __func__, reg, rc);
+ rc("%s: reg=0x%x (error=%d)\n", __func__, reg, rc);
return rc;
}
@@ -382,23 +384,31 @@ static int mb86a20s_initfe(struct dvb_frontend *fe)
/* Initialize the frontend */
rc = mb86a20s_writeregdata(state, mb86a20s_init);
if (rc < 0)
- return rc;
+ goto err;
if (!state->config->is_serial) {
regD5 &= ~1;
rc = mb86a20s_writereg(state, 0x50, 0xd5);
if (rc < 0)
- return rc;
+ goto err;
rc = mb86a20s_writereg(state, 0x51, regD5);
if (rc < 0)
- return rc;
+ goto err;
}
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 1);
- return 0;
+err:
+ if (rc < 0) {
+ state->need_init = true;
+ printk(KERN_INFO "mb86a20s: Init failed. Will try again later\n");
+ } else {
+ state->need_init = false;
+ dprintk("Initialization succeded.\n");
+ }
+ return rc;
}
static int mb86a20s_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
@@ -485,8 +495,22 @@ static int mb86a20s_set_frontend(struct dvb_frontend *fe,
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 1);
+ dprintk("Calling tuner set parameters\n");
fe->ops.tuner_ops.set_params(fe, p);
+ /*
+ * Make it more reliable: if, for some reason, the initial
+ * device initialization doesn't happen, initialize it when
+ * a SBTVD parameters are adjusted.
+ *
+ * Unfortunately, due to a hard to track bug at tda829x/tda18271,
+ * the agc callback logic is not called during DVB attach time,
+ * causing mb86a20s to not be initialized with Kworld SBTVD.
+ * So, this hack is needed, in order to make Kworld SBTVD to work.
+ */
+ if (state->need_init)
+ mb86a20s_initfe(fe);
+
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 0);
rc = mb86a20s_writeregdata(state, mb86a20s_reset_reception);
diff --git a/drivers/media/dvb/ttpci/av7110_ca.c b/drivers/media/dvb/ttpci/av7110_ca.c
index 122c728..9fc1dd0 100644
--- a/drivers/media/dvb/ttpci/av7110_ca.c
+++ b/drivers/media/dvb/ttpci/av7110_ca.c
@@ -277,7 +277,7 @@ static int dvb_ca_ioctl(struct file *file, unsigned int cmd, void *parg)
{
ca_slot_info_t *info=(ca_slot_info_t *)parg;
- if (info->num > 1)
+ if (info->num < 0 || info->num > 1)
return -EINVAL;
av7110->ci_slot[info->num].num = info->num;
av7110->ci_slot[info->num].type = FW_CI_LL_SUPPORT(av7110->arm_app) ?
diff --git a/drivers/media/radio/Kconfig b/drivers/media/radio/Kconfig
index 3c5a473..ecdffa6 100644
--- a/drivers/media/radio/Kconfig
+++ b/drivers/media/radio/Kconfig
@@ -151,20 +151,6 @@ config RADIO_GEMTEK_PROBE
following ports will be probed: 0x20c, 0x30c, 0x24c, 0x34c, 0x248 and
0x28c.
-config RADIO_GEMTEK_PCI
- tristate "GemTek PCI Radio Card support"
- depends on VIDEO_V4L2 && PCI
- ---help---
- Choose Y here if you have this PCI FM radio card.
-
- In order to control your radio card, you will need to use programs
- that are compatible with the Video for Linux API. Information on
- this API and pointers to "v4l" programs may be found at
- <file:Documentation/video4linux/API.html>.
-
- To compile this driver as a module, choose M here: the
- module will be called radio-gemtek-pci.
-
config RADIO_MAXIRADIO
tristate "Guillemot MAXI Radio FM 2000 radio"
depends on VIDEO_V4L2 && PCI
diff --git a/drivers/media/radio/Makefile b/drivers/media/radio/Makefile
index d297074..717656d 100644
--- a/drivers/media/radio/Makefile
+++ b/drivers/media/radio/Makefile
@@ -13,7 +13,6 @@ obj-$(CONFIG_RADIO_MAXIRADIO) += radio-maxiradio.o
obj-$(CONFIG_RADIO_RTRACK) += radio-aimslab.o
obj-$(CONFIG_RADIO_ZOLTRIX) += radio-zoltrix.o
obj-$(CONFIG_RADIO_GEMTEK) += radio-gemtek.o
-obj-$(CONFIG_RADIO_GEMTEK_PCI) += radio-gemtek-pci.o
obj-$(CONFIG_RADIO_TRUST) += radio-trust.o
obj-$(CONFIG_I2C_SI4713) += si4713-i2c.o
obj-$(CONFIG_RADIO_SI4713) += radio-si4713.o
diff --git a/drivers/media/radio/radio-aimslab.c b/drivers/media/radio/radio-aimslab.c
index 6cc5d13..4ce10db 100644
--- a/drivers/media/radio/radio-aimslab.c
+++ b/drivers/media/radio/radio-aimslab.c
@@ -31,6 +31,7 @@
#include <linux/module.h> /* Modules */
#include <linux/init.h> /* Initdata */
#include <linux/ioport.h> /* request_region */
+#include <linux/delay.h> /* msleep */
#include <linux/videodev2.h> /* kernel radio structs */
#include <linux/version.h> /* for KERNEL_VERSION MACRO */
#include <linux/io.h> /* outb, outb_p */
diff --git a/drivers/media/radio/radio-gemtek-pci.c b/drivers/media/radio/radio-gemtek-pci.c
deleted file mode 100644
index 28fa85b..0000000
--- a/drivers/media/radio/radio-gemtek-pci.c
+++ /dev/null
@@ -1,478 +0,0 @@
-/*
- ***************************************************************************
- *
- * radio-gemtek-pci.c - Gemtek PCI Radio driver
- * (C) 2001 Vladimir Shebordaev <vshebordaev@mail.ru>
- *
- ***************************************************************************
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public
- * License along with this program; if not, write to the Free
- * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
- * USA.
- *
- ***************************************************************************
- *
- * Gemtek Corp still silently refuses to release any specifications
- * of their multimedia devices, so the protocol still has to be
- * reverse engineered.
- *
- * The v4l code was inspired by Jonas Munsin's Gemtek serial line
- * radio device driver.
- *
- * Please, let me know if this piece of code was useful :)
- *
- * TODO: multiple device support and portability were not tested
- *
- * Converted to V4L2 API by Mauro Carvalho Chehab <mchehab@infradead.org>
- *
- ***************************************************************************
- */
-
-#include <linux/types.h>
-#include <linux/list.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-#include <linux/videodev2.h>
-#include <linux/errno.h>
-#include <linux/version.h> /* for KERNEL_VERSION MACRO */
-#include <linux/io.h>
-#include <linux/slab.h>
-#include <media/v4l2-device.h>
-#include <media/v4l2-ioctl.h>
-
-MODULE_AUTHOR("Vladimir Shebordaev <vshebordaev@mail.ru>");
-MODULE_DESCRIPTION("The video4linux driver for the Gemtek PCI Radio Card");
-MODULE_LICENSE("GPL");
-
-static int nr_radio = -1;
-static int mx = 1;
-
-module_param(mx, bool, 0);
-MODULE_PARM_DESC(mx, "single digit: 1 - turn off the turner upon module exit (default), 0 - do not");
-module_param(nr_radio, int, 0);
-MODULE_PARM_DESC(nr_radio, "video4linux device number to use");
-
-#define RADIO_VERSION KERNEL_VERSION(0, 0, 2)
-
-#ifndef PCI_VENDOR_ID_GEMTEK
-#define PCI_VENDOR_ID_GEMTEK 0x5046
-#endif
-
-#ifndef PCI_DEVICE_ID_GEMTEK_PR103
-#define PCI_DEVICE_ID_GEMTEK_PR103 0x1001
-#endif
-
-#ifndef GEMTEK_PCI_RANGE_LOW
-#define GEMTEK_PCI_RANGE_LOW (87*16000)
-#endif
-
-#ifndef GEMTEK_PCI_RANGE_HIGH
-#define GEMTEK_PCI_RANGE_HIGH (108*16000)
-#endif
-
-struct gemtek_pci {
- struct v4l2_device v4l2_dev;
- struct video_device vdev;
- struct mutex lock;
- struct pci_dev *pdev;
-
- u32 iobase;
- u32 length;
-
- u32 current_frequency;
- u8 mute;
-};
-
-static inline struct gemtek_pci *to_gemtek_pci(struct v4l2_device *v4l2_dev)
-{
- return container_of(v4l2_dev, struct gemtek_pci, v4l2_dev);
-}
-
-static inline u8 gemtek_pci_out(u16 value, u32 port)
-{
- outw(value, port);
-
- return (u8)value;
-}
-
-#define _b0(v) (*((u8 *)&v))
-
-static void __gemtek_pci_cmd(u16 value, u32 port, u8 *last_byte, int keep)
-{
- u8 byte = *last_byte;
-
- if (!value) {
- if (!keep)
- value = (u16)port;
- byte &= 0xfd;
- } else
- byte |= 2;
-
- _b0(value) = byte;
- outw(value, port);
- byte |= 1;
- _b0(value) = byte;
- outw(value, port);
- byte &= 0xfe;
- _b0(value) = byte;
- outw(value, port);
-
- *last_byte = byte;
-}
-
-static inline void gemtek_pci_nil(u32 port, u8 *last_byte)
-{
- __gemtek_pci_cmd(0x00, port, last_byte, false);
-}
-
-static inline void gemtek_pci_cmd(u16 cmd, u32 port, u8 *last_byte)
-{
- __gemtek_pci_cmd(cmd, port, last_byte, true);
-}
-
-static void gemtek_pci_setfrequency(struct gemtek_pci *card, unsigned long frequency)
-{
- int i;
- u32 value = frequency / 200 + 856;
- u16 mask = 0x8000;
- u8 last_byte;
- u32 port = card->iobase;
-
- mutex_lock(&card->lock);
- card->current_frequency = frequency;
- last_byte = gemtek_pci_out(0x06, port);
-
- i = 0;
- do {
- gemtek_pci_nil(port, &last_byte);
- i++;
- } while (i < 9);
-
- i = 0;
- do {
- gemtek_pci_cmd(value & mask, port, &last_byte);
- mask >>= 1;
- i++;
- } while (i < 16);
-
- outw(0x10, port);
- mutex_unlock(&card->lock);
-}
-
-
-static void gemtek_pci_mute(struct gemtek_pci *card)
-{
- mutex_lock(&card->lock);
- outb(0x1f, card->iobase);
- card->mute = true;
- mutex_unlock(&card->lock);
-}
-
-static void gemtek_pci_unmute(struct gemtek_pci *card)
-{
- if (card->mute) {
- gemtek_pci_setfrequency(card, card->current_frequency);
- card->mute = false;
- }
-}
-
-static int gemtek_pci_getsignal(struct gemtek_pci *card)
-{
- int sig;
-
- mutex_lock(&card->lock);
- sig = (inb(card->iobase) & 0x08) ? 0 : 1;
- mutex_unlock(&card->lock);
- return sig;
-}
-
-static int vidioc_querycap(struct file *file, void *priv,
- struct v4l2_capability *v)
-{
- struct gemtek_pci *card = video_drvdata(file);
-
- strlcpy(v->driver, "radio-gemtek-pci", sizeof(v->driver));
- strlcpy(v->card, "GemTek PCI Radio", sizeof(v->card));
- snprintf(v->bus_info, sizeof(v->bus_info), "PCI:%s", pci_name(card->pdev));
- v->version = RADIO_VERSION;
- v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
- return 0;
-}
-
-static int vidioc_g_tuner(struct file *file, void *priv,
- struct v4l2_tuner *v)
-{
- struct gemtek_pci *card = video_drvdata(file);
-
- if (v->index > 0)
- return -EINVAL;
-
- strlcpy(v->name, "FM", sizeof(v->name));
- v->type = V4L2_TUNER_RADIO;
- v->rangelow = GEMTEK_PCI_RANGE_LOW;
- v->rangehigh = GEMTEK_PCI_RANGE_HIGH;
- v->rxsubchans = V4L2_TUNER_SUB_MONO;
- v->capability = V4L2_TUNER_CAP_LOW;
- v->audmode = V4L2_TUNER_MODE_MONO;
- v->signal = 0xffff * gemtek_pci_getsignal(card);
- return 0;
-}
-
-static int vidioc_s_tuner(struct file *file, void *priv,
- struct v4l2_tuner *v)
-{
- return v->index ? -EINVAL : 0;
-}
-
-static int vidioc_s_frequency(struct file *file, void *priv,
- struct v4l2_frequency *f)
-{
- struct gemtek_pci *card = video_drvdata(file);
-
- if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO)
- return -EINVAL;
- if (f->frequency < GEMTEK_PCI_RANGE_LOW ||
- f->frequency > GEMTEK_PCI_RANGE_HIGH)
- return -EINVAL;
- gemtek_pci_setfrequency(card, f->frequency);
- card->mute = false;
- return 0;
-}
-
-static int vidioc_g_frequency(struct file *file, void *priv,
- struct v4l2_frequency *f)
-{
- struct gemtek_pci *card = video_drvdata(file);
-
- if (f->tuner != 0)
- return -EINVAL;
- f->type = V4L2_TUNER_RADIO;
- f->frequency = card->current_frequency;
- return 0;
-}
-
-static int vidioc_queryctrl(struct file *file, void *priv,
- struct v4l2_queryctrl *qc)
-{
- switch (qc->id) {
- case V4L2_CID_AUDIO_MUTE:
- return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1);
- case V4L2_CID_AUDIO_VOLUME:
- return v4l2_ctrl_query_fill(qc, 0, 65535, 65535, 65535);
- }
- return -EINVAL;
-}
-
-static int vidioc_g_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctrl)
-{
- struct gemtek_pci *card = video_drvdata(file);
-
- switch (ctrl->id) {
- case V4L2_CID_AUDIO_MUTE:
- ctrl->value = card->mute;
- return 0;
- case V4L2_CID_AUDIO_VOLUME:
- if (card->mute)
- ctrl->value = 0;
- else
- ctrl->value = 65535;
- return 0;
- }
- return -EINVAL;
-}
-
-static int vidioc_s_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctrl)
-{
- struct gemtek_pci *card = video_drvdata(file);
-
- switch (ctrl->id) {
- case V4L2_CID_AUDIO_MUTE:
- if (ctrl->value)
- gemtek_pci_mute(card);
- else
- gemtek_pci_unmute(card);
- return 0;
- case V4L2_CID_AUDIO_VOLUME:
- if (ctrl->value)
- gemtek_pci_unmute(card);
- else
- gemtek_pci_mute(card);
- return 0;
- }
- return -EINVAL;
-}
-
-static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
-{
- *i = 0;
- return 0;
-}
-
-static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
-{
- return i ? -EINVAL : 0;
-}
-
-static int vidioc_g_audio(struct file *file, void *priv,
- struct v4l2_audio *a)
-{
- a->index = 0;
- strlcpy(a->name, "Radio", sizeof(a->name));
- a->capability = V4L2_AUDCAP_STEREO;
- return 0;
-}
-
-static int vidioc_s_audio(struct file *file, void *priv,
- struct v4l2_audio *a)
-{
- return a->index ? -EINVAL : 0;
-}
-
-enum {
- GEMTEK_PR103
-};
-
-static char *card_names[] __devinitdata = {
- "GEMTEK_PR103"
-};
-
-static struct pci_device_id gemtek_pci_id[] =
-{
- { PCI_VENDOR_ID_GEMTEK, PCI_DEVICE_ID_GEMTEK_PR103,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, GEMTEK_PR103 },
- { 0 }
-};
-
-MODULE_DEVICE_TABLE(pci, gemtek_pci_id);
-
-static const struct v4l2_file_operations gemtek_pci_fops = {
- .owner = THIS_MODULE,
- .unlocked_ioctl = video_ioctl2,
-};
-
-static const struct v4l2_ioctl_ops gemtek_pci_ioctl_ops = {
- .vidioc_querycap = vidioc_querycap,
- .vidioc_g_tuner = vidioc_g_tuner,
- .vidioc_s_tuner = vidioc_s_tuner,
- .vidioc_g_audio = vidioc_g_audio,
- .vidioc_s_audio = vidioc_s_audio,
- .vidioc_g_input = vidioc_g_input,
- .vidioc_s_input = vidioc_s_input,
- .vidioc_g_frequency = vidioc_g_frequency,
- .vidioc_s_frequency = vidioc_s_frequency,
- .vidioc_queryctrl = vidioc_queryctrl,
- .vidioc_g_ctrl = vidioc_g_ctrl,
- .vidioc_s_ctrl = vidioc_s_ctrl,
-};
-
-static int __devinit gemtek_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id)
-{
- struct gemtek_pci *card;
- struct v4l2_device *v4l2_dev;
- int res;
-
- card = kzalloc(sizeof(struct gemtek_pci), GFP_KERNEL);
- if (card == NULL) {
- dev_err(&pdev->dev, "out of memory\n");
- return -ENOMEM;
- }
-
- v4l2_dev = &card->v4l2_dev;
- mutex_init(&card->lock);
- card->pdev = pdev;
-
- strlcpy(v4l2_dev->name, "gemtek_pci", sizeof(v4l2_dev->name));
-
- res = v4l2_device_register(&pdev->dev, v4l2_dev);
- if (res < 0) {
- v4l2_err(v4l2_dev, "Could not register v4l2_device\n");
- kfree(card);
- return res;
- }
-
- if (pci_enable_device(pdev))
- goto err_pci;
-
- card->iobase = pci_resource_start(pdev, 0);
- card->length = pci_resource_len(pdev, 0);
-
- if (request_region(card->iobase, card->length, card_names[pci_id->driver_data]) == NULL) {
- v4l2_err(v4l2_dev, "i/o port already in use\n");
- goto err_pci;
- }
-
- strlcpy(card->vdev.name, v4l2_dev->name, sizeof(card->vdev.name));
- card->vdev.v4l2_dev = v4l2_dev;
- card->vdev.fops = &gemtek_pci_fops;
- card->vdev.ioctl_ops = &gemtek_pci_ioctl_ops;
- card->vdev.release = video_device_release_empty;
- video_set_drvdata(&card->vdev, card);
-
- gemtek_pci_mute(card);
-
- if (video_register_device(&card->vdev, VFL_TYPE_RADIO, nr_radio) < 0)
- goto err_video;
-
- v4l2_info(v4l2_dev, "Gemtek PCI Radio (rev. %d) found at 0x%04x-0x%04x.\n",
- pdev->revision, card->iobase, card->iobase + card->length - 1);
-
- return 0;
-
-err_video:
- release_region(card->iobase, card->length);
-
-err_pci:
- v4l2_device_unregister(v4l2_dev);
- kfree(card);
- return -ENODEV;
-}
-
-static void __devexit gemtek_pci_remove(struct pci_dev *pdev)
-{
- struct v4l2_device *v4l2_dev = dev_get_drvdata(&pdev->dev);
- struct gemtek_pci *card = to_gemtek_pci(v4l2_dev);
-
- video_unregister_device(&card->vdev);
- v4l2_device_unregister(v4l2_dev);
-
- release_region(card->iobase, card->length);
-
- if (mx)
- gemtek_pci_mute(card);
-
- kfree(card);
-}
-
-static struct pci_driver gemtek_pci_driver = {
- .name = "gemtek_pci",
- .id_table = gemtek_pci_id,
- .probe = gemtek_pci_probe,
- .remove = __devexit_p(gemtek_pci_remove),
-};
-
-static int __init gemtek_pci_init(void)
-{
- return pci_register_driver(&gemtek_pci_driver);
-}
-
-static void __exit gemtek_pci_exit(void)
-{
- pci_unregister_driver(&gemtek_pci_driver);
-}
-
-module_init(gemtek_pci_init);
-module_exit(gemtek_pci_exit);
diff --git a/drivers/media/radio/radio-maxiradio.c b/drivers/media/radio/radio-maxiradio.c
index 6459a22..5c2a905 100644
--- a/drivers/media/radio/radio-maxiradio.c
+++ b/drivers/media/radio/radio-maxiradio.c
@@ -77,8 +77,8 @@ MODULE_PARM_DESC(debug, "activates debug info");
/* TEA5757 pin mappings */
static const int clk = 1, data = 2, wren = 4, mo_st = 8, power = 16;
-#define FREQ_LO (50 * 16000)
-#define FREQ_HI (150 * 16000)
+#define FREQ_LO (87 * 16000)
+#define FREQ_HI (108 * 16000)
#define FREQ_IF 171200 /* 10.7*16000 */
#define FREQ_STEP 200 /* 12.5*16 */
diff --git a/drivers/media/radio/radio-wl1273.c b/drivers/media/radio/radio-wl1273.c
index dd6bd36..7ecc8e6 100644
--- a/drivers/media/radio/radio-wl1273.c
+++ b/drivers/media/radio/radio-wl1273.c
@@ -1407,7 +1407,7 @@ static const struct v4l2_file_operations wl1273_fops = {
.read = wl1273_fm_fops_read,
.write = wl1273_fm_fops_write,
.poll = wl1273_fm_fops_poll,
- .ioctl = video_ioctl2,
+ .unlocked_ioctl = video_ioctl2,
.open = wl1273_fm_fops_open,
.release = wl1273_fm_fops_release,
};
diff --git a/drivers/media/radio/si470x/radio-si470x-common.c b/drivers/media/radio/si470x/radio-si470x-common.c
index ac76dfe..60c176f 100644
--- a/drivers/media/radio/si470x/radio-si470x-common.c
+++ b/drivers/media/radio/si470x/radio-si470x-common.c
@@ -357,7 +357,8 @@ int si470x_start(struct si470x_device *radio)
goto done;
/* sysconfig 1 */
- radio->registers[SYSCONFIG1] = SYSCONFIG1_DE;
+ radio->registers[SYSCONFIG1] =
+ (de << 11) & SYSCONFIG1_DE; /* DE*/
retval = si470x_set_register(radio, SYSCONFIG1);
if (retval < 0)
goto done;
@@ -687,12 +688,8 @@ static int si470x_vidioc_g_tuner(struct file *file, void *priv,
/* driver constants */
strcpy(tuner->name, "FM");
tuner->type = V4L2_TUNER_RADIO;
-#if defined(CONFIG_USB_SI470X) || defined(CONFIG_USB_SI470X_MODULE)
tuner->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO |
V4L2_TUNER_CAP_RDS | V4L2_TUNER_CAP_RDS_BLOCK_IO;
-#else
- tuner->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO;
-#endif
/* range limits */
switch ((radio->registers[SYSCONFIG2] & SYSCONFIG2_BAND) >> 6) {
@@ -718,12 +715,10 @@ static int si470x_vidioc_g_tuner(struct file *file, void *priv,
tuner->rxsubchans = V4L2_TUNER_SUB_MONO;
else
tuner->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
-#if defined(CONFIG_USB_SI470X) || defined(CONFIG_USB_SI470X_MODULE)
/* If there is a reliable method of detecting an RDS channel,
then this code should check for that before setting this
RDS subchannel. */
tuner->rxsubchans |= V4L2_TUNER_SUB_RDS;
-#endif
/* mono/stereo selector */
if ((radio->registers[POWERCFG] & POWERCFG_MONO) == 0)
diff --git a/drivers/media/rc/ene_ir.c b/drivers/media/rc/ene_ir.c
index 80b3c31..1ac4913 100644
--- a/drivers/media/rc/ene_ir.c
+++ b/drivers/media/rc/ene_ir.c
@@ -446,27 +446,27 @@ static void ene_rx_setup(struct ene_device *dev)
select_timeout:
if (dev->rx_fan_input_inuse) {
- dev->rdev->rx_resolution = MS_TO_NS(ENE_FW_SAMPLE_PERIOD_FAN);
+ dev->rdev->rx_resolution = US_TO_NS(ENE_FW_SAMPLE_PERIOD_FAN);
/* Fan input doesn't support timeouts, it just ends the
input with a maximum sample */
dev->rdev->min_timeout = dev->rdev->max_timeout =
- MS_TO_NS(ENE_FW_SMPL_BUF_FAN_MSK *
+ US_TO_NS(ENE_FW_SMPL_BUF_FAN_MSK *
ENE_FW_SAMPLE_PERIOD_FAN);
} else {
- dev->rdev->rx_resolution = MS_TO_NS(sample_period);
+ dev->rdev->rx_resolution = US_TO_NS(sample_period);
/* Theoreticly timeout is unlimited, but we cap it
* because it was seen that on one device, it
* would stop sending spaces after around 250 msec.
* Besides, this is close to 2^32 anyway and timeout is u32.
*/
- dev->rdev->min_timeout = MS_TO_NS(127 * sample_period);
- dev->rdev->max_timeout = MS_TO_NS(200000);
+ dev->rdev->min_timeout = US_TO_NS(127 * sample_period);
+ dev->rdev->max_timeout = US_TO_NS(200000);
}
if (dev->hw_learning_and_tx_capable)
- dev->rdev->tx_resolution = MS_TO_NS(sample_period);
+ dev->rdev->tx_resolution = US_TO_NS(sample_period);
if (dev->rdev->timeout > dev->rdev->max_timeout)
dev->rdev->timeout = dev->rdev->max_timeout;
@@ -801,7 +801,7 @@ static irqreturn_t ene_isr(int irq, void *data)
dbg("RX: %d (%s)", hw_sample, pulse ? "pulse" : "space");
- ev.duration = MS_TO_NS(hw_sample);
+ ev.duration = US_TO_NS(hw_sample);
ev.pulse = pulse;
ir_raw_event_store_with_filter(dev->rdev, &ev);
}
@@ -821,7 +821,7 @@ static void ene_setup_default_settings(struct ene_device *dev)
dev->learning_mode_enabled = learning_mode_force;
/* Set reasonable default timeout */
- dev->rdev->timeout = MS_TO_NS(150000);
+ dev->rdev->timeout = US_TO_NS(150000);
}
/* Upload all hardware settings at once. Used at load and resume time */
@@ -1004,6 +1004,10 @@ static int ene_probe(struct pnp_dev *pnp_dev, const struct pnp_device_id *id)
/* validate resources */
error = -ENODEV;
+ /* init these to -1, as 0 is valid for both */
+ dev->hw_io = -1;
+ dev->irq = -1;
+
if (!pnp_port_valid(pnp_dev, 0) ||
pnp_port_len(pnp_dev, 0) < ENE_IO_SIZE)
goto error;
@@ -1072,6 +1076,8 @@ static int ene_probe(struct pnp_dev *pnp_dev, const struct pnp_device_id *id)
rdev->input_name = "ENE eHome Infrared Remote Transceiver";
}
+ dev->rdev = rdev;
+
ene_rx_setup_hw_buffer(dev);
ene_setup_default_settings(dev);
ene_setup_hw_settings(dev);
@@ -1083,7 +1089,6 @@ static int ene_probe(struct pnp_dev *pnp_dev, const struct pnp_device_id *id)
if (error < 0)
goto error;
- dev->rdev = rdev;
ene_notice("driver has been succesfully loaded");
return 0;
error:
diff --git a/drivers/media/rc/ene_ir.h b/drivers/media/rc/ene_ir.h
index c179baf..337a41d 100644
--- a/drivers/media/rc/ene_ir.h
+++ b/drivers/media/rc/ene_ir.h
@@ -201,8 +201,6 @@
#define dbg_verbose(format, ...) __dbg(2, format, ## __VA_ARGS__)
#define dbg_regs(format, ...) __dbg(3, format, ## __VA_ARGS__)
-#define MS_TO_NS(msec) ((msec) * 1000)
-
struct ene_device {
struct pnp_dev *pnp_dev;
struct rc_dev *rdev;
diff --git a/drivers/media/rc/imon.c b/drivers/media/rc/imon.c
index 6811512..e7dc6b4 100644
--- a/drivers/media/rc/imon.c
+++ b/drivers/media/rc/imon.c
@@ -988,7 +988,6 @@ static int imon_ir_change_protocol(struct rc_dev *rc, u64 rc_type)
int retval;
struct imon_context *ictx = rc->priv;
struct device *dev = ictx->dev;
- bool pad_mouse;
unsigned char ir_proto_packet[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x86 };
@@ -1000,29 +999,20 @@ static int imon_ir_change_protocol(struct rc_dev *rc, u64 rc_type)
case RC_TYPE_RC6:
dev_dbg(dev, "Configuring IR receiver for MCE protocol\n");
ir_proto_packet[0] = 0x01;
- pad_mouse = false;
break;
case RC_TYPE_UNKNOWN:
case RC_TYPE_OTHER:
dev_dbg(dev, "Configuring IR receiver for iMON protocol\n");
- if (pad_stabilize && !nomouse)
- pad_mouse = true;
- else {
+ if (!pad_stabilize)
dev_dbg(dev, "PAD stabilize functionality disabled\n");
- pad_mouse = false;
- }
/* ir_proto_packet[0] = 0x00; // already the default */
rc_type = RC_TYPE_OTHER;
break;
default:
dev_warn(dev, "Unsupported IR protocol specified, overriding "
"to iMON IR protocol\n");
- if (pad_stabilize && !nomouse)
- pad_mouse = true;
- else {
+ if (!pad_stabilize)
dev_dbg(dev, "PAD stabilize functionality disabled\n");
- pad_mouse = false;
- }
/* ir_proto_packet[0] = 0x00; // already the default */
rc_type = RC_TYPE_OTHER;
break;
@@ -1035,7 +1025,7 @@ static int imon_ir_change_protocol(struct rc_dev *rc, u64 rc_type)
goto out;
ictx->rc_type = rc_type;
- ictx->pad_mouse = pad_mouse;
+ ictx->pad_mouse = false;
out:
return retval;
@@ -1517,7 +1507,7 @@ static void imon_incoming_packet(struct imon_context *ictx,
spin_unlock_irqrestore(&ictx->kc_lock, flags);
return;
} else {
- ictx->pad_mouse = 0;
+ ictx->pad_mouse = false;
dev_dbg(dev, "mouse mode disabled, passing key value\n");
}
}
@@ -1756,7 +1746,6 @@ static void imon_get_ffdc_type(struct imon_context *ictx)
printk(KERN_CONT " (id 0x%02x)\n", ffdc_cfg_byte);
ictx->display_type = detected_display_type;
- ictx->rdev->allowed_protos = allowed_protos;
ictx->rc_type = allowed_protos;
}
@@ -1839,10 +1828,6 @@ static struct rc_dev *imon_init_rdev(struct imon_context *ictx)
rdev->allowed_protos = RC_TYPE_OTHER | RC_TYPE_RC6; /* iMON PAD or MCE */
rdev->change_protocol = imon_ir_change_protocol;
rdev->driver_name = MOD_NAME;
- if (ictx->rc_type == RC_TYPE_RC6)
- rdev->map_name = RC_MAP_IMON_MCE;
- else
- rdev->map_name = RC_MAP_IMON_PAD;
/* Enable front-panel buttons and/or knobs */
memcpy(ictx->usb_tx_buf, &fp_packet, sizeof(fp_packet));
@@ -1851,11 +1836,18 @@ static struct rc_dev *imon_init_rdev(struct imon_context *ictx)
if (ret)
dev_info(ictx->dev, "panel buttons/knobs setup failed\n");
- if (ictx->product == 0xffdc)
+ if (ictx->product == 0xffdc) {
imon_get_ffdc_type(ictx);
+ rdev->allowed_protos = ictx->rc_type;
+ }
imon_set_display_type(ictx);
+ if (ictx->rc_type == RC_TYPE_RC6)
+ rdev->map_name = RC_MAP_IMON_MCE;
+ else
+ rdev->map_name = RC_MAP_IMON_PAD;
+
ret = rc_register_device(rdev);
if (ret < 0) {
dev_err(ictx->dev, "remote input dev register failed\n");
@@ -2108,18 +2100,6 @@ static struct imon_context *imon_init_intf0(struct usb_interface *intf)
goto find_endpoint_failed;
}
- ictx->idev = imon_init_idev(ictx);
- if (!ictx->idev) {
- dev_err(dev, "%s: input device setup failed\n", __func__);
- goto idev_setup_failed;
- }
-
- ictx->rdev = imon_init_rdev(ictx);
- if (!ictx->rdev) {
- dev_err(dev, "%s: rc device setup failed\n", __func__);
- goto rdev_setup_failed;
- }
-
usb_fill_int_urb(ictx->rx_urb_intf0, ictx->usbdev_intf0,
usb_rcvintpipe(ictx->usbdev_intf0,
ictx->rx_endpoint_intf0->bEndpointAddress),
@@ -2133,13 +2113,25 @@ static struct imon_context *imon_init_intf0(struct usb_interface *intf)
goto urb_submit_failed;
}
+ ictx->idev = imon_init_idev(ictx);
+ if (!ictx->idev) {
+ dev_err(dev, "%s: input device setup failed\n", __func__);
+ goto idev_setup_failed;
+ }
+
+ ictx->rdev = imon_init_rdev(ictx);
+ if (!ictx->rdev) {
+ dev_err(dev, "%s: rc device setup failed\n", __func__);
+ goto rdev_setup_failed;
+ }
+
return ictx;
-urb_submit_failed:
- rc_unregister_device(ictx->rdev);
rdev_setup_failed:
input_unregister_device(ictx->idev);
idev_setup_failed:
+ usb_kill_urb(ictx->rx_urb_intf0);
+urb_submit_failed:
find_endpoint_failed:
mutex_unlock(&ictx->lock);
usb_free_urb(tx_urb);
diff --git a/drivers/media/rc/ir-raw.c b/drivers/media/rc/ir-raw.c
index 185badd..73230ff 100644
--- a/drivers/media/rc/ir-raw.c
+++ b/drivers/media/rc/ir-raw.c
@@ -233,7 +233,7 @@ EXPORT_SYMBOL_GPL(ir_raw_event_handle);
/* used internally by the sysfs interface */
u64
-ir_raw_get_allowed_protocols()
+ir_raw_get_allowed_protocols(void)
{
u64 protocols;
mutex_lock(&ir_raw_handler_lock);
diff --git a/drivers/media/rc/keymaps/rc-dib0700-nec.c b/drivers/media/rc/keymaps/rc-dib0700-nec.c
index c59851b..7a5f530 100644
--- a/drivers/media/rc/keymaps/rc-dib0700-nec.c
+++ b/drivers/media/rc/keymaps/rc-dib0700-nec.c
@@ -19,35 +19,35 @@
static struct rc_map_table dib0700_nec_table[] = {
/* Key codes for the Pixelview SBTVD remote */
- { 0x8613, KEY_MUTE },
- { 0x8612, KEY_POWER },
- { 0x8601, KEY_1 },
- { 0x8602, KEY_2 },
- { 0x8603, KEY_3 },
- { 0x8604, KEY_4 },
- { 0x8605, KEY_5 },
- { 0x8606, KEY_6 },
- { 0x8607, KEY_7 },
- { 0x8608, KEY_8 },
- { 0x8609, KEY_9 },
- { 0x8600, KEY_0 },
- { 0x860d, KEY_CHANNELUP },
- { 0x8619, KEY_CHANNELDOWN },
- { 0x8610, KEY_VOLUMEUP },
- { 0x860c, KEY_VOLUMEDOWN },
+ { 0x866b13, KEY_MUTE },
+ { 0x866b12, KEY_POWER },
+ { 0x866b01, KEY_1 },
+ { 0x866b02, KEY_2 },
+ { 0x866b03, KEY_3 },
+ { 0x866b04, KEY_4 },
+ { 0x866b05, KEY_5 },
+ { 0x866b06, KEY_6 },
+ { 0x866b07, KEY_7 },
+ { 0x866b08, KEY_8 },
+ { 0x866b09, KEY_9 },
+ { 0x866b00, KEY_0 },
+ { 0x866b0d, KEY_CHANNELUP },
+ { 0x866b19, KEY_CHANNELDOWN },
+ { 0x866b10, KEY_VOLUMEUP },
+ { 0x866b0c, KEY_VOLUMEDOWN },
- { 0x860a, KEY_CAMERA },
- { 0x860b, KEY_ZOOM },
- { 0x861b, KEY_BACKSPACE },
- { 0x8615, KEY_ENTER },
+ { 0x866b0a, KEY_CAMERA },
+ { 0x866b0b, KEY_ZOOM },
+ { 0x866b1b, KEY_BACKSPACE },
+ { 0x866b15, KEY_ENTER },
- { 0x861d, KEY_UP },
- { 0x861e, KEY_DOWN },
- { 0x860e, KEY_LEFT },
- { 0x860f, KEY_RIGHT },
+ { 0x866b1d, KEY_UP },
+ { 0x866b1e, KEY_DOWN },
+ { 0x866b0e, KEY_LEFT },
+ { 0x866b0f, KEY_RIGHT },
- { 0x8618, KEY_RECORD },
- { 0x861a, KEY_STOP },
+ { 0x866b18, KEY_RECORD },
+ { 0x866b1a, KEY_STOP },
/* Key codes for the EvolutePC TVWay+ remote */
{ 0x7a00, KEY_MENU },
diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c
index 0fef6ef..079353e 100644
--- a/drivers/media/rc/mceusb.c
+++ b/drivers/media/rc/mceusb.c
@@ -48,7 +48,6 @@
#define USB_BUFLEN 32 /* USB reception buffer length */
#define USB_CTRL_MSG_SZ 2 /* Size of usb ctrl msg on gen1 hw */
#define MCE_G1_INIT_MSGS 40 /* Init messages on gen1 hw to throw out */
-#define MS_TO_NS(msec) ((msec) * 1000)
/* MCE constants */
#define MCE_CMDBUF_SIZE 384 /* MCE Command buffer length */
@@ -858,7 +857,7 @@ static void mceusb_process_ir_data(struct mceusb_dev *ir, int buf_len)
ir->rem--;
rawir.pulse = ((ir->buf_in[i] & MCE_PULSE_BIT) != 0);
rawir.duration = (ir->buf_in[i] & MCE_PULSE_MASK)
- * MS_TO_NS(MCE_TIME_UNIT);
+ * MS_TO_US(MCE_TIME_UNIT);
dev_dbg(ir->dev, "Storing %s with duration %d\n",
rawir.pulse ? "pulse" : "space",
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index eb875af..aa02160 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -78,7 +78,7 @@ config VIDEO_FIXED_MINOR_RANGES
config VIDEO_HELPER_CHIPS_AUTO
bool "Autoselect pertinent encoders/decoders and other helper chips"
- default y if !EMBEDDED
+ default y if !EXPERT
---help---
Most video cards may require additional modules to encode or
decode audio/video standards. This option will autoselect
@@ -141,15 +141,6 @@ config VIDEO_TDA9840
To compile this driver as a module, choose M here: the
module will be called tda9840.
-config VIDEO_TDA9875
- tristate "Philips TDA9875 audio processor"
- depends on VIDEO_V4L2 && I2C
- ---help---
- Support for tda9875 audio decoder chip found on some bt8xx boards.
-
- To compile this driver as a module, choose M here: the
- module will be called tda9875.
-
config VIDEO_TEA6415C
tristate "Philips TEA6415C audio processor"
depends on I2C
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index 81e38cb..a509d31 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -27,7 +27,6 @@ obj-$(CONFIG_VIDEO_V4L2_COMMON) += v4l2-common.o
obj-$(CONFIG_VIDEO_TUNER) += tuner.o
obj-$(CONFIG_VIDEO_TVAUDIO) += tvaudio.o
obj-$(CONFIG_VIDEO_TDA7432) += tda7432.o
-obj-$(CONFIG_VIDEO_TDA9875) += tda9875.o
obj-$(CONFIG_VIDEO_SAA6588) += saa6588.o
obj-$(CONFIG_VIDEO_TDA9840) += tda9840.o
obj-$(CONFIG_VIDEO_TEA6415C) += tea6415c.o
diff --git a/drivers/media/video/adv7175.c b/drivers/media/video/adv7175.c
index f318b51..d2327db 100644
--- a/drivers/media/video/adv7175.c
+++ b/drivers/media/video/adv7175.c
@@ -303,11 +303,22 @@ static int adv7175_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ide
return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_ADV7175, 0);
}
+static int adv7175_s_power(struct v4l2_subdev *sd, int on)
+{
+ if (on)
+ adv7175_write(sd, 0x01, 0x00);
+ else
+ adv7175_write(sd, 0x01, 0x78);
+
+ return 0;
+}
+
/* ----------------------------------------------------------------------- */
static const struct v4l2_subdev_core_ops adv7175_core_ops = {
.g_chip_ident = adv7175_g_chip_ident,
.init = adv7175_init,
+ .s_power = adv7175_s_power,
};
static const struct v4l2_subdev_video_ops adv7175_video_ops = {
diff --git a/drivers/media/video/bt8xx/bttv-cards.c b/drivers/media/video/bt8xx/bttv-cards.c
index 49efcf6..7f58756 100644
--- a/drivers/media/video/bt8xx/bttv-cards.c
+++ b/drivers/media/video/bt8xx/bttv-cards.c
@@ -1373,7 +1373,6 @@ struct tvcard bttv_tvcards[] = {
.gpiomute = 0x1800,
.audio_mode_gpio= fv2000s_audio,
.no_msp34xx = 1,
- .no_tda9875 = 1,
.needs_tvaudio = 1,
.pll = PLL_28,
.tuner_type = TUNER_PHILIPS_PAL,
@@ -1511,7 +1510,6 @@ struct tvcard bttv_tvcards[] = {
.gpiomute = 0x09,
.needs_tvaudio = 1,
.no_msp34xx = 1,
- .no_tda9875 = 1,
.pll = PLL_28,
.tuner_type = TUNER_PHILIPS_PAL,
.tuner_addr = ADDR_UNSET,
@@ -1550,7 +1548,6 @@ struct tvcard bttv_tvcards[] = {
.gpiomask2 = 0x07ff,
.muxsel = MUXSEL(3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3),
.no_msp34xx = 1,
- .no_tda9875 = 1,
.tuner_type = TUNER_ABSENT,
.tuner_addr = ADDR_UNSET,
.muxsel_hook = rv605_muxsel,
@@ -1686,7 +1683,6 @@ struct tvcard bttv_tvcards[] = {
.tuner_type = TUNER_ABSENT,
.tuner_addr = ADDR_UNSET,
.no_msp34xx = 1,
- .no_tda9875 = 1,
.no_tda7432 = 1,
},
[BTTV_BOARD_OSPREY1x0_848] = {
@@ -1699,7 +1695,6 @@ struct tvcard bttv_tvcards[] = {
.tuner_type = TUNER_ABSENT,
.tuner_addr = ADDR_UNSET,
.no_msp34xx = 1,
- .no_tda9875 = 1,
.no_tda7432 = 1,
},
@@ -1714,7 +1709,6 @@ struct tvcard bttv_tvcards[] = {
.tuner_type = TUNER_ABSENT,
.tuner_addr = ADDR_UNSET,
.no_msp34xx = 1,
- .no_tda9875 = 1,
.no_tda7432 = 1,
},
[BTTV_BOARD_OSPREY1x1] = {
@@ -1727,7 +1721,6 @@ struct tvcard bttv_tvcards[] = {
.tuner_type = TUNER_ABSENT,
.tuner_addr = ADDR_UNSET,
.no_msp34xx = 1,
- .no_tda9875 = 1,
.no_tda7432 = 1,
},
[BTTV_BOARD_OSPREY1x1_SVID] = {
@@ -1740,7 +1733,6 @@ struct tvcard bttv_tvcards[] = {
.tuner_type = TUNER_ABSENT,
.tuner_addr = ADDR_UNSET,
.no_msp34xx = 1,
- .no_tda9875 = 1,
.no_tda7432 = 1,
},
[BTTV_BOARD_OSPREY2xx] = {
@@ -1753,7 +1745,6 @@ struct tvcard bttv_tvcards[] = {
.tuner_type = TUNER_ABSENT,
.tuner_addr = ADDR_UNSET,
.no_msp34xx = 1,
- .no_tda9875 = 1,
.no_tda7432 = 1,
},
@@ -1768,7 +1759,6 @@ struct tvcard bttv_tvcards[] = {
.tuner_type = TUNER_ABSENT,
.tuner_addr = ADDR_UNSET,
.no_msp34xx = 1,
- .no_tda9875 = 1,
.no_tda7432 = 1,
},
[BTTV_BOARD_OSPREY2x0] = {
@@ -1781,7 +1771,6 @@ struct tvcard bttv_tvcards[] = {
.tuner_type = TUNER_ABSENT,
.tuner_addr = ADDR_UNSET,
.no_msp34xx = 1,
- .no_tda9875 = 1,
.no_tda7432 = 1,
},
[BTTV_BOARD_OSPREY500] = {
@@ -1794,7 +1783,6 @@ struct tvcard bttv_tvcards[] = {
.tuner_type = TUNER_ABSENT,
.tuner_addr = ADDR_UNSET,
.no_msp34xx = 1,
- .no_tda9875 = 1,
.no_tda7432 = 1,
},
[BTTV_BOARD_OSPREY540] = {
@@ -1805,7 +1793,6 @@ struct tvcard bttv_tvcards[] = {
.tuner_type = TUNER_ABSENT,
.tuner_addr = ADDR_UNSET,
.no_msp34xx = 1,
- .no_tda9875 = 1,
.no_tda7432 = 1,
},
@@ -1820,7 +1807,6 @@ struct tvcard bttv_tvcards[] = {
.tuner_type = TUNER_ABSENT,
.tuner_addr = ADDR_UNSET,
.no_msp34xx = 1,
- .no_tda9875 = 1,
.no_tda7432 = 1, /* must avoid, conflicts with the bt860 */
},
[BTTV_BOARD_IDS_EAGLE] = {
@@ -1835,7 +1821,6 @@ struct tvcard bttv_tvcards[] = {
.muxsel = MUXSEL(2, 2, 2, 2),
.muxsel_hook = eagle_muxsel,
.no_msp34xx = 1,
- .no_tda9875 = 1,
.pll = PLL_28,
},
[BTTV_BOARD_PINNACLESAT] = {
@@ -1846,7 +1831,6 @@ struct tvcard bttv_tvcards[] = {
.tuner_type = TUNER_ABSENT,
.tuner_addr = ADDR_UNSET,
.no_msp34xx = 1,
- .no_tda9875 = 1,
.no_tda7432 = 1,
.muxsel = MUXSEL(3, 1),
.pll = PLL_28,
@@ -1897,7 +1881,6 @@ struct tvcard bttv_tvcards[] = {
.svhs = 2,
.gpiomask = 0,
.no_msp34xx = 1,
- .no_tda9875 = 1,
.no_tda7432 = 1,
.muxsel = MUXSEL(2, 0, 1),
.pll = PLL_28,
@@ -1970,7 +1953,6 @@ struct tvcard bttv_tvcards[] = {
/* Tuner, CVid, SVid, CVid over SVid connector */
.muxsel = MUXSEL(2, 3, 1, 1),
.gpiomask = 0,
- .no_tda9875 = 1,
.no_tda7432 = 1,
.tuner_type = TUNER_PHILIPS_PAL_I,
.tuner_addr = ADDR_UNSET,
@@ -2017,7 +1999,6 @@ struct tvcard bttv_tvcards[] = {
.muxsel = MUXSEL(2,2,2,2, 3,3,3,3, 1,1,1,1, 0,0,0,0),
.muxsel_hook = xguard_muxsel,
.no_msp34xx = 1,
- .no_tda9875 = 1,
.no_tda7432 = 1,
.pll = PLL_28,
},
@@ -2029,7 +2010,6 @@ struct tvcard bttv_tvcards[] = {
.svhs = NO_SVHS,
.muxsel = MUXSEL(2, 3, 1, 0),
.no_msp34xx = 1,
- .no_tda9875 = 1,
.no_tda7432 = 1,
.pll = PLL_28,
.tuner_type = TUNER_ABSENT,
@@ -2134,7 +2114,6 @@ struct tvcard bttv_tvcards[] = {
.svhs = NO_SVHS, /* card has no svhs */
.needs_tvaudio = 0,
.no_msp34xx = 1,
- .no_tda9875 = 1,
.no_tda7432 = 1,
.gpiomask = 0x00,
.muxsel = MUXSEL(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
@@ -2156,7 +2135,6 @@ struct tvcard bttv_tvcards[] = {
[BTTV_BOARD_TWINHAN_DST] = {
.name = "Twinhan DST + clones",
.no_msp34xx = 1,
- .no_tda9875 = 1,
.no_tda7432 = 1,
.tuner_type = TUNER_ABSENT,
.tuner_addr = ADDR_UNSET,
@@ -2171,7 +2149,6 @@ struct tvcard bttv_tvcards[] = {
/* Vid In, SVid In, Vid over SVid in connector */
.muxsel = MUXSEL(3, 1, 1, 3),
.no_msp34xx = 1,
- .no_tda9875 = 1,
.no_tda7432 = 1,
.tuner_type = TUNER_ABSENT,
.tuner_addr = ADDR_UNSET,
@@ -2226,7 +2203,6 @@ struct tvcard bttv_tvcards[] = {
.svhs = NO_SVHS,
.muxsel = MUXSEL(2, 3, 1, 0),
.no_msp34xx = 1,
- .no_tda9875 = 1,
.no_tda7432 = 1,
.needs_tvaudio = 0,
.tuner_type = TUNER_ABSENT,
@@ -2278,7 +2254,6 @@ struct tvcard bttv_tvcards[] = {
.gpiomask = 0,
.gpiomask2 = 0x3C<<16,/*Set the GPIO[18]->GPIO[21] as output pin.==> drive the video inputs through analog multiplexers*/
.no_msp34xx = 1,
- .no_tda9875 = 1,
.no_tda7432 = 1,
/*878A input is always MUX0, see above.*/
.muxsel = MUXSEL(2, 2, 2, 2),
@@ -2302,7 +2277,6 @@ struct tvcard bttv_tvcards[] = {
.tuner_type = TUNER_TEMIC_PAL,
.tuner_addr = ADDR_UNSET,
.no_msp34xx = 1,
- .no_tda9875 = 1,
},
[BTTV_BOARD_AVDVBT_771] = {
/* Wolfram Joost <wojo@frokaschwei.de> */
@@ -2313,7 +2287,6 @@ struct tvcard bttv_tvcards[] = {
.tuner_addr = ADDR_UNSET,
.muxsel = MUXSEL(3, 3),
.no_msp34xx = 1,
- .no_tda9875 = 1,
.no_tda7432 = 1,
.pll = PLL_28,
.has_dvb = 1,
@@ -2329,7 +2302,6 @@ struct tvcard bttv_tvcards[] = {
.svhs = 1,
.muxsel = MUXSEL(3, 1, 2, 0), /* Comp0, S-Video, ?, ? */
.no_msp34xx = 1,
- .no_tda9875 = 1,
.no_tda7432 = 1,
.pll = PLL_28,
.tuner_type = TUNER_ABSENT,
@@ -2393,7 +2365,6 @@ struct tvcard bttv_tvcards[] = {
/* Chris Pascoe <c.pascoe@itee.uq.edu.au> */
.name = "DViCO FusionHDTV DVB-T Lite",
.no_msp34xx = 1,
- .no_tda9875 = 1,
.no_tda7432 = 1,
.pll = PLL_28,
.no_video = 1,
@@ -2440,7 +2411,6 @@ struct tvcard bttv_tvcards[] = {
.muxsel = MUXSEL(2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2),
.pll = PLL_28,
.no_msp34xx = 1,
- .no_tda9875 = 1,
.no_tda7432 = 1,
.tuner_type = TUNER_ABSENT,
.tuner_addr = ADDR_UNSET,
@@ -2478,7 +2448,6 @@ struct tvcard bttv_tvcards[] = {
.pll = PLL_28,
.no_msp34xx = 1,
.no_tda7432 = 1,
- .no_tda9875 = 1,
.muxsel_hook = kodicom4400r_muxsel,
},
[BTTV_BOARD_KODICOM_4400R_SL] = {
@@ -2500,7 +2469,6 @@ struct tvcard bttv_tvcards[] = {
.pll = PLL_28,
.no_msp34xx = 1,
.no_tda7432 = 1,
- .no_tda9875 = 1,
.muxsel_hook = kodicom4400r_muxsel,
},
/* ---- card 0x86---------------------------------- */
@@ -2530,7 +2498,6 @@ struct tvcard bttv_tvcards[] = {
.gpiomux = { 0x00400005, 0, 0x00000001, 0 },
.gpiomute = 0x00c00007,
.no_msp34xx = 1,
- .no_tda9875 = 1,
.no_tda7432 = 1,
.has_dvb = 1,
},
@@ -2630,7 +2597,6 @@ struct tvcard bttv_tvcards[] = {
.tuner_type = TUNER_ABSENT,
.tuner_addr = ADDR_UNSET,
.no_msp34xx = 1,
- .no_tda9875 = 1,
.no_tda7432 = 1,
},
/* ---- card 0x8d ---------------------------------- */
@@ -2658,7 +2624,6 @@ struct tvcard bttv_tvcards[] = {
.muxsel = MUXSEL(2, 3, 1, 1),
.gpiomux = { 100000, 100002, 100002, 100000 },
.no_msp34xx = 1,
- .no_tda9875 = 1,
.no_tda7432 = 1,
.pll = PLL_28,
.tuner_type = TUNER_TNF_5335MF,
@@ -2674,7 +2639,6 @@ struct tvcard bttv_tvcards[] = {
.gpiomask = 0x0f, /* old: 7 */
.muxsel = MUXSEL(0, 1, 3, 2), /* Composite 0-3 */
.no_msp34xx = 1,
- .no_tda9875 = 1,
.no_tda7432 = 1,
.tuner_type = TUNER_ABSENT,
.tuner_addr = ADDR_UNSET,
@@ -2732,7 +2696,6 @@ struct tvcard bttv_tvcards[] = {
.gpiomux = { 0x00400005, 0, 0x00000001, 0 },
.gpiomute = 0x00c00007,
.no_msp34xx = 1,
- .no_tda9875 = 1,
.no_tda7432 = 1,
},
/* ---- card 0x95---------------------------------- */
@@ -2874,7 +2837,6 @@ struct tvcard bttv_tvcards[] = {
.pll = PLL_28,
.no_msp34xx = 1,
.no_tda7432 = 1,
- .no_tda9875 = 1,
.muxsel_hook = gv800s_muxsel,
},
[BTTV_BOARD_GEOVISION_GV800S_SL] = {
@@ -2899,7 +2861,6 @@ struct tvcard bttv_tvcards[] = {
.pll = PLL_28,
.no_msp34xx = 1,
.no_tda7432 = 1,
- .no_tda9875 = 1,
.muxsel_hook = gv800s_muxsel,
},
[BTTV_BOARD_PV183] = {
diff --git a/drivers/media/video/bt8xx/bttv.h b/drivers/media/video/bt8xx/bttv.h
index fd62bf1..c633359 100644
--- a/drivers/media/video/bt8xx/bttv.h
+++ b/drivers/media/video/bt8xx/bttv.h
@@ -234,7 +234,6 @@ struct tvcard {
/* i2c audio flags */
unsigned int no_msp34xx:1;
- unsigned int no_tda9875:1;
unsigned int no_tda7432:1;
unsigned int needs_tvaudio:1;
unsigned int msp34xx_alt:1;
diff --git a/drivers/media/video/cafe_ccic.c b/drivers/media/video/cafe_ccic.c
index 789087c..55ffd60 100644
--- a/drivers/media/video/cafe_ccic.c
+++ b/drivers/media/video/cafe_ccic.c
@@ -2001,6 +2001,11 @@ static int cafe_pci_probe(struct pci_dev *pdev,
.min_width = 320,
.min_height = 240,
};
+ struct i2c_board_info ov7670_info = {
+ .type = "ov7670",
+ .addr = 0x42,
+ .platform_data = &sensor_cfg,
+ };
/*
* Start putting together one of our big camera structures.
@@ -2062,9 +2067,9 @@ static int cafe_pci_probe(struct pci_dev *pdev,
if (dmi_check_system(olpc_xo1_dmi))
sensor_cfg.clock_speed = 45;
- cam->sensor_addr = 0x42;
- cam->sensor = v4l2_i2c_new_subdev_cfg(&cam->v4l2_dev, &cam->i2c_adapter,
- "ov7670", 0, &sensor_cfg, cam->sensor_addr, NULL);
+ cam->sensor_addr = ov7670_info.addr;
+ cam->sensor = v4l2_i2c_new_subdev_board(&cam->v4l2_dev, &cam->i2c_adapter,
+ &ov7670_info, NULL);
if (cam->sensor == NULL) {
ret = -ENODEV;
goto out_smbus;
@@ -2184,9 +2189,7 @@ static int cafe_pci_resume(struct pci_dev *pdev)
struct cafe_camera *cam = to_cam(v4l2_dev);
int ret = 0;
- ret = pci_restore_state(pdev);
- if (ret)
- return ret;
+ pci_restore_state(pdev);
ret = pci_enable_device(pdev);
if (ret) {
diff --git a/drivers/media/video/cpia2/cpia2.h b/drivers/media/video/cpia2/cpia2.h
index 916c13d..6d6d184 100644
--- a/drivers/media/video/cpia2/cpia2.h
+++ b/drivers/media/video/cpia2/cpia2.h
@@ -378,7 +378,7 @@ struct cpia2_fh {
struct camera_data {
/* locks */
- struct mutex busy_lock; /* guard against SMP multithreading */
+ struct mutex v4l2_lock; /* serialize file operations */
struct v4l2_prio_state prio;
/* camera status */
diff --git a/drivers/media/video/cpia2/cpia2_core.c b/drivers/media/video/cpia2/cpia2_core.c
index 9606bc0..aaffca8 100644
--- a/drivers/media/video/cpia2/cpia2_core.c
+++ b/drivers/media/video/cpia2/cpia2_core.c
@@ -2247,7 +2247,7 @@ struct camera_data *cpia2_init_camera_struct(void)
cam->present = 1;
- mutex_init(&cam->busy_lock);
+ mutex_init(&cam->v4l2_lock);
init_waitqueue_head(&cam->wq_stream);
return cam;
@@ -2365,9 +2365,9 @@ long cpia2_read(struct camera_data *cam,
char __user *buf, unsigned long count, int noblock)
{
struct framebuf *frame;
- if (!count) {
+
+ if (!count)
return 0;
- }
if (!buf) {
ERR("%s: buffer NULL\n",__func__);
@@ -2379,17 +2379,12 @@ long cpia2_read(struct camera_data *cam,
return -EINVAL;
}
- /* make this _really_ smp and multithread-safe */
- if (mutex_lock_interruptible(&cam->busy_lock))
- return -ERESTARTSYS;
-
if (!cam->present) {
LOG("%s: camera removed\n",__func__);
- mutex_unlock(&cam->busy_lock);
return 0; /* EOF */
}
- if(!cam->streaming) {
+ if (!cam->streaming) {
/* Start streaming */
cpia2_usb_stream_start(cam,
cam->params.camera_state.stream_mode);
@@ -2398,42 +2393,31 @@ long cpia2_read(struct camera_data *cam,
/* Copy cam->curbuff in case it changes while we're processing */
frame = cam->curbuff;
if (noblock && frame->status != FRAME_READY) {
- mutex_unlock(&cam->busy_lock);
return -EAGAIN;
}
- if(frame->status != FRAME_READY) {
- mutex_unlock(&cam->busy_lock);
+ if (frame->status != FRAME_READY) {
+ mutex_unlock(&cam->v4l2_lock);
wait_event_interruptible(cam->wq_stream,
!cam->present ||
(frame = cam->curbuff)->status == FRAME_READY);
+ mutex_lock(&cam->v4l2_lock);
if (signal_pending(current))
return -ERESTARTSYS;
- /* make this _really_ smp and multithread-safe */
- if (mutex_lock_interruptible(&cam->busy_lock)) {
- return -ERESTARTSYS;
- }
- if(!cam->present) {
- mutex_unlock(&cam->busy_lock);
+ if (!cam->present)
return 0;
- }
}
/* copy data to user space */
- if (frame->length > count) {
- mutex_unlock(&cam->busy_lock);
+ if (frame->length > count)
return -EFAULT;
- }
- if (copy_to_user(buf, frame->data, frame->length)) {
- mutex_unlock(&cam->busy_lock);
+ if (copy_to_user(buf, frame->data, frame->length))
return -EFAULT;
- }
count = frame->length;
frame->status = FRAME_EMPTY;
- mutex_unlock(&cam->busy_lock);
return count;
}
@@ -2447,17 +2431,13 @@ unsigned int cpia2_poll(struct camera_data *cam, struct file *filp,
{
unsigned int status=0;
- if(!cam) {
+ if (!cam) {
ERR("%s: Internal error, camera_data not found!\n",__func__);
return POLLERR;
}
- mutex_lock(&cam->busy_lock);
-
- if(!cam->present) {
- mutex_unlock(&cam->busy_lock);
+ if (!cam->present)
return POLLHUP;
- }
if(!cam->streaming) {
/* Start streaming */
@@ -2465,16 +2445,13 @@ unsigned int cpia2_poll(struct camera_data *cam, struct file *filp,
cam->params.camera_state.stream_mode);
}
- mutex_unlock(&cam->busy_lock);
poll_wait(filp, &cam->wq_stream, wait);
- mutex_lock(&cam->busy_lock);
if(!cam->present)
status = POLLHUP;
else if(cam->curbuff->status == FRAME_READY)
status = POLLIN | POLLRDNORM;
- mutex_unlock(&cam->busy_lock);
return status;
}
@@ -2496,29 +2473,19 @@ int cpia2_remap_buffer(struct camera_data *cam, struct vm_area_struct *vma)
DBG("mmap offset:%ld size:%ld\n", start_offset, size);
- /* make this _really_ smp-safe */
- if (mutex_lock_interruptible(&cam->busy_lock))
- return -ERESTARTSYS;
-
- if (!cam->present) {
- mutex_unlock(&cam->busy_lock);
+ if (!cam->present)
return -ENODEV;
- }
if (size > cam->frame_size*cam->num_frames ||
(start_offset % cam->frame_size) != 0 ||
- (start_offset+size > cam->frame_size*cam->num_frames)) {
- mutex_unlock(&cam->busy_lock);
+ (start_offset+size > cam->frame_size*cam->num_frames))
return -EINVAL;
- }
pos = ((unsigned long) (cam->frame_buffer)) + start_offset;
while (size > 0) {
page = kvirt_to_pa(pos);
- if (remap_pfn_range(vma, start, page >> PAGE_SHIFT, PAGE_SIZE, PAGE_SHARED)) {
- mutex_unlock(&cam->busy_lock);
+ if (remap_pfn_range(vma, start, page >> PAGE_SHIFT, PAGE_SIZE, PAGE_SHARED))
return -EAGAIN;
- }
start += PAGE_SIZE;
pos += PAGE_SIZE;
if (size > PAGE_SIZE)
@@ -2528,7 +2495,5 @@ int cpia2_remap_buffer(struct camera_data *cam, struct vm_area_struct *vma)
}
cam->mmapped = true;
- mutex_unlock(&cam->busy_lock);
return 0;
}
-
diff --git a/drivers/media/video/cpia2/cpia2_v4l.c b/drivers/media/video/cpia2/cpia2_v4l.c
index 7edf80b..9bad398 100644
--- a/drivers/media/video/cpia2/cpia2_v4l.c
+++ b/drivers/media/video/cpia2/cpia2_v4l.c
@@ -238,59 +238,40 @@ static struct v4l2_queryctrl controls[] = {
static int cpia2_open(struct file *file)
{
struct camera_data *cam = video_drvdata(file);
- int retval = 0;
+ struct cpia2_fh *fh;
if (!cam) {
ERR("Internal error, camera_data not found!\n");
return -ENODEV;
}
- if(mutex_lock_interruptible(&cam->busy_lock))
- return -ERESTARTSYS;
-
- if(!cam->present) {
- retval = -ENODEV;
- goto err_return;
- }
+ if (!cam->present)
+ return -ENODEV;
- if (cam->open_count > 0) {
- goto skip_init;
- }
+ if (cam->open_count == 0) {
+ if (cpia2_allocate_buffers(cam))
+ return -ENOMEM;
- if (cpia2_allocate_buffers(cam)) {
- retval = -ENOMEM;
- goto err_return;
- }
+ /* reset the camera */
+ if (cpia2_reset_camera(cam) < 0)
+ return -EIO;
- /* reset the camera */
- if (cpia2_reset_camera(cam) < 0) {
- retval = -EIO;
- goto err_return;
+ cam->APP_len = 0;
+ cam->COM_len = 0;
}
- cam->APP_len = 0;
- cam->COM_len = 0;
-
-skip_init:
- {
- struct cpia2_fh *fh = kmalloc(sizeof(*fh),GFP_KERNEL);
- if(!fh) {
- retval = -ENOMEM;
- goto err_return;
- }
- file->private_data = fh;
- fh->prio = V4L2_PRIORITY_UNSET;
- v4l2_prio_open(&cam->prio, &fh->prio);
- fh->mmapped = 0;
- }
+ fh = kmalloc(sizeof(*fh), GFP_KERNEL);
+ if (!fh)
+ return -ENOMEM;
+ file->private_data = fh;
+ fh->prio = V4L2_PRIORITY_UNSET;
+ v4l2_prio_open(&cam->prio, &fh->prio);
+ fh->mmapped = 0;
++cam->open_count;
cpia2_dbg_dump_registers(cam);
-
-err_return:
- mutex_unlock(&cam->busy_lock);
- return retval;
+ return 0;
}
/******************************************************************************
@@ -304,15 +285,11 @@ static int cpia2_close(struct file *file)
struct camera_data *cam = video_get_drvdata(dev);
struct cpia2_fh *fh = file->private_data;
- mutex_lock(&cam->busy_lock);
-
if (cam->present &&
- (cam->open_count == 1
- || fh->prio == V4L2_PRIORITY_RECORD
- )) {
+ (cam->open_count == 1 || fh->prio == V4L2_PRIORITY_RECORD)) {
cpia2_usb_stream_stop(cam);
- if(cam->open_count == 1) {
+ if (cam->open_count == 1) {
/* save camera state for later open */
cpia2_save_camera_state(cam);
@@ -321,26 +298,21 @@ static int cpia2_close(struct file *file)
}
}
- {
- if(fh->mmapped)
- cam->mmapped = 0;
- v4l2_prio_close(&cam->prio, fh->prio);
- file->private_data = NULL;
- kfree(fh);
- }
+ if (fh->mmapped)
+ cam->mmapped = 0;
+ v4l2_prio_close(&cam->prio, fh->prio);
+ file->private_data = NULL;
+ kfree(fh);
if (--cam->open_count == 0) {
cpia2_free_buffers(cam);
if (!cam->present) {
video_unregister_device(dev);
- mutex_unlock(&cam->busy_lock);
kfree(cam);
return 0;
}
}
- mutex_unlock(&cam->busy_lock);
-
return 0;
}
@@ -405,11 +377,11 @@ static int sync(struct camera_data *cam, int frame_nr)
return 0;
}
- mutex_unlock(&cam->busy_lock);
+ mutex_unlock(&cam->v4l2_lock);
wait_event_interruptible(cam->wq_stream,
!cam->streaming ||
frame->status == FRAME_READY);
- mutex_lock(&cam->busy_lock);
+ mutex_lock(&cam->v4l2_lock);
if (signal_pending(current))
return -ERESTARTSYS;
if(!cam->present)
@@ -1293,11 +1265,11 @@ static int ioctl_dqbuf(void *arg,struct camera_data *cam, struct file *file)
if(frame < 0) {
/* Wait for a frame to become available */
struct framebuf *cb=cam->curbuff;
- mutex_unlock(&cam->busy_lock);
+ mutex_unlock(&cam->v4l2_lock);
wait_event_interruptible(cam->wq_stream,
!cam->present ||
(cb=cam->curbuff)->status == FRAME_READY);
- mutex_lock(&cam->busy_lock);
+ mutex_lock(&cam->v4l2_lock);
if (signal_pending(current))
return -ERESTARTSYS;
if(!cam->present)
@@ -1337,14 +1309,8 @@ static long cpia2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
if (!cam)
return -ENOTTY;
- /* make this _really_ smp-safe */
- if (mutex_lock_interruptible(&cam->busy_lock))
- return -ERESTARTSYS;
-
- if (!cam->present) {
- mutex_unlock(&cam->busy_lock);
+ if (!cam->present)
return -ENODEV;
- }
/* Priority check */
switch (cmd) {
@@ -1352,10 +1318,8 @@ static long cpia2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
{
struct cpia2_fh *fh = file->private_data;
retval = v4l2_prio_check(&cam->prio, fh->prio);
- if(retval) {
- mutex_unlock(&cam->busy_lock);
+ if (retval)
return retval;
- }
break;
}
default:
@@ -1529,7 +1493,6 @@ static long cpia2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
break;
}
- mutex_unlock(&cam->busy_lock);
return retval;
}
@@ -1596,7 +1559,7 @@ static const struct v4l2_file_operations cpia2_fops = {
.release = cpia2_close,
.read = cpia2_v4l_read,
.poll = cpia2_v4l_poll,
- .ioctl = cpia2_ioctl,
+ .unlocked_ioctl = cpia2_ioctl,
.mmap = cpia2_mmap,
};
@@ -1620,6 +1583,7 @@ int cpia2_register_camera(struct camera_data *cam)
memcpy(cam->vdev, &cpia2_template, sizeof(cpia2_template));
video_set_drvdata(cam->vdev, cam);
+ cam->vdev->lock = &cam->v4l2_lock;
reset_camera_struct_v4l(cam);
diff --git a/drivers/media/video/cx18/cx18-driver.c b/drivers/media/video/cx18/cx18-driver.c
index 133ec2b..944af8a 100644
--- a/drivers/media/video/cx18/cx18-driver.c
+++ b/drivers/media/video/cx18/cx18-driver.c
@@ -664,7 +664,7 @@ static int __devinit cx18_create_in_workq(struct cx18 *cx)
{
snprintf(cx->in_workq_name, sizeof(cx->in_workq_name), "%s-in",
cx->v4l2_dev.name);
- cx->in_work_queue = create_singlethread_workqueue(cx->in_workq_name);
+ cx->in_work_queue = alloc_ordered_workqueue(cx->in_workq_name, 0);
if (cx->in_work_queue == NULL) {
CX18_ERR("Unable to create incoming mailbox handler thread\n");
return -ENOMEM;
@@ -672,18 +672,6 @@ static int __devinit cx18_create_in_workq(struct cx18 *cx)
return 0;
}
-static int __devinit cx18_create_out_workq(struct cx18 *cx)
-{
- snprintf(cx->out_workq_name, sizeof(cx->out_workq_name), "%s-out",
- cx->v4l2_dev.name);
- cx->out_work_queue = create_workqueue(cx->out_workq_name);
- if (cx->out_work_queue == NULL) {
- CX18_ERR("Unable to create outgoing mailbox handler threads\n");
- return -ENOMEM;
- }
- return 0;
-}
-
static void __devinit cx18_init_in_work_orders(struct cx18 *cx)
{
int i;
@@ -710,15 +698,9 @@ static int __devinit cx18_init_struct1(struct cx18 *cx)
mutex_init(&cx->epu2apu_mb_lock);
mutex_init(&cx->epu2cpu_mb_lock);
- ret = cx18_create_out_workq(cx);
- if (ret)
- return ret;
-
ret = cx18_create_in_workq(cx);
- if (ret) {
- destroy_workqueue(cx->out_work_queue);
+ if (ret)
return ret;
- }
cx18_init_in_work_orders(cx);
@@ -1107,7 +1089,6 @@ free_mem:
release_mem_region(cx->base_addr, CX18_MEM_SIZE);
free_workqueues:
destroy_workqueue(cx->in_work_queue);
- destroy_workqueue(cx->out_work_queue);
err:
if (retval == 0)
retval = -ENODEV;
@@ -1259,7 +1240,6 @@ static void cx18_remove(struct pci_dev *pci_dev)
cx18_halt_firmware(cx);
destroy_workqueue(cx->in_work_queue);
- destroy_workqueue(cx->out_work_queue);
cx18_streams_cleanup(cx, 1);
diff --git a/drivers/media/video/cx18/cx18-driver.h b/drivers/media/video/cx18/cx18-driver.h
index f6f3e50..306caac 100644
--- a/drivers/media/video/cx18/cx18-driver.h
+++ b/drivers/media/video/cx18/cx18-driver.h
@@ -617,9 +617,6 @@ struct cx18 {
struct cx18_in_work_order in_work_order[CX18_MAX_IN_WORK_ORDERS];
char epu_debug_str[256]; /* CX18_EPU_DEBUG is rare: use shared space */
- struct workqueue_struct *out_work_queue;
- char out_workq_name[12]; /* "cx18-NN-out" */
-
/* i2c */
struct i2c_adapter i2c_adap[2];
struct i2c_algo_bit_data i2c_algo[2];
diff --git a/drivers/media/video/cx18/cx18-streams.h b/drivers/media/video/cx18/cx18-streams.h
index 51765eb..713b0e6 100644
--- a/drivers/media/video/cx18/cx18-streams.h
+++ b/drivers/media/video/cx18/cx18-streams.h
@@ -42,8 +42,7 @@ static inline bool cx18_stream_enabled(struct cx18_stream *s)
/* Related to submission of mdls to firmware */
static inline void cx18_stream_load_fw_queue(struct cx18_stream *s)
{
- struct cx18 *cx = s->cx;
- queue_work(cx->out_work_queue, &s->out_work_order);
+ schedule_work(&s->out_work_order);
}
static inline void cx18_stream_put_mdl_fw(struct cx18_stream *s,
diff --git a/drivers/media/video/cx231xx/cx231xx-dvb.c b/drivers/media/video/cx231xx/cx231xx-dvb.c
index fe59a1c..363aa60 100644
--- a/drivers/media/video/cx231xx/cx231xx-dvb.c
+++ b/drivers/media/video/cx231xx/cx231xx-dvb.c
@@ -28,7 +28,6 @@
#include <media/videobuf-vmalloc.h>
#include "xc5000.h"
-#include "dvb_dummy_fe.h"
#include "s5h1432.h"
#include "tda18271.h"
#include "s5h1411.h"
@@ -619,7 +618,7 @@ static int dvb_init(struct cx231xx *dev)
if (dev->dvb->frontend == NULL) {
printk(DRIVER_NAME
- ": Failed to attach dummy front end\n");
+ ": Failed to attach s5h1411 front end\n");
result = -EINVAL;
goto out_free;
}
@@ -665,7 +664,7 @@ static int dvb_init(struct cx231xx *dev)
if (dev->dvb->frontend == NULL) {
printk(DRIVER_NAME
- ": Failed to attach dummy front end\n");
+ ": Failed to attach s5h1411 front end\n");
result = -EINVAL;
goto out_free;
}
diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c
index f164618..6fc09dd 100644
--- a/drivers/media/video/cx25840/cx25840-core.c
+++ b/drivers/media/video/cx25840/cx25840-core.c
@@ -1682,20 +1682,6 @@ static int cx25840_log_status(struct v4l2_subdev *sd)
return 0;
}
-static int cx25840_s_config(struct v4l2_subdev *sd, int irq, void *platform_data)
-{
- struct cx25840_state *state = to_state(sd);
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
- if (platform_data) {
- struct cx25840_platform_data *pdata = platform_data;
-
- state->pvr150_workaround = pdata->pvr150_workaround;
- set_input(client, state->vid_input, state->aud_input);
- }
- return 0;
-}
-
static int cx23885_irq_handler(struct v4l2_subdev *sd, u32 status,
bool *handled)
{
@@ -1787,7 +1773,6 @@ static const struct v4l2_ctrl_ops cx25840_ctrl_ops = {
static const struct v4l2_subdev_core_ops cx25840_core_ops = {
.log_status = cx25840_log_status,
- .s_config = cx25840_s_config,
.g_chip_ident = cx25840_g_chip_ident,
.g_ctrl = v4l2_subdev_g_ctrl,
.s_ctrl = v4l2_subdev_s_ctrl,
@@ -1974,7 +1959,6 @@ static int cx25840_probe(struct i2c_client *client,
state->vid_input = CX25840_COMPOSITE7;
state->aud_input = CX25840_AUDIO8;
state->audclk_freq = 48000;
- state->pvr150_workaround = 0;
state->audmode = V4L2_TUNER_MODE_LANG1;
state->vbi_line_offset = 8;
state->id = id;
@@ -2034,6 +2018,12 @@ static int cx25840_probe(struct i2c_client *client,
v4l2_ctrl_cluster(2, &state->volume);
v4l2_ctrl_handler_setup(&state->hdl);
+ if (client->dev.platform_data) {
+ struct cx25840_platform_data *pdata = client->dev.platform_data;
+
+ state->pvr150_workaround = pdata->pvr150_workaround;
+ }
+
cx25840_ir_probe(sd);
return 0;
}
diff --git a/drivers/media/video/davinci/vpif.c b/drivers/media/video/davinci/vpif.c
index 1f532e3..9f3bfc1 100644
--- a/drivers/media/video/davinci/vpif.c
+++ b/drivers/media/video/davinci/vpif.c
@@ -41,6 +41,183 @@ spinlock_t vpif_lock;
void __iomem *vpif_base;
+/**
+ * ch_params: video standard configuration parameters for vpif
+ * The table must include all presets from supported subdevices.
+ */
+const struct vpif_channel_config_params ch_params[] = {
+ /* HDTV formats */
+ {
+ .name = "480p59_94",
+ .width = 720,
+ .height = 480,
+ .frm_fmt = 1,
+ .ycmux_mode = 0,
+ .eav2sav = 138-8,
+ .sav2eav = 720,
+ .l1 = 1,
+ .l3 = 43,
+ .l5 = 523,
+ .vsize = 525,
+ .capture_format = 0,
+ .vbi_supported = 0,
+ .hd_sd = 1,
+ .dv_preset = V4L2_DV_480P59_94,
+ },
+ {
+ .name = "576p50",
+ .width = 720,
+ .height = 576,
+ .frm_fmt = 1,
+ .ycmux_mode = 0,
+ .eav2sav = 144-8,
+ .sav2eav = 720,
+ .l1 = 1,
+ .l3 = 45,
+ .l5 = 621,
+ .vsize = 625,
+ .capture_format = 0,
+ .vbi_supported = 0,
+ .hd_sd = 1,
+ .dv_preset = V4L2_DV_576P50,
+ },
+ {
+ .name = "720p50",
+ .width = 1280,
+ .height = 720,
+ .frm_fmt = 1,
+ .ycmux_mode = 0,
+ .eav2sav = 700-8,
+ .sav2eav = 1280,
+ .l1 = 1,
+ .l3 = 26,
+ .l5 = 746,
+ .vsize = 750,
+ .capture_format = 0,
+ .vbi_supported = 0,
+ .hd_sd = 1,
+ .dv_preset = V4L2_DV_720P50,
+ },
+ {
+ .name = "720p60",
+ .width = 1280,
+ .height = 720,
+ .frm_fmt = 1,
+ .ycmux_mode = 0,
+ .eav2sav = 370 - 8,
+ .sav2eav = 1280,
+ .l1 = 1,
+ .l3 = 26,
+ .l5 = 746,
+ .vsize = 750,
+ .capture_format = 0,
+ .vbi_supported = 0,
+ .hd_sd = 1,
+ .dv_preset = V4L2_DV_720P60,
+ },
+ {
+ .name = "1080I50",
+ .width = 1920,
+ .height = 1080,
+ .frm_fmt = 0,
+ .ycmux_mode = 0,
+ .eav2sav = 720 - 8,
+ .sav2eav = 1920,
+ .l1 = 1,
+ .l3 = 21,
+ .l5 = 561,
+ .l7 = 563,
+ .l9 = 584,
+ .l11 = 1124,
+ .vsize = 1125,
+ .capture_format = 0,
+ .vbi_supported = 0,
+ .hd_sd = 1,
+ .dv_preset = V4L2_DV_1080I50,
+ },
+ {
+ .name = "1080I60",
+ .width = 1920,
+ .height = 1080,
+ .frm_fmt = 0,
+ .ycmux_mode = 0,
+ .eav2sav = 280 - 8,
+ .sav2eav = 1920,
+ .l1 = 1,
+ .l3 = 21,
+ .l5 = 561,
+ .l7 = 563,
+ .l9 = 584,
+ .l11 = 1124,
+ .vsize = 1125,
+ .capture_format = 0,
+ .vbi_supported = 0,
+ .hd_sd = 1,
+ .dv_preset = V4L2_DV_1080I60,
+ },
+ {
+ .name = "1080p60",
+ .width = 1920,
+ .height = 1080,
+ .frm_fmt = 1,
+ .ycmux_mode = 0,
+ .eav2sav = 280 - 8,
+ .sav2eav = 1920,
+ .l1 = 1,
+ .l3 = 42,
+ .l5 = 1122,
+ .vsize = 1125,
+ .capture_format = 0,
+ .vbi_supported = 0,
+ .hd_sd = 1,
+ .dv_preset = V4L2_DV_1080P60,
+ },
+
+ /* SDTV formats */
+ {
+ .name = "NTSC_M",
+ .width = 720,
+ .height = 480,
+ .frm_fmt = 0,
+ .ycmux_mode = 1,
+ .eav2sav = 268,
+ .sav2eav = 1440,
+ .l1 = 1,
+ .l3 = 23,
+ .l5 = 263,
+ .l7 = 266,
+ .l9 = 286,
+ .l11 = 525,
+ .vsize = 525,
+ .capture_format = 0,
+ .vbi_supported = 1,
+ .hd_sd = 0,
+ .stdid = V4L2_STD_525_60,
+ },
+ {
+ .name = "PAL_BDGHIK",
+ .width = 720,
+ .height = 576,
+ .frm_fmt = 0,
+ .ycmux_mode = 1,
+ .eav2sav = 280,
+ .sav2eav = 1440,
+ .l1 = 1,
+ .l3 = 23,
+ .l5 = 311,
+ .l7 = 313,
+ .l9 = 336,
+ .l11 = 624,
+ .vsize = 625,
+ .capture_format = 0,
+ .vbi_supported = 1,
+ .hd_sd = 0,
+ .stdid = V4L2_STD_625_50,
+ },
+};
+
+const unsigned int vpif_ch_params_count = ARRAY_SIZE(ch_params);
+
static inline void vpif_wr_bit(u32 reg, u32 bit, u32 val)
{
if (val)
diff --git a/drivers/media/video/davinci/vpif.h b/drivers/media/video/davinci/vpif.h
index ebd5c43..10550bd 100644
--- a/drivers/media/video/davinci/vpif.h
+++ b/drivers/media/video/davinci/vpif.h
@@ -577,12 +577,10 @@ struct vpif_channel_config_params {
char name[VPIF_MAX_NAME]; /* Name of the mode */
u16 width; /* Indicates width of the image */
u16 height; /* Indicates height of the image */
- u8 fps;
- u8 frm_fmt; /* Indicates whether this is interlaced
- * or progressive format */
- u8 ycmux_mode; /* Indicates whether this mode requires
- * single or two channels */
- u16 eav2sav; /* length of sav 2 eav */
+ u8 frm_fmt; /* Interlaced (0) or progressive (1) */
+ u8 ycmux_mode; /* This mode requires one (0) or two (1)
+ channels */
+ u16 eav2sav; /* length of eav 2 sav */
u16 sav2eav; /* length of sav 2 eav */
u16 l1, l3, l5, l7, l9, l11; /* Other parameter configurations */
u16 vsize; /* Vertical size of the image */
@@ -590,10 +588,14 @@ struct vpif_channel_config_params {
* is in BT or in CCD/CMOS */
u8 vbi_supported; /* Indicates whether this mode
* supports capturing vbi or not */
- u8 hd_sd;
- v4l2_std_id stdid;
+ u8 hd_sd; /* HDTV (1) or SDTV (0) format */
+ v4l2_std_id stdid; /* SDTV format */
+ u32 dv_preset; /* HDTV format */
};
+extern const unsigned int vpif_ch_params_count;
+extern const struct vpif_channel_config_params ch_params[];
+
struct vpif_video_params;
struct vpif_params;
struct vpif_vbi_params;
diff --git a/drivers/media/video/davinci/vpif_capture.c b/drivers/media/video/davinci/vpif_capture.c
index 193abab..d93ad74 100644
--- a/drivers/media/video/davinci/vpif_capture.c
+++ b/drivers/media/video/davinci/vpif_capture.c
@@ -37,6 +37,7 @@
#include <linux/slab.h>
#include <media/v4l2-device.h>
#include <media/v4l2-ioctl.h>
+#include <media/v4l2-chip-ident.h>
#include "vpif_capture.h"
#include "vpif.h"
@@ -81,20 +82,6 @@ static struct vpif_device vpif_obj = { {NULL} };
static struct device *vpif_dev;
/**
- * ch_params: video standard configuration parameters for vpif
- */
-static const struct vpif_channel_config_params ch_params[] = {
- {
- "NTSC_M", 720, 480, 30, 0, 1, 268, 1440, 1, 23, 263, 266,
- 286, 525, 525, 0, 1, 0, V4L2_STD_525_60,
- },
- {
- "PAL_BDGHIK", 720, 576, 25, 0, 1, 280, 1440, 1, 23, 311, 313,
- 336, 624, 625, 0, 1, 0, V4L2_STD_625_50,
- },
-};
-
-/**
* vpif_uservirt_to_phys : translate user/virtual address to phy address
* @virtp: user/virtual address
*
@@ -342,7 +329,7 @@ static void vpif_schedule_next_buffer(struct common_obj *common)
* @dev_id: dev_id ptr
*
* It changes status of the captured buffer, takes next buffer from the queue
- * and sets its address in VPIF registers
+ * and sets its address in VPIF registers
*/
static irqreturn_t vpif_channel_isr(int irq, void *dev_id)
{
@@ -435,24 +422,31 @@ static int vpif_update_std_info(struct channel_obj *ch)
struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
struct vpif_params *vpifparams = &ch->vpifparams;
const struct vpif_channel_config_params *config;
- struct vpif_channel_config_params *std_info;
+ struct vpif_channel_config_params *std_info = &vpifparams->std_info;
struct video_obj *vid_ch = &ch->video;
int index;
vpif_dbg(2, debug, "vpif_update_std_info\n");
- std_info = &vpifparams->std_info;
-
- for (index = 0; index < ARRAY_SIZE(ch_params); index++) {
+ for (index = 0; index < vpif_ch_params_count; index++) {
config = &ch_params[index];
- if (config->stdid & vid_ch->stdid) {
- memcpy(std_info, config, sizeof(*config));
- break;
+ if (config->hd_sd == 0) {
+ vpif_dbg(2, debug, "SD format\n");
+ if (config->stdid & vid_ch->stdid) {
+ memcpy(std_info, config, sizeof(*config));
+ break;
+ }
+ } else {
+ vpif_dbg(2, debug, "HD format\n");
+ if (config->dv_preset == vid_ch->dv_preset) {
+ memcpy(std_info, config, sizeof(*config));
+ break;
+ }
}
}
/* standard not found */
- if (index == ARRAY_SIZE(ch_params))
+ if (index == vpif_ch_params_count)
return -EINVAL;
common->fmt.fmt.pix.width = std_info->width;
@@ -462,6 +456,7 @@ static int vpif_update_std_info(struct channel_obj *ch)
common->fmt.fmt.pix.bytesperline = std_info->width;
vpifparams->video_params.hpitch = std_info->width;
vpifparams->video_params.storage_mode = std_info->frm_fmt;
+
return 0;
}
@@ -757,7 +752,7 @@ static int vpif_open(struct file *filep)
struct video_obj *vid_ch;
struct channel_obj *ch;
struct vpif_fh *fh;
- int i, ret = 0;
+ int i;
vpif_dbg(2, debug, "vpif_open\n");
@@ -766,9 +761,6 @@ static int vpif_open(struct file *filep)
vid_ch = &ch->video;
common = &ch->common[VPIF_VIDEO_INDEX];
- if (mutex_lock_interruptible(&common->lock))
- return -ERESTARTSYS;
-
if (NULL == ch->curr_subdev_info) {
/**
* search through the sub device to see a registered
@@ -785,8 +777,7 @@ static int vpif_open(struct file *filep)
}
if (i == config->subdev_count) {
vpif_err("No sub device registered\n");
- ret = -ENOENT;
- goto exit;
+ return -ENOENT;
}
}
@@ -794,8 +785,7 @@ static int vpif_open(struct file *filep)
fh = kzalloc(sizeof(struct vpif_fh), GFP_KERNEL);
if (NULL == fh) {
vpif_err("unable to allocate memory for file handle object\n");
- ret = -ENOMEM;
- goto exit;
+ return -ENOMEM;
}
/* store pointer to fh in private_data member of filep */
@@ -815,9 +805,7 @@ static int vpif_open(struct file *filep)
/* Initialize priority of this instance to default priority */
fh->prio = V4L2_PRIORITY_UNSET;
v4l2_prio_open(&ch->prio, &fh->prio);
-exit:
- mutex_unlock(&common->lock);
- return ret;
+ return 0;
}
/**
@@ -837,9 +825,6 @@ static int vpif_release(struct file *filep)
common = &ch->common[VPIF_VIDEO_INDEX];
- if (mutex_lock_interruptible(&common->lock))
- return -ERESTARTSYS;
-
/* if this instance is doing IO */
if (fh->io_allowed[VPIF_VIDEO_INDEX]) {
/* Reset io_usrs member of channel object */
@@ -863,9 +848,6 @@ static int vpif_release(struct file *filep)
/* Decrement channel usrs counter */
ch->usrs--;
- /* unlock mutex on channel object */
- mutex_unlock(&common->lock);
-
/* Close the priority */
v4l2_prio_close(&ch->prio, fh->prio);
@@ -890,7 +872,6 @@ static int vpif_reqbufs(struct file *file, void *priv,
struct channel_obj *ch = fh->channel;
struct common_obj *common;
u8 index = 0;
- int ret = 0;
vpif_dbg(2, debug, "vpif_reqbufs\n");
@@ -913,13 +894,8 @@ static int vpif_reqbufs(struct file *file, void *priv,
common = &ch->common[index];
- if (mutex_lock_interruptible(&common->lock))
- return -ERESTARTSYS;
-
- if (0 != common->io_usrs) {
- ret = -EBUSY;
- goto reqbuf_exit;
- }
+ if (0 != common->io_usrs)
+ return -EBUSY;
/* Initialize videobuf queue as per the buffer type */
videobuf_queue_dma_contig_init(&common->buffer_queue,
@@ -928,7 +904,7 @@ static int vpif_reqbufs(struct file *file, void *priv,
reqbuf->type,
common->fmt.fmt.pix.field,
sizeof(struct videobuf_buffer), fh,
- NULL);
+ &common->lock);
/* Set io allowed member of file handle to TRUE */
fh->io_allowed[index] = 1;
@@ -939,11 +915,7 @@ static int vpif_reqbufs(struct file *file, void *priv,
INIT_LIST_HEAD(&common->dma_queue);
/* Allocate buffers */
- ret = videobuf_reqbufs(&common->buffer_queue, reqbuf);
-
-reqbuf_exit:
- mutex_unlock(&common->lock);
- return ret;
+ return videobuf_reqbufs(&common->buffer_queue, reqbuf);
}
/**
@@ -1157,11 +1129,6 @@ static int vpif_streamon(struct file *file, void *priv,
return ret;
}
- if (mutex_lock_interruptible(&common->lock)) {
- ret = -ERESTARTSYS;
- goto streamoff_exit;
- }
-
/* If buffer queue is empty, return error */
if (list_empty(&common->dma_queue)) {
vpif_dbg(1, debug, "buffer queue is empty\n");
@@ -1240,13 +1207,10 @@ static int vpif_streamon(struct file *file, void *priv,
enable_channel1(1);
}
channel_first_int[VPIF_VIDEO_INDEX][ch->channel_id] = 1;
- mutex_unlock(&common->lock);
return ret;
exit:
- mutex_unlock(&common->lock);
-streamoff_exit:
- ret = videobuf_streamoff(&common->buffer_queue);
+ videobuf_streamoff(&common->buffer_queue);
return ret;
}
@@ -1284,9 +1248,6 @@ static int vpif_streamoff(struct file *file, void *priv,
return -EINVAL;
}
- if (mutex_lock_interruptible(&common->lock))
- return -ERESTARTSYS;
-
/* disable channel */
if (VPIF_CHANNEL0_VIDEO == ch->channel_id) {
enable_channel0(0);
@@ -1304,8 +1265,6 @@ static int vpif_streamoff(struct file *file, void *priv,
if (ret && (ret != -ENOIOCTLCMD))
vpif_dbg(1, debug, "stream off failed in subdev\n");
- mutex_unlock(&common->lock);
-
return videobuf_streamoff(&common->buffer_queue);
}
@@ -1381,21 +1340,16 @@ static int vpif_querystd(struct file *file, void *priv, v4l2_std_id *std_id)
{
struct vpif_fh *fh = priv;
struct channel_obj *ch = fh->channel;
- struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
int ret = 0;
vpif_dbg(2, debug, "vpif_querystd\n");
- if (mutex_lock_interruptible(&common->lock))
- return -ERESTARTSYS;
-
/* Call querystd function of decoder device */
ret = v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], video,
querystd, std_id);
if (ret < 0)
vpif_dbg(1, debug, "Failed to set standard for sub devices\n");
- mutex_unlock(&common->lock);
return ret;
}
@@ -1451,16 +1405,14 @@ static int vpif_s_std(struct file *file, void *priv, v4l2_std_id *std_id)
fh->initialized = 1;
/* Call encoder subdevice function to set the standard */
- if (mutex_lock_interruptible(&common->lock))
- return -ERESTARTSYS;
-
ch->video.stdid = *std_id;
+ ch->video.dv_preset = V4L2_DV_INVALID;
+ memset(&ch->video.bt_timings, 0, sizeof(ch->video.bt_timings));
/* Get the information about the standard */
if (vpif_update_std_info(ch)) {
- ret = -EINVAL;
vpif_err("Error getting the standard info\n");
- goto s_std_exit;
+ return -EINVAL;
}
/* Configure the default format information */
@@ -1471,9 +1423,6 @@ static int vpif_s_std(struct file *file, void *priv, v4l2_std_id *std_id)
s_std, *std_id);
if (ret < 0)
vpif_dbg(1, debug, "Failed to set standard for sub devices\n");
-
-s_std_exit:
- mutex_unlock(&common->lock);
return ret;
}
@@ -1567,9 +1516,6 @@ static int vpif_s_input(struct file *file, void *priv, unsigned int index)
return -EINVAL;
}
- if (mutex_lock_interruptible(&common->lock))
- return -ERESTARTSYS;
-
/* first setup input path from sub device to vpif */
if (config->setup_input_path) {
ret = config->setup_input_path(ch->channel_id,
@@ -1578,7 +1524,7 @@ static int vpif_s_input(struct file *file, void *priv, unsigned int index)
vpif_dbg(1, debug, "couldn't setup input path for the"
" sub device %s, for input index %d\n",
subdev_info->name, index);
- goto exit;
+ return ret;
}
}
@@ -1589,7 +1535,7 @@ static int vpif_s_input(struct file *file, void *priv, unsigned int index)
input, output, 0);
if (ret < 0) {
vpif_dbg(1, debug, "Failed to set input\n");
- goto exit;
+ return ret;
}
}
vid_ch->input_idx = index;
@@ -1600,9 +1546,6 @@ static int vpif_s_input(struct file *file, void *priv, unsigned int index)
/* update tvnorms from the sub device input info */
ch->video_dev->tvnorms = chan_cfg->inputs[index].input.std;
-
-exit:
- mutex_unlock(&common->lock);
return ret;
}
@@ -1671,11 +1614,7 @@ static int vpif_g_fmt_vid_cap(struct file *file, void *priv,
return -EINVAL;
/* Fill in the information about format */
- if (mutex_lock_interruptible(&common->lock))
- return -ERESTARTSYS;
-
*fmt = common->fmt;
- mutex_unlock(&common->lock);
return 0;
}
@@ -1694,7 +1633,7 @@ static int vpif_s_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_pix_format *pixfmt;
int ret = 0;
- vpif_dbg(2, debug, "VIDIOC_S_FMT\n");
+ vpif_dbg(2, debug, "%s\n", __func__);
/* If streaming is started, return error */
if (common->started) {
@@ -1723,12 +1662,7 @@ static int vpif_s_fmt_vid_cap(struct file *file, void *priv,
if (ret)
return ret;
/* store the format in the channel object */
- if (mutex_lock_interruptible(&common->lock))
- return -ERESTARTSYS;
-
common->fmt = *fmt;
- mutex_unlock(&common->lock);
-
return 0;
}
@@ -1807,6 +1741,306 @@ static int vpif_cropcap(struct file *file, void *priv,
return 0;
}
+/**
+ * vpif_enum_dv_presets() - ENUM_DV_PRESETS handler
+ * @file: file ptr
+ * @priv: file handle
+ * @preset: input preset
+ */
+static int vpif_enum_dv_presets(struct file *file, void *priv,
+ struct v4l2_dv_enum_preset *preset)
+{
+ struct vpif_fh *fh = priv;
+ struct channel_obj *ch = fh->channel;
+
+ return v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index],
+ video, enum_dv_presets, preset);
+}
+
+/**
+ * vpif_query_dv_presets() - QUERY_DV_PRESET handler
+ * @file: file ptr
+ * @priv: file handle
+ * @preset: input preset
+ */
+static int vpif_query_dv_preset(struct file *file, void *priv,
+ struct v4l2_dv_preset *preset)
+{
+ struct vpif_fh *fh = priv;
+ struct channel_obj *ch = fh->channel;
+
+ return v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index],
+ video, query_dv_preset, preset);
+}
+/**
+ * vpif_s_dv_presets() - S_DV_PRESETS handler
+ * @file: file ptr
+ * @priv: file handle
+ * @preset: input preset
+ */
+static int vpif_s_dv_preset(struct file *file, void *priv,
+ struct v4l2_dv_preset *preset)
+{
+ struct vpif_fh *fh = priv;
+ struct channel_obj *ch = fh->channel;
+ struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+ int ret = 0;
+
+ if (common->started) {
+ vpif_dbg(1, debug, "streaming in progress\n");
+ return -EBUSY;
+ }
+
+ if ((VPIF_CHANNEL0_VIDEO == ch->channel_id) ||
+ (VPIF_CHANNEL1_VIDEO == ch->channel_id)) {
+ if (!fh->initialized) {
+ vpif_dbg(1, debug, "Channel Busy\n");
+ return -EBUSY;
+ }
+ }
+
+ ret = v4l2_prio_check(&ch->prio, fh->prio);
+ if (ret)
+ return ret;
+
+ fh->initialized = 1;
+
+ /* Call encoder subdevice function to set the standard */
+ if (mutex_lock_interruptible(&common->lock))
+ return -ERESTARTSYS;
+
+ ch->video.dv_preset = preset->preset;
+ ch->video.stdid = V4L2_STD_UNKNOWN;
+ memset(&ch->video.bt_timings, 0, sizeof(ch->video.bt_timings));
+
+ /* Get the information about the standard */
+ if (vpif_update_std_info(ch)) {
+ vpif_dbg(1, debug, "Error getting the standard info\n");
+ ret = -EINVAL;
+ } else {
+ /* Configure the default format information */
+ vpif_config_format(ch);
+
+ ret = v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index],
+ video, s_dv_preset, preset);
+ }
+
+ mutex_unlock(&common->lock);
+
+ return ret;
+}
+/**
+ * vpif_g_dv_presets() - G_DV_PRESETS handler
+ * @file: file ptr
+ * @priv: file handle
+ * @preset: input preset
+ */
+static int vpif_g_dv_preset(struct file *file, void *priv,
+ struct v4l2_dv_preset *preset)
+{
+ struct vpif_fh *fh = priv;
+ struct channel_obj *ch = fh->channel;
+
+ preset->preset = ch->video.dv_preset;
+
+ return 0;
+}
+
+/**
+ * vpif_s_dv_timings() - S_DV_TIMINGS handler
+ * @file: file ptr
+ * @priv: file handle
+ * @timings: digital video timings
+ */
+static int vpif_s_dv_timings(struct file *file, void *priv,
+ struct v4l2_dv_timings *timings)
+{
+ struct vpif_fh *fh = priv;
+ struct channel_obj *ch = fh->channel;
+ struct vpif_params *vpifparams = &ch->vpifparams;
+ struct vpif_channel_config_params *std_info = &vpifparams->std_info;
+ struct video_obj *vid_ch = &ch->video;
+ struct v4l2_bt_timings *bt = &vid_ch->bt_timings;
+ int ret;
+
+ if (timings->type != V4L2_DV_BT_656_1120) {
+ vpif_dbg(2, debug, "Timing type not defined\n");
+ return -EINVAL;
+ }
+
+ /* Configure subdevice timings, if any */
+ ret = v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index],
+ video, s_dv_timings, timings);
+ if (ret == -ENOIOCTLCMD) {
+ vpif_dbg(2, debug, "Custom DV timings not supported by "
+ "subdevice\n");
+ return -EINVAL;
+ }
+ if (ret < 0) {
+ vpif_dbg(2, debug, "Error setting custom DV timings\n");
+ return ret;
+ }
+
+ if (!(timings->bt.width && timings->bt.height &&
+ (timings->bt.hbackporch ||
+ timings->bt.hfrontporch ||
+ timings->bt.hsync) &&
+ timings->bt.vfrontporch &&
+ (timings->bt.vbackporch ||
+ timings->bt.vsync))) {
+ vpif_dbg(2, debug, "Timings for width, height, "
+ "horizontal back porch, horizontal sync, "
+ "horizontal front porch, vertical back porch, "
+ "vertical sync and vertical back porch "
+ "must be defined\n");
+ return -EINVAL;
+ }
+
+ *bt = timings->bt;
+
+ /* Configure video port timings */
+
+ std_info->eav2sav = bt->hbackporch + bt->hfrontporch +
+ bt->hsync - 8;
+ std_info->sav2eav = bt->width;
+
+ std_info->l1 = 1;
+ std_info->l3 = bt->vsync + bt->vbackporch + 1;
+
+ if (bt->interlaced) {
+ if (bt->il_vbackporch || bt->il_vfrontporch || bt->il_vsync) {
+ std_info->vsize = bt->height * 2 +
+ bt->vfrontporch + bt->vsync + bt->vbackporch +
+ bt->il_vfrontporch + bt->il_vsync +
+ bt->il_vbackporch;
+ std_info->l5 = std_info->vsize/2 -
+ (bt->vfrontporch - 1);
+ std_info->l7 = std_info->vsize/2 + 1;
+ std_info->l9 = std_info->l7 + bt->il_vsync +
+ bt->il_vbackporch + 1;
+ std_info->l11 = std_info->vsize -
+ (bt->il_vfrontporch - 1);
+ } else {
+ vpif_dbg(2, debug, "Required timing values for "
+ "interlaced BT format missing\n");
+ return -EINVAL;
+ }
+ } else {
+ std_info->vsize = bt->height + bt->vfrontporch +
+ bt->vsync + bt->vbackporch;
+ std_info->l5 = std_info->vsize - (bt->vfrontporch - 1);
+ }
+ strncpy(std_info->name, "Custom timings BT656/1120", VPIF_MAX_NAME);
+ std_info->width = bt->width;
+ std_info->height = bt->height;
+ std_info->frm_fmt = bt->interlaced ? 0 : 1;
+ std_info->ycmux_mode = 0;
+ std_info->capture_format = 0;
+ std_info->vbi_supported = 0;
+ std_info->hd_sd = 1;
+ std_info->stdid = 0;
+ std_info->dv_preset = V4L2_DV_INVALID;
+
+ vid_ch->stdid = 0;
+ vid_ch->dv_preset = V4L2_DV_INVALID;
+ return 0;
+}
+
+/**
+ * vpif_g_dv_timings() - G_DV_TIMINGS handler
+ * @file: file ptr
+ * @priv: file handle
+ * @timings: digital video timings
+ */
+static int vpif_g_dv_timings(struct file *file, void *priv,
+ struct v4l2_dv_timings *timings)
+{
+ struct vpif_fh *fh = priv;
+ struct channel_obj *ch = fh->channel;
+ struct video_obj *vid_ch = &ch->video;
+ struct v4l2_bt_timings *bt = &vid_ch->bt_timings;
+
+ timings->bt = *bt;
+
+ return 0;
+}
+
+/*
+ * vpif_g_chip_ident() - Identify the chip
+ * @file: file ptr
+ * @priv: file handle
+ * @chip: chip identity
+ *
+ * Returns zero or -EINVAL if read operations fails.
+ */
+static int vpif_g_chip_ident(struct file *file, void *priv,
+ struct v4l2_dbg_chip_ident *chip)
+{
+ chip->ident = V4L2_IDENT_NONE;
+ chip->revision = 0;
+ if (chip->match.type != V4L2_CHIP_MATCH_I2C_DRIVER &&
+ chip->match.type != V4L2_CHIP_MATCH_I2C_ADDR) {
+ vpif_dbg(2, debug, "match_type is invalid.\n");
+ return -EINVAL;
+ }
+
+ return v4l2_device_call_until_err(&vpif_obj.v4l2_dev, 0, core,
+ g_chip_ident, chip);
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+/*
+ * vpif_dbg_g_register() - Read register
+ * @file: file ptr
+ * @priv: file handle
+ * @reg: register to be read
+ *
+ * Debugging only
+ * Returns zero or -EINVAL if read operations fails.
+ */
+static int vpif_dbg_g_register(struct file *file, void *priv,
+ struct v4l2_dbg_register *reg){
+ struct vpif_fh *fh = priv;
+ struct channel_obj *ch = fh->channel;
+
+ return v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], core,
+ g_register, reg);
+}
+
+/*
+ * vpif_dbg_s_register() - Write to register
+ * @file: file ptr
+ * @priv: file handle
+ * @reg: register to be modified
+ *
+ * Debugging only
+ * Returns zero or -EINVAL if write operations fails.
+ */
+static int vpif_dbg_s_register(struct file *file, void *priv,
+ struct v4l2_dbg_register *reg){
+ struct vpif_fh *fh = priv;
+ struct channel_obj *ch = fh->channel;
+
+ return v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], core,
+ s_register, reg);
+}
+#endif
+
+/*
+ * vpif_log_status() - Status information
+ * @file: file ptr
+ * @priv: file handle
+ *
+ * Returns zero.
+ */
+static int vpif_log_status(struct file *filep, void *priv)
+{
+ /* status for sub devices */
+ v4l2_device_call_all(&vpif_obj.v4l2_dev, 0, core, log_status);
+
+ return 0;
+}
+
/* vpif capture ioctl operations */
static const struct v4l2_ioctl_ops vpif_ioctl_ops = {
.vidioc_querycap = vpif_querycap,
@@ -1829,6 +2063,18 @@ static const struct v4l2_ioctl_ops vpif_ioctl_ops = {
.vidioc_streamon = vpif_streamon,
.vidioc_streamoff = vpif_streamoff,
.vidioc_cropcap = vpif_cropcap,
+ .vidioc_enum_dv_presets = vpif_enum_dv_presets,
+ .vidioc_s_dv_preset = vpif_s_dv_preset,
+ .vidioc_g_dv_preset = vpif_g_dv_preset,
+ .vidioc_query_dv_preset = vpif_query_dv_preset,
+ .vidioc_s_dv_timings = vpif_s_dv_timings,
+ .vidioc_g_dv_timings = vpif_g_dv_timings,
+ .vidioc_g_chip_ident = vpif_g_chip_ident,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ .vidioc_g_register = vpif_dbg_g_register,
+ .vidioc_s_register = vpif_dbg_s_register,
+#endif
+ .vidioc_log_status = vpif_log_status,
};
/* vpif file operations */
@@ -1836,7 +2082,7 @@ static struct v4l2_file_operations vpif_fops = {
.owner = THIS_MODULE,
.open = vpif_open,
.release = vpif_release,
- .ioctl = video_ioctl2,
+ .unlocked_ioctl = video_ioctl2,
.mmap = vpif_mmap,
.poll = vpif_poll
};
@@ -1979,6 +2225,7 @@ static __init int vpif_probe(struct platform_device *pdev)
common = &(ch->common[VPIF_VIDEO_INDEX]);
spin_lock_init(&common->irqlock);
mutex_init(&common->lock);
+ ch->video_dev->lock = &common->lock;
/* Initialize prio member of channel object */
v4l2_prio_init(&ch->prio);
err = video_register_device(ch->video_dev,
@@ -2026,9 +2273,9 @@ static __init int vpif_probe(struct platform_device *pdev)
if (vpif_obj.sd[i])
vpif_obj.sd[i]->grp_id = 1 << i;
}
- v4l2_info(&vpif_obj.v4l2_dev, "DM646x VPIF Capture driver"
- " initialized\n");
+ v4l2_info(&vpif_obj.v4l2_dev,
+ "DM646x VPIF capture driver initialized\n");
return 0;
probe_subdev_out:
diff --git a/drivers/media/video/davinci/vpif_capture.h b/drivers/media/video/davinci/vpif_capture.h
index 4e12ec8..7a4196d 100644
--- a/drivers/media/video/davinci/vpif_capture.h
+++ b/drivers/media/video/davinci/vpif_capture.h
@@ -59,6 +59,8 @@ struct video_obj {
enum v4l2_field buf_field;
/* Currently selected or default standard */
v4l2_std_id stdid;
+ u32 dv_preset;
+ struct v4l2_bt_timings bt_timings;
/* This is to track the last input that is passed to application */
u32 input_idx;
};
diff --git a/drivers/media/video/davinci/vpif_display.c b/drivers/media/video/davinci/vpif_display.c
index 412c65d..cdf659a 100644
--- a/drivers/media/video/davinci/vpif_display.c
+++ b/drivers/media/video/davinci/vpif_display.c
@@ -38,6 +38,7 @@
#include <media/adv7343.h>
#include <media/v4l2-device.h>
#include <media/v4l2-ioctl.h>
+#include <media/v4l2-chip-ident.h>
#include <mach/dm646x.h>
@@ -84,17 +85,6 @@ static struct vpif_config_params config_params = {
static struct vpif_device vpif_obj = { {NULL} };
static struct device *vpif_dev;
-static const struct vpif_channel_config_params ch_params[] = {
- {
- "NTSC", 720, 480, 30, 0, 1, 268, 1440, 1, 23, 263, 266,
- 286, 525, 525, 0, 1, 0, V4L2_STD_525_60,
- },
- {
- "PAL", 720, 576, 25, 0, 1, 280, 1440, 1, 23, 311, 313,
- 336, 624, 625, 0, 1, 0, V4L2_STD_625_50,
- },
-};
-
/*
* vpif_uservirt_to_phys: This function is used to convert user
* space virtual address to physical address.
@@ -373,30 +363,54 @@ static irqreturn_t vpif_channel_isr(int irq, void *dev_id)
return IRQ_HANDLED;
}
-static int vpif_get_std_info(struct channel_obj *ch)
+static int vpif_update_std_info(struct channel_obj *ch)
{
- struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
struct video_obj *vid_ch = &ch->video;
struct vpif_params *vpifparams = &ch->vpifparams;
struct vpif_channel_config_params *std_info = &vpifparams->std_info;
const struct vpif_channel_config_params *config;
- int index;
-
- std_info->stdid = vid_ch->stdid;
- if (!std_info->stdid)
- return -1;
+ int i;
- for (index = 0; index < ARRAY_SIZE(ch_params); index++) {
- config = &ch_params[index];
- if (config->stdid & std_info->stdid) {
- memcpy(std_info, config, sizeof(*config));
- break;
+ for (i = 0; i < vpif_ch_params_count; i++) {
+ config = &ch_params[i];
+ if (config->hd_sd == 0) {
+ vpif_dbg(2, debug, "SD format\n");
+ if (config->stdid & vid_ch->stdid) {
+ memcpy(std_info, config, sizeof(*config));
+ break;
+ }
+ } else {
+ vpif_dbg(2, debug, "HD format\n");
+ if (config->dv_preset == vid_ch->dv_preset) {
+ memcpy(std_info, config, sizeof(*config));
+ break;
+ }
}
}
- if (index == ARRAY_SIZE(ch_params))
- return -1;
+ if (i == vpif_ch_params_count) {
+ vpif_dbg(1, debug, "Format not found\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int vpif_update_resolution(struct channel_obj *ch)
+{
+ struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+ struct video_obj *vid_ch = &ch->video;
+ struct vpif_params *vpifparams = &ch->vpifparams;
+ struct vpif_channel_config_params *std_info = &vpifparams->std_info;
+
+ if (!vid_ch->stdid && !vid_ch->dv_preset && !vid_ch->bt_timings.height)
+ return -EINVAL;
+
+ if (vid_ch->stdid || vid_ch->dv_preset) {
+ if (vpif_update_std_info(ch))
+ return -EINVAL;
+ }
common->fmt.fmt.pix.width = std_info->width;
common->fmt.fmt.pix.height = std_info->height;
@@ -404,8 +418,8 @@ static int vpif_get_std_info(struct channel_obj *ch)
common->fmt.fmt.pix.width, common->fmt.fmt.pix.height);
/* Set height and width paramateres */
- ch->common[VPIF_VIDEO_INDEX].height = std_info->height;
- ch->common[VPIF_VIDEO_INDEX].width = std_info->width;
+ common->height = std_info->height;
+ common->width = std_info->width;
return 0;
}
@@ -516,10 +530,8 @@ static int vpif_check_format(struct channel_obj *ch,
else
sizeimage = config_params.channel_bufsize[ch->channel_id];
- if (vpif_get_std_info(ch)) {
- vpif_err("Error getting the standard info\n");
+ if (vpif_update_resolution(ch))
return -EINVAL;
- }
hpitch = pixfmt->bytesperline;
vpitch = sizeimage / (hpitch * 2);
@@ -568,7 +580,10 @@ static void vpif_config_addr(struct channel_obj *ch, int muxmode)
static int vpif_mmap(struct file *filep, struct vm_area_struct *vma)
{
struct vpif_fh *fh = filep->private_data;
- struct common_obj *common = &fh->channel->common[VPIF_VIDEO_INDEX];
+ struct channel_obj *ch = fh->channel;
+ struct common_obj *common = &(ch->common[VPIF_VIDEO_INDEX]);
+
+ vpif_dbg(2, debug, "vpif_mmap\n");
return videobuf_mmap_mapper(&common->buffer_queue, vma);
}
@@ -637,9 +652,6 @@ static int vpif_release(struct file *filep)
struct channel_obj *ch = fh->channel;
struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
- if (mutex_lock_interruptible(&common->lock))
- return -ERESTARTSYS;
-
/* if this instance is doing IO */
if (fh->io_allowed[VPIF_VIDEO_INDEX]) {
/* Reset io_usrs member of channel object */
@@ -662,8 +674,6 @@ static int vpif_release(struct file *filep)
config_params.numbuffers[ch->channel_id];
}
- mutex_unlock(&common->lock);
-
/* Decrement channel usrs counter */
atomic_dec(&ch->usrs);
/* If this file handle has initialize encoder device, reset it */
@@ -680,7 +690,12 @@ static int vpif_release(struct file *filep)
}
/* functions implementing ioctls */
-
+/**
+ * vpif_querycap() - QUERYCAP handler
+ * @file: file ptr
+ * @priv: file handle
+ * @cap: ptr to v4l2_capability structure
+ */
static int vpif_querycap(struct file *file, void *priv,
struct v4l2_capability *cap)
{
@@ -722,17 +737,9 @@ static int vpif_g_fmt_vid_out(struct file *file, void *priv,
if (common->fmt.type != fmt->type)
return -EINVAL;
- /* Fill in the information about format */
- if (mutex_lock_interruptible(&common->lock))
- return -ERESTARTSYS;
-
- if (vpif_get_std_info(ch)) {
- vpif_err("Error getting the standard info\n");
+ if (vpif_update_resolution(ch))
return -EINVAL;
- }
-
*fmt = common->fmt;
- mutex_unlock(&common->lock);
return 0;
}
@@ -773,12 +780,7 @@ static int vpif_s_fmt_vid_out(struct file *file, void *priv,
/* store the pix format in the channel object */
common->fmt.fmt.pix = *pixfmt;
/* store the format in the channel object */
- if (mutex_lock_interruptible(&common->lock))
- return -ERESTARTSYS;
-
common->fmt = *fmt;
- mutex_unlock(&common->lock);
-
return 0;
}
@@ -808,7 +810,6 @@ static int vpif_reqbufs(struct file *file, void *priv,
struct common_obj *common;
enum v4l2_field field;
u8 index = 0;
- int ret = 0;
/* This file handle has not initialized the channel,
It is not allowed to do settings */
@@ -826,18 +827,12 @@ static int vpif_reqbufs(struct file *file, void *priv,
index = VPIF_VIDEO_INDEX;
common = &ch->common[index];
- if (mutex_lock_interruptible(&common->lock))
- return -ERESTARTSYS;
- if (common->fmt.type != reqbuf->type) {
- ret = -EINVAL;
- goto reqbuf_exit;
- }
+ if (common->fmt.type != reqbuf->type)
+ return -EINVAL;
- if (0 != common->io_usrs) {
- ret = -EBUSY;
- goto reqbuf_exit;
- }
+ if (0 != common->io_usrs)
+ return -EBUSY;
if (reqbuf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
if (common->fmt.fmt.pix.field == V4L2_FIELD_ANY)
@@ -854,7 +849,7 @@ static int vpif_reqbufs(struct file *file, void *priv,
&common->irqlock,
reqbuf->type, field,
sizeof(struct videobuf_buffer), fh,
- NULL);
+ &common->lock);
/* Set io allowed member of file handle to TRUE */
fh->io_allowed[index] = 1;
@@ -865,11 +860,7 @@ static int vpif_reqbufs(struct file *file, void *priv,
INIT_LIST_HEAD(&common->dma_queue);
/* Allocate buffers */
- ret = videobuf_reqbufs(&common->buffer_queue, reqbuf);
-
-reqbuf_exit:
- mutex_unlock(&common->lock);
- return ret;
+ return videobuf_reqbufs(&common->buffer_queue, reqbuf);
}
static int vpif_querybuf(struct file *file, void *priv,
@@ -990,22 +981,19 @@ static int vpif_s_std(struct file *file, void *priv, v4l2_std_id *std_id)
}
/* Call encoder subdevice function to set the standard */
- if (mutex_lock_interruptible(&common->lock))
- return -ERESTARTSYS;
-
ch->video.stdid = *std_id;
+ ch->video.dv_preset = V4L2_DV_INVALID;
+ memset(&ch->video.bt_timings, 0, sizeof(ch->video.bt_timings));
+
/* Get the information about the standard */
- if (vpif_get_std_info(ch)) {
- vpif_err("Error getting the standard info\n");
+ if (vpif_update_resolution(ch))
return -EINVAL;
- }
if ((ch->vpifparams.std_info.width *
ch->vpifparams.std_info.height * 2) >
config_params.channel_bufsize[ch->channel_id]) {
vpif_err("invalid std for this size\n");
- ret = -EINVAL;
- goto s_std_exit;
+ return -EINVAL;
}
common->fmt.fmt.pix.bytesperline = common->fmt.fmt.pix.width;
@@ -1016,16 +1004,13 @@ static int vpif_s_std(struct file *file, void *priv, v4l2_std_id *std_id)
s_std_output, *std_id);
if (ret < 0) {
vpif_err("Failed to set output standard\n");
- goto s_std_exit;
+ return ret;
}
ret = v4l2_device_call_until_err(&vpif_obj.v4l2_dev, 1, core,
s_std, *std_id);
if (ret < 0)
vpif_err("Failed to set standard for sub devices\n");
-
-s_std_exit:
- mutex_unlock(&common->lock);
return ret;
}
@@ -1090,21 +1075,17 @@ static int vpif_streamon(struct file *file, void *priv,
if (ret < 0)
return ret;
- /* Call videobuf_streamon to start streaming in videobuf */
+ /* Call videobuf_streamon to start streaming in videobuf */
ret = videobuf_streamon(&common->buffer_queue);
if (ret < 0) {
vpif_err("videobuf_streamon\n");
return ret;
}
- if (mutex_lock_interruptible(&common->lock))
- return -ERESTARTSYS;
-
/* If buffer queue is empty, return error */
if (list_empty(&common->dma_queue)) {
vpif_err("buffer queue is empty\n");
- ret = -EIO;
- goto streamon_exit;
+ return -EIO;
}
/* Get the next frame from the buffer queue */
@@ -1130,8 +1111,7 @@ static int vpif_streamon(struct file *file, void *priv,
|| (!ch->vpifparams.std_info.frm_fmt
&& (common->fmt.fmt.pix.field == V4L2_FIELD_NONE))) {
vpif_err("conflict in field format and std format\n");
- ret = -EINVAL;
- goto streamon_exit;
+ return -EINVAL;
}
/* clock settings */
@@ -1140,13 +1120,13 @@ static int vpif_streamon(struct file *file, void *priv,
ch->vpifparams.std_info.hd_sd);
if (ret < 0) {
vpif_err("can't set clock\n");
- goto streamon_exit;
+ return ret;
}
/* set the parameters and addresses */
ret = vpif_set_video_params(vpif, ch->channel_id + 2);
if (ret < 0)
- goto streamon_exit;
+ return ret;
common->started = ret;
vpif_config_addr(ch, ret);
@@ -1171,9 +1151,6 @@ static int vpif_streamon(struct file *file, void *priv,
}
channel_first_int[VPIF_VIDEO_INDEX][ch->channel_id] = 1;
}
-
-streamon_exit:
- mutex_unlock(&common->lock);
return ret;
}
@@ -1199,9 +1176,6 @@ static int vpif_streamoff(struct file *file, void *priv,
return -EINVAL;
}
- if (mutex_lock_interruptible(&common->lock))
- return -ERESTARTSYS;
-
if (buftype == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
/* disable channel */
if (VPIF_CHANNEL2_VIDEO == ch->channel_id) {
@@ -1216,8 +1190,6 @@ static int vpif_streamoff(struct file *file, void *priv,
}
common->started = 0;
- mutex_unlock(&common->lock);
-
return videobuf_streamoff(&common->buffer_queue);
}
@@ -1264,13 +1236,9 @@ static int vpif_s_output(struct file *file, void *priv, unsigned int i)
struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
int ret = 0;
- if (mutex_lock_interruptible(&common->lock))
- return -ERESTARTSYS;
-
if (common->started) {
vpif_err("Streaming in progress\n");
- ret = -EBUSY;
- goto s_output_exit;
+ return -EBUSY;
}
ret = v4l2_device_call_until_err(&vpif_obj.v4l2_dev, 1, video,
@@ -1280,9 +1248,6 @@ static int vpif_s_output(struct file *file, void *priv, unsigned int i)
vpif_err("Failed to set output standard\n");
vid_ch->output_id = i;
-
-s_output_exit:
- mutex_unlock(&common->lock);
return ret;
}
@@ -1315,6 +1280,287 @@ static int vpif_s_priority(struct file *file, void *priv, enum v4l2_priority p)
return v4l2_prio_change(&ch->prio, &fh->prio, p);
}
+/**
+ * vpif_enum_dv_presets() - ENUM_DV_PRESETS handler
+ * @file: file ptr
+ * @priv: file handle
+ * @preset: input preset
+ */
+static int vpif_enum_dv_presets(struct file *file, void *priv,
+ struct v4l2_dv_enum_preset *preset)
+{
+ struct vpif_fh *fh = priv;
+ struct channel_obj *ch = fh->channel;
+ struct video_obj *vid_ch = &ch->video;
+
+ return v4l2_subdev_call(vpif_obj.sd[vid_ch->output_id],
+ video, enum_dv_presets, preset);
+}
+
+/**
+ * vpif_s_dv_presets() - S_DV_PRESETS handler
+ * @file: file ptr
+ * @priv: file handle
+ * @preset: input preset
+ */
+static int vpif_s_dv_preset(struct file *file, void *priv,
+ struct v4l2_dv_preset *preset)
+{
+ struct vpif_fh *fh = priv;
+ struct channel_obj *ch = fh->channel;
+ struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+ struct video_obj *vid_ch = &ch->video;
+ int ret = 0;
+
+ if (common->started) {
+ vpif_dbg(1, debug, "streaming in progress\n");
+ return -EBUSY;
+ }
+
+ ret = v4l2_prio_check(&ch->prio, fh->prio);
+ if (ret != 0)
+ return ret;
+
+ fh->initialized = 1;
+
+ /* Call encoder subdevice function to set the standard */
+ if (mutex_lock_interruptible(&common->lock))
+ return -ERESTARTSYS;
+
+ ch->video.dv_preset = preset->preset;
+ ch->video.stdid = V4L2_STD_UNKNOWN;
+ memset(&ch->video.bt_timings, 0, sizeof(ch->video.bt_timings));
+
+ /* Get the information about the standard */
+ if (vpif_update_resolution(ch)) {
+ ret = -EINVAL;
+ } else {
+ /* Configure the default format information */
+ vpif_config_format(ch);
+
+ ret = v4l2_subdev_call(vpif_obj.sd[vid_ch->output_id],
+ video, s_dv_preset, preset);
+ }
+
+ mutex_unlock(&common->lock);
+
+ return ret;
+}
+/**
+ * vpif_g_dv_presets() - G_DV_PRESETS handler
+ * @file: file ptr
+ * @priv: file handle
+ * @preset: input preset
+ */
+static int vpif_g_dv_preset(struct file *file, void *priv,
+ struct v4l2_dv_preset *preset)
+{
+ struct vpif_fh *fh = priv;
+ struct channel_obj *ch = fh->channel;
+
+ preset->preset = ch->video.dv_preset;
+
+ return 0;
+}
+/**
+ * vpif_s_dv_timings() - S_DV_TIMINGS handler
+ * @file: file ptr
+ * @priv: file handle
+ * @timings: digital video timings
+ */
+static int vpif_s_dv_timings(struct file *file, void *priv,
+ struct v4l2_dv_timings *timings)
+{
+ struct vpif_fh *fh = priv;
+ struct channel_obj *ch = fh->channel;
+ struct vpif_params *vpifparams = &ch->vpifparams;
+ struct vpif_channel_config_params *std_info = &vpifparams->std_info;
+ struct video_obj *vid_ch = &ch->video;
+ struct v4l2_bt_timings *bt = &vid_ch->bt_timings;
+ int ret;
+
+ if (timings->type != V4L2_DV_BT_656_1120) {
+ vpif_dbg(2, debug, "Timing type not defined\n");
+ return -EINVAL;
+ }
+
+ /* Configure subdevice timings, if any */
+ ret = v4l2_subdev_call(vpif_obj.sd[vid_ch->output_id],
+ video, s_dv_timings, timings);
+ if (ret == -ENOIOCTLCMD) {
+ vpif_dbg(2, debug, "Custom DV timings not supported by "
+ "subdevice\n");
+ return -EINVAL;
+ }
+ if (ret < 0) {
+ vpif_dbg(2, debug, "Error setting custom DV timings\n");
+ return ret;
+ }
+
+ if (!(timings->bt.width && timings->bt.height &&
+ (timings->bt.hbackporch ||
+ timings->bt.hfrontporch ||
+ timings->bt.hsync) &&
+ timings->bt.vfrontporch &&
+ (timings->bt.vbackporch ||
+ timings->bt.vsync))) {
+ vpif_dbg(2, debug, "Timings for width, height, "
+ "horizontal back porch, horizontal sync, "
+ "horizontal front porch, vertical back porch, "
+ "vertical sync and vertical back porch "
+ "must be defined\n");
+ return -EINVAL;
+ }
+
+ *bt = timings->bt;
+
+ /* Configure video port timings */
+
+ std_info->eav2sav = bt->hbackporch + bt->hfrontporch +
+ bt->hsync - 8;
+ std_info->sav2eav = bt->width;
+
+ std_info->l1 = 1;
+ std_info->l3 = bt->vsync + bt->vbackporch + 1;
+
+ if (bt->interlaced) {
+ if (bt->il_vbackporch || bt->il_vfrontporch || bt->il_vsync) {
+ std_info->vsize = bt->height * 2 +
+ bt->vfrontporch + bt->vsync + bt->vbackporch +
+ bt->il_vfrontporch + bt->il_vsync +
+ bt->il_vbackporch;
+ std_info->l5 = std_info->vsize/2 -
+ (bt->vfrontporch - 1);
+ std_info->l7 = std_info->vsize/2 + 1;
+ std_info->l9 = std_info->l7 + bt->il_vsync +
+ bt->il_vbackporch + 1;
+ std_info->l11 = std_info->vsize -
+ (bt->il_vfrontporch - 1);
+ } else {
+ vpif_dbg(2, debug, "Required timing values for "
+ "interlaced BT format missing\n");
+ return -EINVAL;
+ }
+ } else {
+ std_info->vsize = bt->height + bt->vfrontporch +
+ bt->vsync + bt->vbackporch;
+ std_info->l5 = std_info->vsize - (bt->vfrontporch - 1);
+ }
+ strncpy(std_info->name, "Custom timings BT656/1120",
+ VPIF_MAX_NAME);
+ std_info->width = bt->width;
+ std_info->height = bt->height;
+ std_info->frm_fmt = bt->interlaced ? 0 : 1;
+ std_info->ycmux_mode = 0;
+ std_info->capture_format = 0;
+ std_info->vbi_supported = 0;
+ std_info->hd_sd = 1;
+ std_info->stdid = 0;
+ std_info->dv_preset = V4L2_DV_INVALID;
+
+ vid_ch->stdid = 0;
+ vid_ch->dv_preset = V4L2_DV_INVALID;
+
+ return 0;
+}
+
+/**
+ * vpif_g_dv_timings() - G_DV_TIMINGS handler
+ * @file: file ptr
+ * @priv: file handle
+ * @timings: digital video timings
+ */
+static int vpif_g_dv_timings(struct file *file, void *priv,
+ struct v4l2_dv_timings *timings)
+{
+ struct vpif_fh *fh = priv;
+ struct channel_obj *ch = fh->channel;
+ struct video_obj *vid_ch = &ch->video;
+ struct v4l2_bt_timings *bt = &vid_ch->bt_timings;
+
+ timings->bt = *bt;
+
+ return 0;
+}
+
+/*
+ * vpif_g_chip_ident() - Identify the chip
+ * @file: file ptr
+ * @priv: file handle
+ * @chip: chip identity
+ *
+ * Returns zero or -EINVAL if read operations fails.
+ */
+static int vpif_g_chip_ident(struct file *file, void *priv,
+ struct v4l2_dbg_chip_ident *chip)
+{
+ chip->ident = V4L2_IDENT_NONE;
+ chip->revision = 0;
+ if (chip->match.type != V4L2_CHIP_MATCH_I2C_DRIVER &&
+ chip->match.type != V4L2_CHIP_MATCH_I2C_ADDR) {
+ vpif_dbg(2, debug, "match_type is invalid.\n");
+ return -EINVAL;
+ }
+
+ return v4l2_device_call_until_err(&vpif_obj.v4l2_dev, 0, core,
+ g_chip_ident, chip);
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+/*
+ * vpif_dbg_g_register() - Read register
+ * @file: file ptr
+ * @priv: file handle
+ * @reg: register to be read
+ *
+ * Debugging only
+ * Returns zero or -EINVAL if read operations fails.
+ */
+static int vpif_dbg_g_register(struct file *file, void *priv,
+ struct v4l2_dbg_register *reg){
+ struct vpif_fh *fh = priv;
+ struct channel_obj *ch = fh->channel;
+ struct video_obj *vid_ch = &ch->video;
+
+ return v4l2_subdev_call(vpif_obj.sd[vid_ch->output_id], core,
+ g_register, reg);
+}
+
+/*
+ * vpif_dbg_s_register() - Write to register
+ * @file: file ptr
+ * @priv: file handle
+ * @reg: register to be modified
+ *
+ * Debugging only
+ * Returns zero or -EINVAL if write operations fails.
+ */
+static int vpif_dbg_s_register(struct file *file, void *priv,
+ struct v4l2_dbg_register *reg){
+ struct vpif_fh *fh = priv;
+ struct channel_obj *ch = fh->channel;
+ struct video_obj *vid_ch = &ch->video;
+
+ return v4l2_subdev_call(vpif_obj.sd[vid_ch->output_id], core,
+ s_register, reg);
+}
+#endif
+
+/*
+ * vpif_log_status() - Status information
+ * @file: file ptr
+ * @priv: file handle
+ *
+ * Returns zero.
+ */
+static int vpif_log_status(struct file *filep, void *priv)
+{
+ /* status for sub devices */
+ v4l2_device_call_all(&vpif_obj.v4l2_dev, 0, core, log_status);
+
+ return 0;
+}
+
/* vpif display ioctl operations */
static const struct v4l2_ioctl_ops vpif_ioctl_ops = {
.vidioc_querycap = vpif_querycap,
@@ -1336,13 +1582,24 @@ static const struct v4l2_ioctl_ops vpif_ioctl_ops = {
.vidioc_s_output = vpif_s_output,
.vidioc_g_output = vpif_g_output,
.vidioc_cropcap = vpif_cropcap,
+ .vidioc_enum_dv_presets = vpif_enum_dv_presets,
+ .vidioc_s_dv_preset = vpif_s_dv_preset,
+ .vidioc_g_dv_preset = vpif_g_dv_preset,
+ .vidioc_s_dv_timings = vpif_s_dv_timings,
+ .vidioc_g_dv_timings = vpif_g_dv_timings,
+ .vidioc_g_chip_ident = vpif_g_chip_ident,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ .vidioc_g_register = vpif_dbg_g_register,
+ .vidioc_s_register = vpif_dbg_s_register,
+#endif
+ .vidioc_log_status = vpif_log_status,
};
static const struct v4l2_file_operations vpif_fops = {
.owner = THIS_MODULE,
.open = vpif_open,
.release = vpif_release,
- .ioctl = video_ioctl2,
+ .unlocked_ioctl = video_ioctl2,
.mmap = vpif_mmap,
.poll = vpif_poll
};
@@ -1526,6 +1783,7 @@ static __init int vpif_probe(struct platform_device *pdev)
v4l2_prio_init(&ch->prio);
ch->common[VPIF_VIDEO_INDEX].fmt.type =
V4L2_BUF_TYPE_VIDEO_OUTPUT;
+ ch->video_dev->lock = &common->lock;
/* register video device */
vpif_dbg(1, debug, "channel=%x,channel->video_dev=%x\n",
@@ -1565,6 +1823,8 @@ static __init int vpif_probe(struct platform_device *pdev)
vpif_obj.sd[i]->grp_id = 1 << i;
}
+ v4l2_info(&vpif_obj.v4l2_dev,
+ "DM646x VPIF display driver initialized\n");
return 0;
probe_subdev_out:
diff --git a/drivers/media/video/davinci/vpif_display.h b/drivers/media/video/davinci/vpif_display.h
index a2a7cd1..b53aaa8 100644
--- a/drivers/media/video/davinci/vpif_display.h
+++ b/drivers/media/video/davinci/vpif_display.h
@@ -67,6 +67,8 @@ struct video_obj {
* most recent displayed frame only */
v4l2_std_id stdid; /* Currently selected or default
* standard */
+ u32 dv_preset;
+ struct v4l2_bt_timings bt_timings;
u32 output_id; /* Current output id */
};
diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c
index 099d5df..87f77a3 100644
--- a/drivers/media/video/em28xx/em28xx-cards.c
+++ b/drivers/media/video/em28xx/em28xx-cards.c
@@ -33,6 +33,7 @@
#include <media/saa7115.h>
#include <media/tvp5150.h>
#include <media/tvaudio.h>
+#include <media/mt9v011.h>
#include <media/i2c-addr.h>
#include <media/tveeprom.h>
#include <media/v4l2-common.h>
@@ -1917,11 +1918,6 @@ static unsigned short tvp5150_addrs[] = {
I2C_CLIENT_END
};
-static unsigned short mt9v011_addrs[] = {
- 0xba >> 1,
- I2C_CLIENT_END
-};
-
static unsigned short msp3400_addrs[] = {
0x80 >> 1,
0x88 >> 1,
@@ -2437,6 +2433,7 @@ void em28xx_register_i2c_ir(struct em28xx *dev)
dev->init_data.ir_codes = RC_MAP_RC5_HAUPPAUGE_NEW;
dev->init_data.get_key = em28xx_get_key_em_haup;
dev->init_data.name = "i2c IR (EM2840 Hauppauge)";
+ break;
case EM2820_BOARD_LEADTEK_WINFAST_USBII_DELUXE:
dev->init_data.ir_codes = RC_MAP_WINFAST_USBII_DELUXE;
dev->init_data.get_key = em28xx_get_key_winfast_usbii_deluxe;
@@ -2623,11 +2620,17 @@ void em28xx_card_setup(struct em28xx *dev)
"tvp5150", 0, tvp5150_addrs);
if (dev->em28xx_sensor == EM28XX_MT9V011) {
+ struct mt9v011_platform_data pdata;
+ struct i2c_board_info mt9v011_info = {
+ .type = "mt9v011",
+ .addr = 0xba >> 1,
+ .platform_data = &pdata,
+ };
struct v4l2_subdev *sd;
- sd = v4l2_i2c_new_subdev(&dev->v4l2_dev,
- &dev->i2c_adap, "mt9v011", 0, mt9v011_addrs);
- v4l2_subdev_call(sd, core, s_config, 0, &dev->sensor_xtal);
+ pdata.xtal = dev->sensor_xtal;
+ sd = v4l2_i2c_new_subdev_board(&dev->v4l2_dev, &dev->i2c_adap,
+ &mt9v011_info, NULL);
}
diff --git a/drivers/media/video/et61x251/et61x251.h b/drivers/media/video/et61x251/et61x251.h
index cc77d14..bf66189 100644
--- a/drivers/media/video/et61x251/et61x251.h
+++ b/drivers/media/video/et61x251/et61x251.h
@@ -59,31 +59,7 @@
/*****************************************************************************/
static const struct usb_device_id et61x251_id_table[] = {
- { USB_DEVICE(0x102c, 0x6151), },
{ USB_DEVICE(0x102c, 0x6251), },
- { USB_DEVICE(0x102c, 0x6253), },
- { USB_DEVICE(0x102c, 0x6254), },
- { USB_DEVICE(0x102c, 0x6255), },
- { USB_DEVICE(0x102c, 0x6256), },
- { USB_DEVICE(0x102c, 0x6257), },
- { USB_DEVICE(0x102c, 0x6258), },
- { USB_DEVICE(0x102c, 0x6259), },
- { USB_DEVICE(0x102c, 0x625a), },
- { USB_DEVICE(0x102c, 0x625b), },
- { USB_DEVICE(0x102c, 0x625c), },
- { USB_DEVICE(0x102c, 0x625d), },
- { USB_DEVICE(0x102c, 0x625e), },
- { USB_DEVICE(0x102c, 0x625f), },
- { USB_DEVICE(0x102c, 0x6260), },
- { USB_DEVICE(0x102c, 0x6261), },
- { USB_DEVICE(0x102c, 0x6262), },
- { USB_DEVICE(0x102c, 0x6263), },
- { USB_DEVICE(0x102c, 0x6264), },
- { USB_DEVICE(0x102c, 0x6265), },
- { USB_DEVICE(0x102c, 0x6266), },
- { USB_DEVICE(0x102c, 0x6267), },
- { USB_DEVICE(0x102c, 0x6268), },
- { USB_DEVICE(0x102c, 0x6269), },
{ }
};
diff --git a/drivers/media/video/gspca/benq.c b/drivers/media/video/gspca/benq.c
index 6290439..a09c470 100644
--- a/drivers/media/video/gspca/benq.c
+++ b/drivers/media/video/gspca/benq.c
@@ -276,7 +276,7 @@ static const struct sd_desc sd_desc = {
};
/* -- module initialisation -- */
-static const __devinitdata struct usb_device_id device_table[] = {
+static const struct usb_device_id device_table[] = {
{USB_DEVICE(0x04a5, 0x3035)},
{}
};
diff --git a/drivers/media/video/gspca/conex.c b/drivers/media/video/gspca/conex.c
index 1eacb6c..8b39849 100644
--- a/drivers/media/video/gspca/conex.c
+++ b/drivers/media/video/gspca/conex.c
@@ -1040,14 +1040,14 @@ static const struct sd_desc sd_desc = {
};
/* -- module initialisation -- */
-static const struct usb_device_id device_table[] __devinitconst = {
+static const struct usb_device_id device_table[] = {
{USB_DEVICE(0x0572, 0x0041)},
{}
};
MODULE_DEVICE_TABLE(usb, device_table);
/* -- device connect -- */
-static int __devinit sd_probe(struct usb_interface *intf,
+static int sd_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
diff --git a/drivers/media/video/gspca/cpia1.c b/drivers/media/video/gspca/cpia1.c
index c1ae05f..4bf2cab 100644
--- a/drivers/media/video/gspca/cpia1.c
+++ b/drivers/media/video/gspca/cpia1.c
@@ -2088,7 +2088,7 @@ static const struct sd_desc sd_desc = {
};
/* -- module initialisation -- */
-static const __devinitdata struct usb_device_id device_table[] = {
+static const struct usb_device_id device_table[] = {
{USB_DEVICE(0x0553, 0x0002)},
{USB_DEVICE(0x0813, 0x0001)},
{}
diff --git a/drivers/media/video/gspca/etoms.c b/drivers/media/video/gspca/etoms.c
index a594b36..4b2c483 100644
--- a/drivers/media/video/gspca/etoms.c
+++ b/drivers/media/video/gspca/etoms.c
@@ -864,7 +864,7 @@ static const struct sd_desc sd_desc = {
};
/* -- module initialisation -- */
-static const struct usb_device_id device_table[] __devinitconst = {
+static const struct usb_device_id device_table[] = {
{USB_DEVICE(0x102c, 0x6151), .driver_info = SENSOR_PAS106},
#if !defined CONFIG_USB_ET61X251 && !defined CONFIG_USB_ET61X251_MODULE
{USB_DEVICE(0x102c, 0x6251), .driver_info = SENSOR_TAS5130CXX},
@@ -875,7 +875,7 @@ static const struct usb_device_id device_table[] __devinitconst = {
MODULE_DEVICE_TABLE(usb, device_table);
/* -- device connect -- */
-static int __devinit sd_probe(struct usb_interface *intf,
+static int sd_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
diff --git a/drivers/media/video/gspca/finepix.c b/drivers/media/video/gspca/finepix.c
index d782264..987b4b6 100644
--- a/drivers/media/video/gspca/finepix.c
+++ b/drivers/media/video/gspca/finepix.c
@@ -229,7 +229,7 @@ static void sd_stop0(struct gspca_dev *gspca_dev)
}
/* Table of supported USB devices */
-static const __devinitdata struct usb_device_id device_table[] = {
+static const struct usb_device_id device_table[] = {
{USB_DEVICE(0x04cb, 0x0104)},
{USB_DEVICE(0x04cb, 0x0109)},
{USB_DEVICE(0x04cb, 0x010b)},
diff --git a/drivers/media/video/gspca/gl860/gl860.c b/drivers/media/video/gspca/gl860/gl860.c
index b05bec7..9908303 100644
--- a/drivers/media/video/gspca/gl860/gl860.c
+++ b/drivers/media/video/gspca/gl860/gl860.c
@@ -488,7 +488,7 @@ static void sd_callback(struct gspca_dev *gspca_dev)
/*=================== USB driver structure initialisation ==================*/
-static const __devinitdata struct usb_device_id device_table[] = {
+static const struct usb_device_id device_table[] = {
{USB_DEVICE(0x05e3, 0x0503)},
{USB_DEVICE(0x05e3, 0xf191)},
{}
diff --git a/drivers/media/video/gspca/gspca.c b/drivers/media/video/gspca/gspca.c
index 4429700..f21f2a2 100644
--- a/drivers/media/video/gspca/gspca.c
+++ b/drivers/media/video/gspca/gspca.c
@@ -55,7 +55,7 @@ MODULE_AUTHOR("Jean-François Moine <http://moinejf.free.fr>");
MODULE_DESCRIPTION("GSPCA USB Camera Driver");
MODULE_LICENSE("GPL");
-#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 11, 0)
+#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 12, 0)
#ifdef GSPCA_DEBUG
int gspca_debug = D_ERR | D_PROBE;
@@ -508,8 +508,8 @@ static int gspca_is_compressed(__u32 format)
return 0;
}
-static int frame_alloc(struct gspca_dev *gspca_dev,
- unsigned int count)
+static int frame_alloc(struct gspca_dev *gspca_dev, struct file *file,
+ enum v4l2_memory memory, unsigned int count)
{
struct gspca_frame *frame;
unsigned int frsz;
@@ -519,7 +519,6 @@ static int frame_alloc(struct gspca_dev *gspca_dev,
frsz = gspca_dev->cam.cam_mode[i].sizeimage;
PDEBUG(D_STREAM, "frame alloc frsz: %d", frsz);
frsz = PAGE_ALIGN(frsz);
- gspca_dev->frsz = frsz;
if (count >= GSPCA_MAX_FRAMES)
count = GSPCA_MAX_FRAMES - 1;
gspca_dev->frbuf = vmalloc_32(frsz * count);
@@ -527,6 +526,9 @@ static int frame_alloc(struct gspca_dev *gspca_dev,
err("frame alloc failed");
return -ENOMEM;
}
+ gspca_dev->capt_file = file;
+ gspca_dev->memory = memory;
+ gspca_dev->frsz = frsz;
gspca_dev->nframes = count;
for (i = 0; i < count; i++) {
frame = &gspca_dev->frame[i];
@@ -535,7 +537,7 @@ static int frame_alloc(struct gspca_dev *gspca_dev,
frame->v4l2_buf.flags = 0;
frame->v4l2_buf.field = V4L2_FIELD_NONE;
frame->v4l2_buf.length = frsz;
- frame->v4l2_buf.memory = gspca_dev->memory;
+ frame->v4l2_buf.memory = memory;
frame->v4l2_buf.sequence = 0;
frame->data = gspca_dev->frbuf + i * frsz;
frame->v4l2_buf.m.offset = i * frsz;
@@ -558,6 +560,9 @@ static void frame_free(struct gspca_dev *gspca_dev)
gspca_dev->frame[i].data = NULL;
}
gspca_dev->nframes = 0;
+ gspca_dev->frsz = 0;
+ gspca_dev->capt_file = NULL;
+ gspca_dev->memory = GSPCA_MEMORY_NO;
}
static void destroy_urbs(struct gspca_dev *gspca_dev)
@@ -1210,29 +1215,15 @@ static void gspca_release(struct video_device *vfd)
static int dev_open(struct file *file)
{
struct gspca_dev *gspca_dev;
- int ret;
PDEBUG(D_STREAM, "[%s] open", current->comm);
gspca_dev = (struct gspca_dev *) video_devdata(file);
- if (mutex_lock_interruptible(&gspca_dev->queue_lock))
- return -ERESTARTSYS;
- if (!gspca_dev->present) {
- ret = -ENODEV;
- goto out;
- }
-
- if (gspca_dev->users > 4) { /* (arbitrary value) */
- ret = -EBUSY;
- goto out;
- }
+ if (!gspca_dev->present)
+ return -ENODEV;
/* protect the subdriver against rmmod */
- if (!try_module_get(gspca_dev->module)) {
- ret = -ENODEV;
- goto out;
- }
-
- gspca_dev->users++;
+ if (!try_module_get(gspca_dev->module))
+ return -ENODEV;
file->private_data = gspca_dev;
#ifdef GSPCA_DEBUG
@@ -1244,14 +1235,7 @@ static int dev_open(struct file *file)
gspca_dev->vdev.debug &= ~(V4L2_DEBUG_IOCTL
| V4L2_DEBUG_IOCTL_ARG);
#endif
- ret = 0;
-out:
- mutex_unlock(&gspca_dev->queue_lock);
- if (ret != 0)
- PDEBUG(D_ERR|D_STREAM, "open failed err %d", ret);
- else
- PDEBUG(D_STREAM, "open done");
- return ret;
+ return 0;
}
static int dev_close(struct file *file)
@@ -1261,7 +1245,6 @@ static int dev_close(struct file *file)
PDEBUG(D_STREAM, "[%s] close", current->comm);
if (mutex_lock_interruptible(&gspca_dev->queue_lock))
return -ERESTARTSYS;
- gspca_dev->users--;
/* if the file did the capture, free the streaming resources */
if (gspca_dev->capt_file == file) {
@@ -1272,8 +1255,6 @@ static int dev_close(struct file *file)
mutex_unlock(&gspca_dev->usb_lock);
}
frame_free(gspca_dev);
- gspca_dev->capt_file = NULL;
- gspca_dev->memory = GSPCA_MEMORY_NO;
}
file->private_data = NULL;
module_put(gspca_dev->module);
@@ -1516,6 +1497,7 @@ static int vidioc_reqbufs(struct file *file, void *priv,
return -ERESTARTSYS;
if (gspca_dev->memory != GSPCA_MEMORY_NO
+ && gspca_dev->memory != GSPCA_MEMORY_READ
&& gspca_dev->memory != rb->memory) {
ret = -EBUSY;
goto out;
@@ -1544,19 +1526,18 @@ static int vidioc_reqbufs(struct file *file, void *priv,
gspca_stream_off(gspca_dev);
mutex_unlock(&gspca_dev->usb_lock);
}
+ /* Don't restart the stream when switching from read to mmap mode */
+ if (gspca_dev->memory == GSPCA_MEMORY_READ)
+ streaming = 0;
/* free the previous allocated buffers, if any */
- if (gspca_dev->nframes != 0) {
+ if (gspca_dev->nframes != 0)
frame_free(gspca_dev);
- gspca_dev->capt_file = NULL;
- }
if (rb->count == 0) /* unrequest */
goto out;
- gspca_dev->memory = rb->memory;
- ret = frame_alloc(gspca_dev, rb->count);
+ ret = frame_alloc(gspca_dev, file, rb->memory, rb->count);
if (ret == 0) {
rb->count = gspca_dev->nframes;
- gspca_dev->capt_file = file;
if (streaming)
ret = gspca_init_transfer(gspca_dev);
}
@@ -1630,11 +1611,15 @@ static int vidioc_streamoff(struct file *file, void *priv,
if (buf_type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
- if (!gspca_dev->streaming)
- return 0;
+
if (mutex_lock_interruptible(&gspca_dev->queue_lock))
return -ERESTARTSYS;
+ if (!gspca_dev->streaming) {
+ ret = 0;
+ goto out;
+ }
+
/* check the capture file */
if (gspca_dev->capt_file != file) {
ret = -EBUSY;
@@ -1649,6 +1634,8 @@ static int vidioc_streamoff(struct file *file, void *priv,
gspca_dev->usb_err = 0;
gspca_stream_off(gspca_dev);
mutex_unlock(&gspca_dev->usb_lock);
+ /* In case another thread is waiting in dqbuf */
+ wake_up_interruptible(&gspca_dev->wq);
/* empty the transfer queues */
atomic_set(&gspca_dev->fr_q, 0);
@@ -1827,33 +1814,77 @@ out:
return ret;
}
+static int frame_ready_nolock(struct gspca_dev *gspca_dev, struct file *file,
+ enum v4l2_memory memory)
+{
+ if (!gspca_dev->present)
+ return -ENODEV;
+ if (gspca_dev->capt_file != file || gspca_dev->memory != memory ||
+ !gspca_dev->streaming)
+ return -EINVAL;
+
+ /* check if a frame is ready */
+ return gspca_dev->fr_o != atomic_read(&gspca_dev->fr_i);
+}
+
+static int frame_ready(struct gspca_dev *gspca_dev, struct file *file,
+ enum v4l2_memory memory)
+{
+ int ret;
+
+ if (mutex_lock_interruptible(&gspca_dev->queue_lock))
+ return -ERESTARTSYS;
+ ret = frame_ready_nolock(gspca_dev, file, memory);
+ mutex_unlock(&gspca_dev->queue_lock);
+ return ret;
+}
+
/*
- * wait for a video frame
+ * dequeue a video buffer
*
- * If a frame is ready, its index is returned.
+ * If nonblock_ing is false, block until a buffer is available.
*/
-static int frame_wait(struct gspca_dev *gspca_dev,
- int nonblock_ing)
+static int vidioc_dqbuf(struct file *file, void *priv,
+ struct v4l2_buffer *v4l2_buf)
{
- int i, ret;
+ struct gspca_dev *gspca_dev = priv;
+ struct gspca_frame *frame;
+ int i, j, ret;
- /* check if a frame is ready */
- i = gspca_dev->fr_o;
- if (i == atomic_read(&gspca_dev->fr_i)) {
- if (nonblock_ing)
+ PDEBUG(D_FRAM, "dqbuf");
+
+ if (mutex_lock_interruptible(&gspca_dev->queue_lock))
+ return -ERESTARTSYS;
+
+ for (;;) {
+ ret = frame_ready_nolock(gspca_dev, file, v4l2_buf->memory);
+ if (ret < 0)
+ goto out;
+ if (ret > 0)
+ break;
+
+ mutex_unlock(&gspca_dev->queue_lock);
+
+ if (file->f_flags & O_NONBLOCK)
return -EAGAIN;
/* wait till a frame is ready */
ret = wait_event_interruptible_timeout(gspca_dev->wq,
- i != atomic_read(&gspca_dev->fr_i) ||
- !gspca_dev->streaming || !gspca_dev->present,
+ frame_ready(gspca_dev, file, v4l2_buf->memory),
msecs_to_jiffies(3000));
if (ret < 0)
return ret;
- if (ret == 0 || !gspca_dev->streaming || !gspca_dev->present)
+ if (ret == 0)
return -EIO;
+
+ if (mutex_lock_interruptible(&gspca_dev->queue_lock))
+ return -ERESTARTSYS;
}
+ i = gspca_dev->fr_o;
+ j = gspca_dev->fr_queue[i];
+ frame = &gspca_dev->frame[j];
+
gspca_dev->fr_o = (i + 1) % GSPCA_MAX_FRAMES;
if (gspca_dev->sd_desc->dq_callback) {
@@ -1863,46 +1894,12 @@ static int frame_wait(struct gspca_dev *gspca_dev,
gspca_dev->sd_desc->dq_callback(gspca_dev);
mutex_unlock(&gspca_dev->usb_lock);
}
- return gspca_dev->fr_queue[i];
-}
-
-/*
- * dequeue a video buffer
- *
- * If nonblock_ing is false, block until a buffer is available.
- */
-static int vidioc_dqbuf(struct file *file, void *priv,
- struct v4l2_buffer *v4l2_buf)
-{
- struct gspca_dev *gspca_dev = priv;
- struct gspca_frame *frame;
- int i, ret;
-
- PDEBUG(D_FRAM, "dqbuf");
- if (v4l2_buf->memory != gspca_dev->memory)
- return -EINVAL;
-
- if (!gspca_dev->present)
- return -ENODEV;
-
- /* if not streaming, be sure the application will not loop forever */
- if (!(file->f_flags & O_NONBLOCK)
- && !gspca_dev->streaming && gspca_dev->users == 1)
- return -EINVAL;
- /* only the capturing file may dequeue */
- if (gspca_dev->capt_file != file)
- return -EINVAL;
-
- /* only one dequeue / read at a time */
- if (mutex_lock_interruptible(&gspca_dev->read_lock))
- return -ERESTARTSYS;
+ frame->v4l2_buf.flags &= ~V4L2_BUF_FLAG_DONE;
+ memcpy(v4l2_buf, &frame->v4l2_buf, sizeof *v4l2_buf);
+ PDEBUG(D_FRAM, "dqbuf %d", j);
+ ret = 0;
- ret = frame_wait(gspca_dev, file->f_flags & O_NONBLOCK);
- if (ret < 0)
- goto out;
- i = ret; /* frame index */
- frame = &gspca_dev->frame[i];
if (gspca_dev->memory == V4L2_MEMORY_USERPTR) {
if (copy_to_user((__u8 __user *) frame->v4l2_buf.m.userptr,
frame->data,
@@ -1910,15 +1907,10 @@ static int vidioc_dqbuf(struct file *file, void *priv,
PDEBUG(D_ERR|D_STREAM,
"dqbuf cp to user failed");
ret = -EFAULT;
- goto out;
}
}
- frame->v4l2_buf.flags &= ~V4L2_BUF_FLAG_DONE;
- memcpy(v4l2_buf, &frame->v4l2_buf, sizeof *v4l2_buf);
- PDEBUG(D_FRAM, "dqbuf %d", i);
- ret = 0;
out:
- mutex_unlock(&gspca_dev->read_lock);
+ mutex_unlock(&gspca_dev->queue_lock);
return ret;
}
@@ -2033,9 +2025,7 @@ static unsigned int dev_poll(struct file *file, poll_table *wait)
poll_wait(file, &gspca_dev->wq, wait);
/* if reqbufs is not done, the user would use read() */
- if (gspca_dev->nframes == 0) {
- if (gspca_dev->memory != GSPCA_MEMORY_NO)
- return POLLERR; /* not the 1st time */
+ if (gspca_dev->memory == GSPCA_MEMORY_NO) {
ret = read_alloc(gspca_dev, file);
if (ret != 0)
return POLLERR;
@@ -2067,18 +2057,10 @@ static ssize_t dev_read(struct file *file, char __user *data,
PDEBUG(D_FRAM, "read (%zd)", count);
if (!gspca_dev->present)
return -ENODEV;
- switch (gspca_dev->memory) {
- case GSPCA_MEMORY_NO: /* first time */
+ if (gspca_dev->memory == GSPCA_MEMORY_NO) { /* first time ? */
ret = read_alloc(gspca_dev, file);
if (ret != 0)
return ret;
- break;
- case GSPCA_MEMORY_READ:
- if (gspca_dev->capt_file == file)
- break;
- /* fall thru */
- default:
- return -EINVAL;
}
/* get a frame */
@@ -2266,7 +2248,6 @@ int gspca_dev_probe2(struct usb_interface *intf,
goto out;
mutex_init(&gspca_dev->usb_lock);
- mutex_init(&gspca_dev->read_lock);
mutex_init(&gspca_dev->queue_lock);
init_waitqueue_head(&gspca_dev->wq);
@@ -2341,12 +2322,11 @@ void gspca_disconnect(struct usb_interface *intf)
PDEBUG(D_PROBE, "%s disconnect",
video_device_node_name(&gspca_dev->vdev));
mutex_lock(&gspca_dev->usb_lock);
+
gspca_dev->present = 0;
+ wake_up_interruptible(&gspca_dev->wq);
- if (gspca_dev->streaming) {
- destroy_urbs(gspca_dev);
- wake_up_interruptible(&gspca_dev->wq);
- }
+ destroy_urbs(gspca_dev);
#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
gspca_input_destroy_urb(gspca_dev);
diff --git a/drivers/media/video/gspca/gspca.h b/drivers/media/video/gspca/gspca.h
index 97b77a2..4175522 100644
--- a/drivers/media/video/gspca/gspca.h
+++ b/drivers/media/video/gspca/gspca.h
@@ -205,14 +205,12 @@ struct gspca_dev {
wait_queue_head_t wq; /* wait queue */
struct mutex usb_lock; /* usb exchange protection */
- struct mutex read_lock; /* read protection */
struct mutex queue_lock; /* ISOC queue protection */
int usb_err; /* USB error - protected by usb_lock */
u16 pkt_size; /* ISOC packet size */
#ifdef CONFIG_PM
char frozen; /* suspend - resume */
#endif
- char users; /* number of opens */
char present; /* device connected */
char nbufread; /* number of buffers for read() */
char memory; /* memory type (V4L2_MEMORY_xxx) */
diff --git a/drivers/media/video/gspca/jeilinj.c b/drivers/media/video/gspca/jeilinj.c
index a35e87b..06b777f 100644
--- a/drivers/media/video/gspca/jeilinj.c
+++ b/drivers/media/video/gspca/jeilinj.c
@@ -314,7 +314,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
}
/* Table of supported USB devices */
-static const __devinitdata struct usb_device_id device_table[] = {
+static const struct usb_device_id device_table[] = {
{USB_DEVICE(0x0979, 0x0280)},
{}
};
diff --git a/drivers/media/video/gspca/jpeg.h b/drivers/media/video/gspca/jpeg.h
index de63c36..ab54910 100644
--- a/drivers/media/video/gspca/jpeg.h
+++ b/drivers/media/video/gspca/jpeg.h
@@ -141,9 +141,9 @@ static void jpeg_define(u8 *jpeg_hdr,
memcpy(jpeg_hdr, jpeg_head, sizeof jpeg_head);
#ifndef CONEX_CAM
jpeg_hdr[JPEG_HEIGHT_OFFSET + 0] = height >> 8;
- jpeg_hdr[JPEG_HEIGHT_OFFSET + 1] = height & 0xff;
+ jpeg_hdr[JPEG_HEIGHT_OFFSET + 1] = height;
jpeg_hdr[JPEG_HEIGHT_OFFSET + 2] = width >> 8;
- jpeg_hdr[JPEG_HEIGHT_OFFSET + 3] = width & 0xff;
+ jpeg_hdr[JPEG_HEIGHT_OFFSET + 3] = width;
jpeg_hdr[JPEG_HEIGHT_OFFSET + 6] = samplesY;
#endif
}
diff --git a/drivers/media/video/gspca/konica.c b/drivers/media/video/gspca/konica.c
index d2ce65d..5964691 100644
--- a/drivers/media/video/gspca/konica.c
+++ b/drivers/media/video/gspca/konica.c
@@ -607,7 +607,7 @@ static const struct sd_desc sd_desc = {
};
/* -- module initialisation -- */
-static const __devinitdata struct usb_device_id device_table[] = {
+static const struct usb_device_id device_table[] = {
{USB_DEVICE(0x04c8, 0x0720)}, /* Intel YC 76 */
{}
};
diff --git a/drivers/media/video/gspca/m5602/m5602_core.c b/drivers/media/video/gspca/m5602/m5602_core.c
index c872b93..a7722b1 100644
--- a/drivers/media/video/gspca/m5602/m5602_core.c
+++ b/drivers/media/video/gspca/m5602/m5602_core.c
@@ -28,7 +28,7 @@ int force_sensor;
static int dump_bridge;
int dump_sensor;
-static const __devinitdata struct usb_device_id m5602_table[] = {
+static const struct usb_device_id m5602_table[] = {
{USB_DEVICE(0x0402, 0x5602)},
{}
};
diff --git a/drivers/media/video/gspca/mars.c b/drivers/media/video/gspca/mars.c
index a81536e..cb4d0bf 100644
--- a/drivers/media/video/gspca/mars.c
+++ b/drivers/media/video/gspca/mars.c
@@ -490,7 +490,7 @@ static const struct sd_desc sd_desc = {
};
/* -- module initialisation -- */
-static const __devinitdata struct usb_device_id device_table[] = {
+static const struct usb_device_id device_table[] = {
{USB_DEVICE(0x093a, 0x050f)},
{}
};
diff --git a/drivers/media/video/gspca/mr97310a.c b/drivers/media/video/gspca/mr97310a.c
index 7607a28..3884c9d 100644
--- a/drivers/media/video/gspca/mr97310a.c
+++ b/drivers/media/video/gspca/mr97310a.c
@@ -1229,7 +1229,7 @@ static const struct sd_desc sd_desc = {
};
/* -- module initialisation -- */
-static const __devinitdata struct usb_device_id device_table[] = {
+static const struct usb_device_id device_table[] = {
{USB_DEVICE(0x08ca, 0x0110)}, /* Trust Spyc@m 100 */
{USB_DEVICE(0x08ca, 0x0111)}, /* Aiptek Pencam VGA+ */
{USB_DEVICE(0x093a, 0x010f)}, /* All other known MR97310A VGA cams */
diff --git a/drivers/media/video/gspca/ov519.c b/drivers/media/video/gspca/ov519.c
index e1c3b93..8ab2c45 100644
--- a/drivers/media/video/gspca/ov519.c
+++ b/drivers/media/video/gspca/ov519.c
@@ -488,7 +488,6 @@ static const struct v4l2_pix_format ovfx2_ov3610_mode[] = {
#define R511_SNAP_PXDIV 0x1c
#define R511_SNAP_LNDIV 0x1d
#define R511_SNAP_UV_EN 0x1e
-#define R511_SNAP_UV_EN 0x1e
#define R511_SNAP_OPTS 0x1f
#define R511_DRAM_FLOW_CTL 0x20
@@ -1847,8 +1846,7 @@ static const struct ov_i2c_regvals norm_7670[] = {
{ 0x6c, 0x0a },
{ 0x6d, 0x55 },
{ 0x6e, 0x11 },
- { 0x6f, 0x9f },
- /* "9e for advance AWB" */
+ { 0x6f, 0x9f }, /* "9e for advance AWB" */
{ 0x6a, 0x40 },
{ OV7670_R01_BLUE, 0x40 },
{ OV7670_R02_RED, 0x60 },
@@ -3054,7 +3052,7 @@ static void ov519_configure(struct sd *sd)
{
static const struct ov_regvals init_519[] = {
{ 0x5a, 0x6d }, /* EnableSystem */
- { 0x53, 0x9b },
+ { 0x53, 0x9b }, /* don't enable the microcontroller */
{ OV519_R54_EN_CLK1, 0xff }, /* set bit2 to enable jpeg */
{ 0x5d, 0x03 },
{ 0x49, 0x01 },
@@ -4747,7 +4745,7 @@ static const struct sd_desc sd_desc = {
};
/* -- module initialisation -- */
-static const __devinitdata struct usb_device_id device_table[] = {
+static const struct usb_device_id device_table[] = {
{USB_DEVICE(0x041e, 0x4003), .driver_info = BRIDGE_W9968CF },
{USB_DEVICE(0x041e, 0x4052), .driver_info = BRIDGE_OV519 },
{USB_DEVICE(0x041e, 0x405f), .driver_info = BRIDGE_OV519 },
diff --git a/drivers/media/video/gspca/ov534.c b/drivers/media/video/gspca/ov534.c
index 0edf939..04da228 100644
--- a/drivers/media/video/gspca/ov534.c
+++ b/drivers/media/video/gspca/ov534.c
@@ -479,15 +479,20 @@ static void ov534_reg_write(struct gspca_dev *gspca_dev, u16 reg, u8 val)
struct usb_device *udev = gspca_dev->dev;
int ret;
- PDEBUG(D_USBO, "reg=0x%04x, val=0%02x", reg, val);
+ if (gspca_dev->usb_err < 0)
+ return;
+
+ PDEBUG(D_USBO, "SET 01 0000 %04x %02x", reg, val);
gspca_dev->usb_buf[0] = val;
ret = usb_control_msg(udev,
usb_sndctrlpipe(udev, 0),
0x01,
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
0x00, reg, gspca_dev->usb_buf, 1, CTRL_TIMEOUT);
- if (ret < 0)
+ if (ret < 0) {
err("write failed %d", ret);
+ gspca_dev->usb_err = ret;
+ }
}
static u8 ov534_reg_read(struct gspca_dev *gspca_dev, u16 reg)
@@ -495,14 +500,18 @@ static u8 ov534_reg_read(struct gspca_dev *gspca_dev, u16 reg)
struct usb_device *udev = gspca_dev->dev;
int ret;
+ if (gspca_dev->usb_err < 0)
+ return 0;
ret = usb_control_msg(udev,
usb_rcvctrlpipe(udev, 0),
0x01,
USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
0x00, reg, gspca_dev->usb_buf, 1, CTRL_TIMEOUT);
- PDEBUG(D_USBI, "reg=0x%04x, data=0x%02x", reg, gspca_dev->usb_buf[0]);
- if (ret < 0)
+ PDEBUG(D_USBI, "GET 01 0000 %04x %02x", reg, gspca_dev->usb_buf[0]);
+ if (ret < 0) {
err("read failed %d", ret);
+ gspca_dev->usb_err = ret;
+ }
return gspca_dev->usb_buf[0];
}
@@ -558,13 +567,15 @@ static int sccb_check_status(struct gspca_dev *gspca_dev)
static void sccb_reg_write(struct gspca_dev *gspca_dev, u8 reg, u8 val)
{
- PDEBUG(D_USBO, "reg: 0x%02x, val: 0x%02x", reg, val);
+ PDEBUG(D_USBO, "sccb write: %02x %02x", reg, val);
ov534_reg_write(gspca_dev, OV534_REG_SUBADDR, reg);
ov534_reg_write(gspca_dev, OV534_REG_WRITE, val);
ov534_reg_write(gspca_dev, OV534_REG_OPERATION, OV534_OP_WRITE_3);
- if (!sccb_check_status(gspca_dev))
+ if (!sccb_check_status(gspca_dev)) {
err("sccb_reg_write failed");
+ gspca_dev->usb_err = -EIO;
+ }
}
static u8 sccb_reg_read(struct gspca_dev *gspca_dev, u16 reg)
@@ -885,7 +896,7 @@ static int sd_init(struct gspca_dev *gspca_dev)
ov534_set_led(gspca_dev, 0);
set_frame_rate(gspca_dev);
- return 0;
+ return gspca_dev->usb_err;
}
static int sd_start(struct gspca_dev *gspca_dev)
@@ -920,7 +931,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
ov534_set_led(gspca_dev, 1);
ov534_reg_write(gspca_dev, 0xe0, 0x00);
- return 0;
+ return gspca_dev->usb_err;
}
static void sd_stopN(struct gspca_dev *gspca_dev)
@@ -1289,7 +1300,7 @@ static const struct sd_desc sd_desc = {
};
/* -- module initialisation -- */
-static const __devinitdata struct usb_device_id device_table[] = {
+static const struct usb_device_id device_table[] = {
{USB_DEVICE(0x1415, 0x2000)},
{}
};
diff --git a/drivers/media/video/gspca/ov534_9.c b/drivers/media/video/gspca/ov534_9.c
index c5244b4..aaf5428 100644
--- a/drivers/media/video/gspca/ov534_9.c
+++ b/drivers/media/video/gspca/ov534_9.c
@@ -1429,7 +1429,7 @@ static const struct sd_desc sd_desc = {
};
/* -- module initialisation -- */
-static const __devinitdata struct usb_device_id device_table[] = {
+static const struct usb_device_id device_table[] = {
{USB_DEVICE(0x06f8, 0x3003)},
{}
};
diff --git a/drivers/media/video/gspca/pac207.c b/drivers/media/video/gspca/pac207.c
index 96f9986..81739a2 100644
--- a/drivers/media/video/gspca/pac207.c
+++ b/drivers/media/video/gspca/pac207.c
@@ -530,7 +530,7 @@ static const struct sd_desc sd_desc = {
};
/* -- module initialisation -- */
-static const __devinitdata struct usb_device_id device_table[] = {
+static const struct usb_device_id device_table[] = {
{USB_DEVICE(0x041e, 0x4028)},
{USB_DEVICE(0x093a, 0x2460)},
{USB_DEVICE(0x093a, 0x2461)},
diff --git a/drivers/media/video/gspca/pac7302.c b/drivers/media/video/gspca/pac7302.c
index 2700975..5615d7b 100644
--- a/drivers/media/video/gspca/pac7302.c
+++ b/drivers/media/video/gspca/pac7302.c
@@ -1184,7 +1184,7 @@ static const struct sd_desc sd_desc = {
};
/* -- module initialisation -- */
-static const struct usb_device_id device_table[] __devinitconst = {
+static const struct usb_device_id device_table[] = {
{USB_DEVICE(0x06f8, 0x3009)},
{USB_DEVICE(0x093a, 0x2620)},
{USB_DEVICE(0x093a, 0x2621)},
@@ -1201,7 +1201,7 @@ static const struct usb_device_id device_table[] __devinitconst = {
MODULE_DEVICE_TABLE(usb, device_table);
/* -- device connect -- */
-static int __devinit sd_probe(struct usb_interface *intf,
+static int sd_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
diff --git a/drivers/media/video/gspca/pac7311.c b/drivers/media/video/gspca/pac7311.c
index 6820f5d..f8801b5 100644
--- a/drivers/media/video/gspca/pac7311.c
+++ b/drivers/media/video/gspca/pac7311.c
@@ -837,7 +837,7 @@ static const struct sd_desc sd_desc = {
};
/* -- module initialisation -- */
-static const struct usb_device_id device_table[] __devinitconst = {
+static const struct usb_device_id device_table[] = {
{USB_DEVICE(0x093a, 0x2600)},
{USB_DEVICE(0x093a, 0x2601)},
{USB_DEVICE(0x093a, 0x2603)},
@@ -849,7 +849,7 @@ static const struct usb_device_id device_table[] __devinitconst = {
MODULE_DEVICE_TABLE(usb, device_table);
/* -- device connect -- */
-static int __devinit sd_probe(struct usb_interface *intf,
+static int sd_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
diff --git a/drivers/media/video/gspca/sn9c2028.c b/drivers/media/video/gspca/sn9c2028.c
index 40a0668..4271f86 100644
--- a/drivers/media/video/gspca/sn9c2028.c
+++ b/drivers/media/video/gspca/sn9c2028.c
@@ -703,7 +703,7 @@ static const struct sd_desc sd_desc = {
};
/* -- module initialisation -- */
-static const __devinitdata struct usb_device_id device_table[] = {
+static const struct usb_device_id device_table[] = {
{USB_DEVICE(0x0458, 0x7005)}, /* Genius Smart 300, version 2 */
/* The Genius Smart is untested. I can't find an owner ! */
/* {USB_DEVICE(0x0c45, 0x8000)}, DC31VC, Don't know this camera */
diff --git a/drivers/media/video/gspca/sn9c20x.c b/drivers/media/video/gspca/sn9c20x.c
index cb08d00..fcf2989 100644
--- a/drivers/media/video/gspca/sn9c20x.c
+++ b/drivers/media/video/gspca/sn9c20x.c
@@ -2470,7 +2470,7 @@ static const struct sd_desc sd_desc = {
| (SENSOR_ ## sensor << 8) \
| (i2c_addr)
-static const __devinitdata struct usb_device_id device_table[] = {
+static const struct usb_device_id device_table[] = {
{USB_DEVICE(0x0c45, 0x6240), SN9C20X(MT9M001, 0x5d, 0)},
{USB_DEVICE(0x0c45, 0x6242), SN9C20X(MT9M111, 0x5d, 0)},
{USB_DEVICE(0x0c45, 0x6248), SN9C20X(OV9655, 0x30, 0)},
diff --git a/drivers/media/video/gspca/sonixb.c b/drivers/media/video/gspca/sonixb.c
index 73504a3..c6cd68d 100644
--- a/drivers/media/video/gspca/sonixb.c
+++ b/drivers/media/video/gspca/sonixb.c
@@ -23,8 +23,15 @@
/* Some documentation on known sonixb registers:
Reg Use
+sn9c101 / sn9c102:
0x10 high nibble red gain low nibble blue gain
0x11 low nibble green gain
+sn9c103:
+0x05 red gain 0-127
+0x06 blue gain 0-127
+0x07 green gain 0-127
+all:
+0x08-0x0f i2c / 3wire registers
0x12 hstart
0x13 vstart
0x15 hsize (hsize = register-value * 16)
@@ -88,12 +95,9 @@ struct sd {
typedef const __u8 sensor_init_t[8];
struct sensor_data {
- const __u8 *bridge_init[2];
- int bridge_init_size[2];
+ const __u8 *bridge_init;
sensor_init_t *sensor_init;
int sensor_init_size;
- sensor_init_t *sensor_bridge_init[2];
- int sensor_bridge_init_size[2];
int flags;
unsigned ctrl_dis;
__u8 sensor_addr;
@@ -114,7 +118,6 @@ struct sensor_data {
#define NO_FREQ (1 << FREQ_IDX)
#define NO_BRIGHTNESS (1 << BRIGHTNESS_IDX)
-#define COMP2 0x8f
#define COMP 0xc7 /* 0x87 //0x07 */
#define COMP1 0xc9 /* 0x89 //0x09 */
@@ -123,15 +126,11 @@ struct sensor_data {
#define SYS_CLK 0x04
-#define SENS(bridge_1, bridge_3, sensor, sensor_1, \
- sensor_3, _flags, _ctrl_dis, _sensor_addr) \
+#define SENS(bridge, sensor, _flags, _ctrl_dis, _sensor_addr) \
{ \
- .bridge_init = { bridge_1, bridge_3 }, \
- .bridge_init_size = { sizeof(bridge_1), sizeof(bridge_3) }, \
+ .bridge_init = bridge, \
.sensor_init = sensor, \
.sensor_init_size = sizeof(sensor), \
- .sensor_bridge_init = { sensor_1, sensor_3,}, \
- .sensor_bridge_init_size = { sizeof(sensor_1), sizeof(sensor_3)}, \
.flags = _flags, .ctrl_dis = _ctrl_dis, .sensor_addr = _sensor_addr \
}
@@ -311,7 +310,6 @@ static const __u8 initHv7131d[] = {
0x00, 0x00,
0x00, 0x00, 0x00, 0x02, 0x02, 0x00,
0x28, 0x1e, 0x60, 0x8e, 0x42,
- 0x1d, 0x10, 0x02, 0x03, 0x0f, 0x0c
};
static const __u8 hv7131d_sensor_init[][8] = {
{0xa0, 0x11, 0x01, 0x04, 0x00, 0x00, 0x00, 0x17},
@@ -326,7 +324,6 @@ static const __u8 initHv7131r[] = {
0x00, 0x00,
0x00, 0x00, 0x00, 0x02, 0x01, 0x00,
0x28, 0x1e, 0x60, 0x8a, 0x20,
- 0x1d, 0x10, 0x02, 0x03, 0x0f, 0x0c
};
static const __u8 hv7131r_sensor_init[][8] = {
{0xc0, 0x11, 0x31, 0x38, 0x2a, 0x2e, 0x00, 0x10},
@@ -339,7 +336,7 @@ static const __u8 initOv6650[] = {
0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x01, 0x01, 0x0a, 0x16, 0x12, 0x68, 0x8b,
- 0x10, 0x1d, 0x10, 0x02, 0x02, 0x09, 0x07
+ 0x10,
};
static const __u8 ov6650_sensor_init[][8] = {
/* Bright, contrast, etc are set through SCBB interface.
@@ -378,24 +375,13 @@ static const __u8 initOv7630[] = {
0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* r09 .. r10 */
0x00, 0x01, 0x01, 0x0a, /* r11 .. r14 */
0x28, 0x1e, /* H & V sizes r15 .. r16 */
- 0x68, COMP2, MCK_INIT1, /* r17 .. r19 */
- 0x1d, 0x10, 0x02, 0x03, 0x0f, 0x0c /* r1a .. r1f */
-};
-static const __u8 initOv7630_3[] = {
- 0x44, 0x44, 0x00, 0x1a, 0x20, 0x20, 0x20, 0x80, /* r01 .. r08 */
- 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* r09 .. r10 */
- 0x00, 0x02, 0x01, 0x0a, /* r11 .. r14 */
- 0x28, 0x1e, /* H & V sizes r15 .. r16 */
0x68, 0x8f, MCK_INIT1, /* r17 .. r19 */
- 0x1d, 0x10, 0x02, 0x03, 0x0f, 0x0c, 0x00, /* r1a .. r20 */
- 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, /* r21 .. r28 */
- 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0, 0xff /* r29 .. r30 */
};
static const __u8 ov7630_sensor_init[][8] = {
{0xa0, 0x21, 0x12, 0x80, 0x00, 0x00, 0x00, 0x10},
{0xb0, 0x21, 0x01, 0x77, 0x3a, 0x00, 0x00, 0x10},
/* {0xd0, 0x21, 0x12, 0x7c, 0x01, 0x80, 0x34, 0x10}, jfm */
- {0xd0, 0x21, 0x12, 0x1c, 0x00, 0x80, 0x34, 0x10}, /* jfm */
+ {0xd0, 0x21, 0x12, 0x5c, 0x00, 0x80, 0x34, 0x10}, /* jfm */
{0xa0, 0x21, 0x1b, 0x04, 0x00, 0x80, 0x34, 0x10},
{0xa0, 0x21, 0x20, 0x44, 0x00, 0x80, 0x34, 0x10},
{0xa0, 0x21, 0x23, 0xee, 0x00, 0x80, 0x34, 0x10},
@@ -413,16 +399,11 @@ static const __u8 ov7630_sensor_init[][8] = {
{0xd0, 0x21, 0x17, 0x1c, 0xbd, 0x06, 0xf6, 0x10},
};
-static const __u8 ov7630_sensor_init_3[][8] = {
- {0xa0, 0x21, 0x13, 0x80, 0x00, 0x00, 0x00, 0x10},
-};
-
static const __u8 initPas106[] = {
0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x40, 0x00, 0x00, 0x00,
0x00, 0x00,
0x00, 0x00, 0x00, 0x04, 0x01, 0x00,
0x16, 0x12, 0x24, COMP1, MCK_INIT1,
- 0x18, 0x10, 0x02, 0x02, 0x09, 0x07
};
/* compression 0x86 mckinit1 0x2b */
@@ -496,7 +477,6 @@ static const __u8 initPas202[] = {
0x00, 0x00,
0x00, 0x00, 0x00, 0x06, 0x03, 0x0a,
0x28, 0x1e, 0x20, 0x89, 0x20,
- 0x00, 0x00, 0x02, 0x03, 0x0f, 0x0c
};
/* "Known" PAS202BCB registers:
@@ -537,7 +517,6 @@ static const __u8 initTas5110c[] = {
0x00, 0x00,
0x00, 0x00, 0x00, 0x45, 0x09, 0x0a,
0x16, 0x12, 0x60, 0x86, 0x2b,
- 0x14, 0x0a, 0x02, 0x02, 0x09, 0x07
};
/* Same as above, except a different hstart */
static const __u8 initTas5110d[] = {
@@ -545,12 +524,19 @@ static const __u8 initTas5110d[] = {
0x00, 0x00,
0x00, 0x00, 0x00, 0x41, 0x09, 0x0a,
0x16, 0x12, 0x60, 0x86, 0x2b,
- 0x14, 0x0a, 0x02, 0x02, 0x09, 0x07
};
-static const __u8 tas5110_sensor_init[][8] = {
+/* tas5110c is 3 wire, tas5110d is 2 wire (regular i2c) */
+static const __u8 tas5110c_sensor_init[][8] = {
{0x30, 0x11, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x10},
{0x30, 0x11, 0x02, 0x20, 0xa9, 0x00, 0x00, 0x10},
- {0xa0, 0x61, 0x9a, 0xca, 0x00, 0x00, 0x00, 0x17},
+};
+/* Known TAS5110D registers
+ * reg02: gain, bit order reversed!! 0 == max gain, 255 == min gain
+ * reg03: bit3: vflip, bit4: ~hflip, bit7: ~gainboost (~ == inverted)
+ * Note: writing reg03 seems to only work when written together with 02
+ */
+static const __u8 tas5110d_sensor_init[][8] = {
+ {0xa0, 0x61, 0x9a, 0xca, 0x00, 0x00, 0x00, 0x17}, /* reset */
};
static const __u8 initTas5130[] = {
@@ -558,7 +544,6 @@ static const __u8 initTas5130[] = {
0x00, 0x00,
0x00, 0x00, 0x00, 0x68, 0x0c, 0x0a,
0x28, 0x1e, 0x60, COMP, MCK_INIT,
- 0x18, 0x10, 0x04, 0x03, 0x11, 0x0c
};
static const __u8 tas5130_sensor_init[][8] = {
/* {0x30, 0x11, 0x00, 0x40, 0x47, 0x00, 0x00, 0x10},
@@ -569,21 +554,18 @@ static const __u8 tas5130_sensor_init[][8] = {
};
static struct sensor_data sensor_data[] = {
-SENS(initHv7131d, NULL, hv7131d_sensor_init, NULL, NULL, F_GAIN, NO_BRIGHTNESS|NO_FREQ, 0),
-SENS(initHv7131r, NULL, hv7131r_sensor_init, NULL, NULL, 0, NO_BRIGHTNESS|NO_EXPO|NO_FREQ, 0),
-SENS(initOv6650, NULL, ov6650_sensor_init, NULL, NULL, F_GAIN|F_SIF, 0, 0x60),
-SENS(initOv7630, initOv7630_3, ov7630_sensor_init, NULL, ov7630_sensor_init_3,
- F_GAIN, 0, 0x21),
-SENS(initPas106, NULL, pas106_sensor_init, NULL, NULL, F_GAIN|F_SIF, NO_FREQ,
- 0),
-SENS(initPas202, initPas202, pas202_sensor_init, NULL, NULL, F_GAIN,
- NO_FREQ, 0),
-SENS(initTas5110c, NULL, tas5110_sensor_init, NULL, NULL,
- F_GAIN|F_SIF|F_COARSE_EXPO, NO_BRIGHTNESS|NO_FREQ, 0),
-SENS(initTas5110d, NULL, tas5110_sensor_init, NULL, NULL,
- F_GAIN|F_SIF|F_COARSE_EXPO, NO_BRIGHTNESS|NO_FREQ, 0),
-SENS(initTas5130, NULL, tas5130_sensor_init, NULL, NULL, 0, NO_EXPO|NO_FREQ,
- 0),
+SENS(initHv7131d, hv7131d_sensor_init, F_GAIN, NO_BRIGHTNESS|NO_FREQ, 0),
+SENS(initHv7131r, hv7131r_sensor_init, 0, NO_BRIGHTNESS|NO_EXPO|NO_FREQ, 0),
+SENS(initOv6650, ov6650_sensor_init, F_GAIN|F_SIF, 0, 0x60),
+SENS(initOv7630, ov7630_sensor_init, F_GAIN, 0, 0x21),
+SENS(initPas106, pas106_sensor_init, F_GAIN|F_SIF, NO_FREQ, 0),
+SENS(initPas202, pas202_sensor_init, F_GAIN, NO_FREQ, 0),
+SENS(initTas5110c, tas5110c_sensor_init, F_GAIN|F_SIF|F_COARSE_EXPO,
+ NO_BRIGHTNESS|NO_FREQ, 0),
+SENS(initTas5110d, tas5110d_sensor_init, F_GAIN|F_SIF|F_COARSE_EXPO,
+ NO_BRIGHTNESS|NO_FREQ, 0),
+SENS(initTas5130, tas5130_sensor_init, F_GAIN,
+ NO_BRIGHTNESS|NO_EXPO|NO_FREQ, 0),
};
/* get one byte in gspca_dev->usb_buf */
@@ -655,7 +637,6 @@ static void i2c_w_vector(struct gspca_dev *gspca_dev,
static void setbrightness(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- __u8 value;
switch (sd->sensor) {
case SENSOR_OV6650:
@@ -697,17 +678,6 @@ static void setbrightness(struct gspca_dev *gspca_dev)
goto err;
break;
}
- case SENSOR_TAS5130CXX: {
- __u8 i2c[] =
- {0x30, 0x11, 0x02, 0x20, 0x70, 0x00, 0x00, 0x10};
-
- value = 0xff - sd->brightness;
- i2c[4] = value;
- PDEBUG(D_CONF, "brightness %d : %d", value, i2c[4]);
- if (i2c_w(gspca_dev, i2c) < 0)
- goto err;
- break;
- }
}
return;
err:
@@ -733,7 +703,7 @@ static void setsensorgain(struct gspca_dev *gspca_dev)
break;
}
case SENSOR_TAS5110C:
- case SENSOR_TAS5110D: {
+ case SENSOR_TAS5130CXX: {
__u8 i2c[] =
{0x30, 0x11, 0x02, 0x20, 0x70, 0x00, 0x00, 0x10};
@@ -742,6 +712,23 @@ static void setsensorgain(struct gspca_dev *gspca_dev)
goto err;
break;
}
+ case SENSOR_TAS5110D: {
+ __u8 i2c[] = {
+ 0xb0, 0x61, 0x02, 0x00, 0x10, 0x00, 0x00, 0x17 };
+ gain = 255 - gain;
+ /* The bits in the register are the wrong way around!! */
+ i2c[3] |= (gain & 0x80) >> 7;
+ i2c[3] |= (gain & 0x40) >> 5;
+ i2c[3] |= (gain & 0x20) >> 3;
+ i2c[3] |= (gain & 0x10) >> 1;
+ i2c[3] |= (gain & 0x08) << 1;
+ i2c[3] |= (gain & 0x04) << 3;
+ i2c[3] |= (gain & 0x02) << 5;
+ i2c[3] |= (gain & 0x01) << 7;
+ if (i2c_w(gspca_dev, i2c) < 0)
+ goto err;
+ break;
+ }
case SENSOR_OV6650:
gain >>= 1;
@@ -796,7 +783,7 @@ static void setgain(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
__u8 gain;
- __u8 buf[2] = { 0, 0 };
+ __u8 buf[3] = { 0, 0, 0 };
if (sensor_data[sd->sensor].flags & F_GAIN) {
/* Use the sensor gain to do the actual gain */
@@ -804,13 +791,18 @@ static void setgain(struct gspca_dev *gspca_dev)
return;
}
- gain = sd->gain >> 4;
-
- /* red and blue gain */
- buf[0] = gain << 4 | gain;
- /* green gain */
- buf[1] = gain;
- reg_w(gspca_dev, 0x10, buf, 2);
+ if (sd->bridge == BRIDGE_103) {
+ gain = sd->gain >> 1;
+ buf[0] = gain; /* Red */
+ buf[1] = gain; /* Green */
+ buf[2] = gain; /* Blue */
+ reg_w(gspca_dev, 0x05, buf, 3);
+ } else {
+ gain = sd->gain >> 4;
+ buf[0] = gain << 4 | gain; /* Red and blue */
+ buf[1] = gain; /* Green */
+ reg_w(gspca_dev, 0x10, buf, 2);
+ }
}
static void setexposure(struct gspca_dev *gspca_dev)
@@ -1049,7 +1041,7 @@ static void do_autogain(struct gspca_dev *gspca_dev)
desired_avg_lum = 5000;
} else {
deadzone = 1500;
- desired_avg_lum = 18000;
+ desired_avg_lum = 13000;
}
if (sensor_data[sd->sensor].flags & F_COARSE_EXPO)
@@ -1127,53 +1119,91 @@ static int sd_start(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
struct cam *cam = &gspca_dev->cam;
- int mode, l;
- const __u8 *sn9c10x;
- __u8 reg12_19[8];
+ int i, mode;
+ __u8 regs[0x31];
mode = cam->cam_mode[gspca_dev->curr_mode].priv & 0x07;
- sn9c10x = sensor_data[sd->sensor].bridge_init[sd->bridge];
- l = sensor_data[sd->sensor].bridge_init_size[sd->bridge];
- memcpy(reg12_19, &sn9c10x[0x12 - 1], 8);
- reg12_19[6] = sn9c10x[0x18 - 1] | (mode << 4);
- /* Special cases where reg 17 and or 19 value depends on mode */
+ /* Copy registers 0x01 - 0x19 from the template */
+ memcpy(&regs[0x01], sensor_data[sd->sensor].bridge_init, 0x19);
+ /* Set the mode */
+ regs[0x18] |= mode << 4;
+
+ /* Set bridge gain to 1.0 */
+ if (sd->bridge == BRIDGE_103) {
+ regs[0x05] = 0x20; /* Red */
+ regs[0x06] = 0x20; /* Green */
+ regs[0x07] = 0x20; /* Blue */
+ } else {
+ regs[0x10] = 0x00; /* Red and blue */
+ regs[0x11] = 0x00; /* Green */
+ }
+
+ /* Setup pixel numbers and auto exposure window */
+ if (sensor_data[sd->sensor].flags & F_SIF) {
+ regs[0x1a] = 0x14; /* HO_SIZE 640, makes no sense */
+ regs[0x1b] = 0x0a; /* VO_SIZE 320, makes no sense */
+ regs[0x1c] = 0x02; /* AE H-start 64 */
+ regs[0x1d] = 0x02; /* AE V-start 64 */
+ regs[0x1e] = 0x09; /* AE H-end 288 */
+ regs[0x1f] = 0x07; /* AE V-end 224 */
+ } else {
+ regs[0x1a] = 0x1d; /* HO_SIZE 960, makes no sense */
+ regs[0x1b] = 0x10; /* VO_SIZE 512, makes no sense */
+ regs[0x1c] = 0x05; /* AE H-start 160 */
+ regs[0x1d] = 0x03; /* AE V-start 96 */
+ regs[0x1e] = 0x0f; /* AE H-end 480 */
+ regs[0x1f] = 0x0c; /* AE V-end 384 */
+ }
+
+ /* Setup the gamma table (only used with the sn9c103 bridge) */
+ for (i = 0; i < 16; i++)
+ regs[0x20 + i] = i * 16;
+ regs[0x20 + i] = 255;
+
+ /* Special cases where some regs depend on mode or bridge */
switch (sd->sensor) {
case SENSOR_TAS5130CXX:
- /* probably not mode specific at all most likely the upper
+ /* FIXME / TESTME
+ probably not mode specific at all most likely the upper
nibble of 0x19 is exposure (clock divider) just as with
the tas5110, we need someone to test this. */
- reg12_19[7] = mode ? 0x23 : 0x43;
+ regs[0x19] = mode ? 0x23 : 0x43;
break;
+ case SENSOR_OV7630:
+ /* FIXME / TESTME for some reason with the 101/102 bridge the
+ clock is set to 12 Mhz (reg1 == 0x04), rather then 24.
+ Also the hstart needs to go from 1 to 2 when using a 103,
+ which is likely related. This does not seem right. */
+ if (sd->bridge == BRIDGE_103) {
+ regs[0x01] = 0x44; /* Select 24 Mhz clock */
+ regs[0x12] = 0x02; /* Set hstart to 2 */
+ }
}
/* Disable compression when the raw bayer format has been selected */
if (cam->cam_mode[gspca_dev->curr_mode].priv & MODE_RAW)
- reg12_19[6] &= ~0x80;
+ regs[0x18] &= ~0x80;
/* Vga mode emulation on SIF sensor? */
if (cam->cam_mode[gspca_dev->curr_mode].priv & MODE_REDUCED_SIF) {
- reg12_19[0] += 16; /* 0x12: hstart adjust */
- reg12_19[1] += 24; /* 0x13: vstart adjust */
- reg12_19[3] = 320 / 16; /* 0x15: hsize */
- reg12_19[4] = 240 / 16; /* 0x16: vsize */
+ regs[0x12] += 16; /* hstart adjust */
+ regs[0x13] += 24; /* vstart adjust */
+ regs[0x15] = 320 / 16; /* hsize */
+ regs[0x16] = 240 / 16; /* vsize */
}
/* reg 0x01 bit 2 video transfert on */
- reg_w(gspca_dev, 0x01, &sn9c10x[0x01 - 1], 1);
+ reg_w(gspca_dev, 0x01, &regs[0x01], 1);
/* reg 0x17 SensorClk enable inv Clk 0x60 */
- reg_w(gspca_dev, 0x17, &sn9c10x[0x17 - 1], 1);
+ reg_w(gspca_dev, 0x17, &regs[0x17], 1);
/* Set the registers from the template */
- reg_w(gspca_dev, 0x01, sn9c10x, l);
+ reg_w(gspca_dev, 0x01, &regs[0x01],
+ (sd->bridge == BRIDGE_103) ? 0x30 : 0x1f);
/* Init the sensor */
i2c_w_vector(gspca_dev, sensor_data[sd->sensor].sensor_init,
sensor_data[sd->sensor].sensor_init_size);
- if (sensor_data[sd->sensor].sensor_bridge_init[sd->bridge])
- i2c_w_vector(gspca_dev,
- sensor_data[sd->sensor].sensor_bridge_init[sd->bridge],
- sensor_data[sd->sensor].sensor_bridge_init_size[
- sd->bridge]);
- /* Mode specific sensor setup */
+ /* Mode / bridge specific sensor setup */
switch (sd->sensor) {
case SENSOR_PAS202: {
const __u8 i2cpclockdiv[] =
@@ -1181,27 +1211,37 @@ static int sd_start(struct gspca_dev *gspca_dev)
/* clockdiv from 4 to 3 (7.5 -> 10 fps) when in low res mode */
if (mode)
i2c_w(gspca_dev, i2cpclockdiv);
+ break;
}
+ case SENSOR_OV7630:
+ /* FIXME / TESTME We should be able to handle this identical
+ for the 101/102 and the 103 case */
+ if (sd->bridge == BRIDGE_103) {
+ const __u8 i2c[] = { 0xa0, 0x21, 0x13,
+ 0x80, 0x00, 0x00, 0x00, 0x10 };
+ i2c_w(gspca_dev, i2c);
+ }
+ break;
}
/* H_size V_size 0x28, 0x1e -> 640x480. 0x16, 0x12 -> 352x288 */
- reg_w(gspca_dev, 0x15, &reg12_19[3], 2);
+ reg_w(gspca_dev, 0x15, &regs[0x15], 2);
/* compression register */
- reg_w(gspca_dev, 0x18, &reg12_19[6], 1);
+ reg_w(gspca_dev, 0x18, &regs[0x18], 1);
/* H_start */
- reg_w(gspca_dev, 0x12, &reg12_19[0], 1);
+ reg_w(gspca_dev, 0x12, &regs[0x12], 1);
/* V_START */
- reg_w(gspca_dev, 0x13, &reg12_19[1], 1);
+ reg_w(gspca_dev, 0x13, &regs[0x13], 1);
/* reset 0x17 SensorClk enable inv Clk 0x60 */
/*fixme: ov7630 [17]=68 8f (+20 if 102)*/
- reg_w(gspca_dev, 0x17, &reg12_19[5], 1);
+ reg_w(gspca_dev, 0x17, &regs[0x17], 1);
/*MCKSIZE ->3 */ /*fixme: not ov7630*/
- reg_w(gspca_dev, 0x19, &reg12_19[7], 1);
+ reg_w(gspca_dev, 0x19, &regs[0x19], 1);
/* AE_STRX AE_STRY AE_ENDX AE_ENDY */
- reg_w(gspca_dev, 0x1c, &sn9c10x[0x1c - 1], 4);
+ reg_w(gspca_dev, 0x1c, &regs[0x1c], 4);
/* Enable video transfert */
- reg_w(gspca_dev, 0x01, &sn9c10x[0], 1);
+ reg_w(gspca_dev, 0x01, &regs[0x01], 1);
/* Compression */
- reg_w(gspca_dev, 0x18, &reg12_19[6], 2);
+ reg_w(gspca_dev, 0x18, &regs[0x18], 2);
msleep(20);
sd->reg11 = -1;
@@ -1525,15 +1565,15 @@ static const struct sd_desc sd_desc = {
.driver_info = (SENSOR_ ## sensor << 8) | BRIDGE_ ## bridge
-static const struct usb_device_id device_table[] __devinitconst = {
+static const struct usb_device_id device_table[] = {
{USB_DEVICE(0x0c45, 0x6001), SB(TAS5110C, 102)}, /* TAS5110C1B */
{USB_DEVICE(0x0c45, 0x6005), SB(TAS5110C, 101)}, /* TAS5110C1B */
{USB_DEVICE(0x0c45, 0x6007), SB(TAS5110D, 101)}, /* TAS5110D */
{USB_DEVICE(0x0c45, 0x6009), SB(PAS106, 101)},
{USB_DEVICE(0x0c45, 0x600d), SB(PAS106, 101)},
{USB_DEVICE(0x0c45, 0x6011), SB(OV6650, 101)},
-#if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE
{USB_DEVICE(0x0c45, 0x6019), SB(OV7630, 101)},
+#if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE
{USB_DEVICE(0x0c45, 0x6024), SB(TAS5130CXX, 102)},
{USB_DEVICE(0x0c45, 0x6025), SB(TAS5130CXX, 102)},
#endif
@@ -1544,18 +1584,22 @@ static const struct usb_device_id device_table[] __devinitconst = {
{USB_DEVICE(0x0c45, 0x602c), SB(OV7630, 102)},
{USB_DEVICE(0x0c45, 0x602d), SB(HV7131R, 102)},
{USB_DEVICE(0x0c45, 0x602e), SB(OV7630, 102)},
- /* {USB_DEVICE(0x0c45, 0x602b), SB(MI03XX, 102)}, */ /* MI0343 MI0360 MI0330 */
+ /* {USB_DEVICE(0x0c45, 0x6030), SB(MI03XX, 102)}, */ /* MI0343 MI0360 MI0330 */
+ /* {USB_DEVICE(0x0c45, 0x6082), SB(MI03XX, 103)}, */ /* MI0343 MI0360 */
+ {USB_DEVICE(0x0c45, 0x6083), SB(HV7131D, 103)},
+ {USB_DEVICE(0x0c45, 0x608c), SB(HV7131R, 103)},
+ /* {USB_DEVICE(0x0c45, 0x608e), SB(CISVF10, 103)}, */
{USB_DEVICE(0x0c45, 0x608f), SB(OV7630, 103)},
-#if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE
+ {USB_DEVICE(0x0c45, 0x60a8), SB(PAS106, 103)},
+ {USB_DEVICE(0x0c45, 0x60aa), SB(TAS5130CXX, 103)},
{USB_DEVICE(0x0c45, 0x60af), SB(PAS202, 103)},
-#endif
{USB_DEVICE(0x0c45, 0x60b0), SB(OV7630, 103)},
{}
};
MODULE_DEVICE_TABLE(usb, device_table);
/* -- device connect -- */
-static int __devinit sd_probe(struct usb_interface *intf,
+static int sd_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
diff --git a/drivers/media/video/gspca/sonixj.c b/drivers/media/video/gspca/sonixj.c
index 2d0bb17..d6f39ce 100644
--- a/drivers/media/video/gspca/sonixj.c
+++ b/drivers/media/video/gspca/sonixj.c
@@ -25,12 +25,12 @@
#include "gspca.h"
#include "jpeg.h"
-#define V4L2_CID_INFRARED (V4L2_CID_PRIVATE_BASE + 0)
-
MODULE_AUTHOR("Jean-François Moine <http://moinejf.free.fr>");
MODULE_DESCRIPTION("GSPCA/SONIX JPEG USB Camera Driver");
MODULE_LICENSE("GPL");
+static int starcam;
+
/* controls */
enum e_ctrl {
BRIGHTNESS,
@@ -43,7 +43,7 @@ enum e_ctrl {
HFLIP,
VFLIP,
SHARPNESS,
- INFRARED,
+ ILLUM,
FREQ,
NCTRLS /* number of controls */
};
@@ -100,7 +100,8 @@ enum sensors {
};
/* device flags */
-#define PDN_INV 1 /* inverse pin S_PWR_DN / sn_xxx tables */
+#define F_PDN_INV 0x01 /* inverse pin S_PWR_DN / sn_xxx tables */
+#define F_ILLUM 0x02 /* presence of illuminator */
/* sn9c1xx definitions */
/* register 0x01 */
@@ -124,7 +125,7 @@ static void setgamma(struct gspca_dev *gspca_dev);
static void setautogain(struct gspca_dev *gspca_dev);
static void sethvflip(struct gspca_dev *gspca_dev);
static void setsharpness(struct gspca_dev *gspca_dev);
-static void setinfrared(struct gspca_dev *gspca_dev);
+static void setillum(struct gspca_dev *gspca_dev);
static void setfreq(struct gspca_dev *gspca_dev);
static const struct ctrl sd_ctrls[NCTRLS] = {
@@ -251,18 +252,17 @@ static const struct ctrl sd_ctrls[NCTRLS] = {
},
.set_control = setsharpness
},
-/* mt9v111 only */
-[INFRARED] = {
+[ILLUM] = {
{
- .id = V4L2_CID_INFRARED,
+ .id = V4L2_CID_ILLUMINATORS_1,
.type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "Infrared",
+ .name = "Illuminator / infrared",
.minimum = 0,
.maximum = 1,
.step = 1,
.default_value = 0,
},
- .set_control = setinfrared
+ .set_control = setillum
},
/* ov7630/ov7648/ov7660 only */
[FREQ] = {
@@ -282,32 +282,26 @@ static const struct ctrl sd_ctrls[NCTRLS] = {
/* table of the disabled controls */
static const __u32 ctrl_dis[] = {
[SENSOR_ADCM1700] = (1 << AUTOGAIN) |
- (1 << INFRARED) |
(1 << HFLIP) |
(1 << VFLIP) |
(1 << FREQ),
-[SENSOR_GC0307] = (1 << INFRARED) |
- (1 << HFLIP) |
+[SENSOR_GC0307] = (1 << HFLIP) |
(1 << VFLIP) |
(1 << FREQ),
-[SENSOR_HV7131R] = (1 << INFRARED) |
- (1 << HFLIP) |
+[SENSOR_HV7131R] = (1 << HFLIP) |
(1 << FREQ),
-[SENSOR_MI0360] = (1 << INFRARED) |
- (1 << HFLIP) |
+[SENSOR_MI0360] = (1 << HFLIP) |
(1 << VFLIP) |
(1 << FREQ),
-[SENSOR_MI0360B] = (1 << INFRARED) |
- (1 << HFLIP) |
+[SENSOR_MI0360B] = (1 << HFLIP) |
(1 << VFLIP) |
(1 << FREQ),
-[SENSOR_MO4000] = (1 << INFRARED) |
- (1 << HFLIP) |
+[SENSOR_MO4000] = (1 << HFLIP) |
(1 << VFLIP) |
(1 << FREQ),
@@ -315,40 +309,32 @@ static const __u32 ctrl_dis[] = {
(1 << VFLIP) |
(1 << FREQ),
-[SENSOR_OM6802] = (1 << INFRARED) |
- (1 << HFLIP) |
+[SENSOR_OM6802] = (1 << HFLIP) |
(1 << VFLIP) |
(1 << FREQ),
-[SENSOR_OV7630] = (1 << INFRARED) |
- (1 << HFLIP),
+[SENSOR_OV7630] = (1 << HFLIP),
-[SENSOR_OV7648] = (1 << INFRARED) |
- (1 << HFLIP),
+[SENSOR_OV7648] = (1 << HFLIP),
[SENSOR_OV7660] = (1 << AUTOGAIN) |
- (1 << INFRARED) |
(1 << HFLIP) |
(1 << VFLIP),
[SENSOR_PO1030] = (1 << AUTOGAIN) |
- (1 << INFRARED) |
(1 << HFLIP) |
(1 << VFLIP) |
(1 << FREQ),
[SENSOR_PO2030N] = (1 << AUTOGAIN) |
- (1 << INFRARED) |
(1 << FREQ),
[SENSOR_SOI768] = (1 << AUTOGAIN) |
- (1 << INFRARED) |
(1 << HFLIP) |
(1 << VFLIP) |
(1 << FREQ),
[SENSOR_SP80708] = (1 << AUTOGAIN) |
- (1 << INFRARED) |
(1 << HFLIP) |
(1 << VFLIP) |
(1 << FREQ),
@@ -1822,44 +1808,46 @@ static int sd_init(struct gspca_dev *gspca_dev)
PDEBUG(D_PROBE, "Sonix chip id: %02x", regF1);
switch (sd->bridge) {
case BRIDGE_SN9C102P:
+ case BRIDGE_SN9C105:
if (regF1 != 0x11)
return -ENODEV;
+ break;
+ default:
+/* case BRIDGE_SN9C110: */
+/* case BRIDGE_SN9C120: */
+ if (regF1 != 0x12)
+ return -ENODEV;
+ }
+
+ switch (sd->sensor) {
+ case SENSOR_MI0360:
+ mi0360_probe(gspca_dev);
+ break;
+ case SENSOR_OV7630:
+ ov7630_probe(gspca_dev);
+ break;
+ case SENSOR_OV7648:
+ ov7648_probe(gspca_dev);
+ break;
+ case SENSOR_PO2030N:
+ po2030n_probe(gspca_dev);
+ break;
+ }
+
+ switch (sd->bridge) {
+ case BRIDGE_SN9C102P:
reg_w1(gspca_dev, 0x02, regGpio[1]);
break;
case BRIDGE_SN9C105:
- if (regF1 != 0x11)
- return -ENODEV;
- if (sd->sensor == SENSOR_MI0360)
- mi0360_probe(gspca_dev);
reg_w(gspca_dev, 0x01, regGpio, 2);
break;
+ case BRIDGE_SN9C110:
+ reg_w1(gspca_dev, 0x02, 0x62);
+ break;
case BRIDGE_SN9C120:
- if (regF1 != 0x12)
- return -ENODEV;
- switch (sd->sensor) {
- case SENSOR_MI0360:
- mi0360_probe(gspca_dev);
- break;
- case SENSOR_OV7630:
- ov7630_probe(gspca_dev);
- break;
- case SENSOR_OV7648:
- ov7648_probe(gspca_dev);
- break;
- case SENSOR_PO2030N:
- po2030n_probe(gspca_dev);
- break;
- }
regGpio[1] = 0x70; /* no audio */
reg_w(gspca_dev, 0x01, regGpio, 2);
break;
- default:
-/* case BRIDGE_SN9C110: */
-/* case BRIDGE_SN9C325: */
- if (regF1 != 0x12)
- return -ENODEV;
- reg_w1(gspca_dev, 0x02, 0x62);
- break;
}
if (sd->sensor == SENSOR_OM6802)
@@ -1874,6 +1862,8 @@ static int sd_init(struct gspca_dev *gspca_dev)
sd->i2c_addr = sn9c1xx[9];
gspca_dev->ctrl_dis = ctrl_dis[sd->sensor];
+ if (!(sd->flags & F_ILLUM))
+ gspca_dev->ctrl_dis |= (1 << ILLUM);
return gspca_dev->usb_err;
}
@@ -2197,16 +2187,28 @@ static void setsharpness(struct gspca_dev *gspca_dev)
reg_w1(gspca_dev, 0x99, sd->ctrls[SHARPNESS].val);
}
-static void setinfrared(struct gspca_dev *gspca_dev)
+static void setillum(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- if (gspca_dev->ctrl_dis & (1 << INFRARED))
+ if (gspca_dev->ctrl_dis & (1 << ILLUM))
return;
-/*fixme: different sequence for StarCam Clip and StarCam 370i */
-/* Clip */
- i2c_w1(gspca_dev, 0x02, /* gpio */
- sd->ctrls[INFRARED].val ? 0x66 : 0x64);
+ switch (sd->sensor) {
+ case SENSOR_ADCM1700:
+ reg_w1(gspca_dev, 0x02, /* gpio */
+ sd->ctrls[ILLUM].val ? 0x64 : 0x60);
+ break;
+ case SENSOR_MT9V111:
+ if (starcam)
+ reg_w1(gspca_dev, 0x02,
+ sd->ctrls[ILLUM].val ?
+ 0x55 : 0x54); /* 370i */
+ else
+ reg_w1(gspca_dev, 0x02,
+ sd->ctrls[ILLUM].val ?
+ 0x66 : 0x64); /* Clip */
+ break;
+ }
}
static void setfreq(struct gspca_dev *gspca_dev)
@@ -2344,7 +2346,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
/* sensor clock already enabled in sd_init */
/* reg_w1(gspca_dev, 0xf1, 0x00); */
reg01 = sn9c1xx[1];
- if (sd->flags & PDN_INV)
+ if (sd->flags & F_PDN_INV)
reg01 ^= S_PDN_INV; /* power down inverted */
reg_w1(gspca_dev, 0x01, reg01);
@@ -2907,13 +2909,11 @@ static const struct sd_desc sd_desc = {
.driver_info = (BRIDGE_ ## bridge << 16) \
| (SENSOR_ ## sensor << 8) \
| (flags)
-static const __devinitdata struct usb_device_id device_table[] = {
-#if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE
+static const struct usb_device_id device_table[] = {
{USB_DEVICE(0x0458, 0x7025), BS(SN9C120, MI0360)},
{USB_DEVICE(0x0458, 0x702e), BS(SN9C120, OV7660)},
-#endif
- {USB_DEVICE(0x045e, 0x00f5), BSF(SN9C105, OV7660, PDN_INV)},
- {USB_DEVICE(0x045e, 0x00f7), BSF(SN9C105, OV7660, PDN_INV)},
+ {USB_DEVICE(0x045e, 0x00f5), BSF(SN9C105, OV7660, F_PDN_INV)},
+ {USB_DEVICE(0x045e, 0x00f7), BSF(SN9C105, OV7660, F_PDN_INV)},
{USB_DEVICE(0x0471, 0x0327), BS(SN9C105, MI0360)},
{USB_DEVICE(0x0471, 0x0328), BS(SN9C105, MI0360)},
{USB_DEVICE(0x0471, 0x0330), BS(SN9C105, MI0360)},
@@ -2925,7 +2925,7 @@ static const __devinitdata struct usb_device_id device_table[] = {
/* {USB_DEVICE(0x0c45, 0x607b), BS(SN9C102P, OV7660)}, */
{USB_DEVICE(0x0c45, 0x607c), BS(SN9C102P, HV7131R)},
/* {USB_DEVICE(0x0c45, 0x607e), BS(SN9C102P, OV7630)}, */
- {USB_DEVICE(0x0c45, 0x60c0), BS(SN9C105, MI0360)},
+ {USB_DEVICE(0x0c45, 0x60c0), BSF(SN9C105, MI0360, F_ILLUM)},
/* or MT9V111 */
/* {USB_DEVICE(0x0c45, 0x60c2), BS(SN9C105, P1030xC)}, */
/* {USB_DEVICE(0x0c45, 0x60c8), BS(SN9C105, OM6802)}, */
@@ -2936,10 +2936,8 @@ static const __devinitdata struct usb_device_id device_table[] = {
/* {USB_DEVICE(0x0c45, 0x60fa), BS(SN9C105, OV7648)}, */
/* {USB_DEVICE(0x0c45, 0x60f2), BS(SN9C105, OV7660)}, */
{USB_DEVICE(0x0c45, 0x60fb), BS(SN9C105, OV7660)},
-#if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE
{USB_DEVICE(0x0c45, 0x60fc), BS(SN9C105, HV7131R)},
{USB_DEVICE(0x0c45, 0x60fe), BS(SN9C105, OV7630)},
-#endif
{USB_DEVICE(0x0c45, 0x6100), BS(SN9C120, MI0360)}, /*sn9c128*/
{USB_DEVICE(0x0c45, 0x6102), BS(SN9C120, PO2030N)}, /* /GC0305*/
/* {USB_DEVICE(0x0c45, 0x6108), BS(SN9C120, OM6802)}, */
@@ -2962,16 +2960,15 @@ static const __devinitdata struct usb_device_id device_table[] = {
/* {USB_DEVICE(0x0c45, 0x6132), BS(SN9C120, OV7670)}, */
{USB_DEVICE(0x0c45, 0x6138), BS(SN9C120, MO4000)},
{USB_DEVICE(0x0c45, 0x613a), BS(SN9C120, OV7648)},
-#if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE
{USB_DEVICE(0x0c45, 0x613b), BS(SN9C120, OV7660)},
-#endif
{USB_DEVICE(0x0c45, 0x613c), BS(SN9C120, HV7131R)},
{USB_DEVICE(0x0c45, 0x613e), BS(SN9C120, OV7630)},
{USB_DEVICE(0x0c45, 0x6142), BS(SN9C120, PO2030N)}, /*sn9c120b*/
/* or GC0305 / GC0307 */
{USB_DEVICE(0x0c45, 0x6143), BS(SN9C120, SP80708)}, /*sn9c120b*/
{USB_DEVICE(0x0c45, 0x6148), BS(SN9C120, OM6802)}, /*sn9c120b*/
- {USB_DEVICE(0x0c45, 0x614a), BS(SN9C120, ADCM1700)}, /*sn9c120b*/
+ {USB_DEVICE(0x0c45, 0x614a), BSF(SN9C120, ADCM1700, F_ILLUM)},
+/* {USB_DEVICE(0x0c45, 0x614c), BS(SN9C120, GC0306)}, */ /*sn9c120b*/
{}
};
MODULE_DEVICE_TABLE(usb, device_table);
@@ -3007,3 +3004,7 @@ static void __exit sd_mod_exit(void)
module_init(sd_mod_init);
module_exit(sd_mod_exit);
+
+module_param(starcam, int, 0644);
+MODULE_PARM_DESC(starcam,
+ "StarCam model. 0: Clip, 1: 370i");
diff --git a/drivers/media/video/gspca/spca1528.c b/drivers/media/video/gspca/spca1528.c
index e643386..76c006b 100644
--- a/drivers/media/video/gspca/spca1528.c
+++ b/drivers/media/video/gspca/spca1528.c
@@ -555,7 +555,7 @@ static const struct sd_desc sd_desc = {
};
/* -- module initialisation -- */
-static const __devinitdata struct usb_device_id device_table[] = {
+static const struct usb_device_id device_table[] = {
{USB_DEVICE(0x04fc, 0x1528)},
{}
};
diff --git a/drivers/media/video/gspca/spca500.c b/drivers/media/video/gspca/spca500.c
index 8e202b9..45552c3 100644
--- a/drivers/media/video/gspca/spca500.c
+++ b/drivers/media/video/gspca/spca500.c
@@ -1051,7 +1051,7 @@ static const struct sd_desc sd_desc = {
};
/* -- module initialisation -- */
-static const __devinitdata struct usb_device_id device_table[] = {
+static const struct usb_device_id device_table[] = {
{USB_DEVICE(0x040a, 0x0300), .driver_info = KodakEZ200},
{USB_DEVICE(0x041e, 0x400a), .driver_info = CreativePCCam300},
{USB_DEVICE(0x046d, 0x0890), .driver_info = LogitechTraveler},
diff --git a/drivers/media/video/gspca/spca501.c b/drivers/media/video/gspca/spca501.c
index 642839a..f7ef282 100644
--- a/drivers/media/video/gspca/spca501.c
+++ b/drivers/media/video/gspca/spca501.c
@@ -2155,7 +2155,7 @@ static const struct sd_desc sd_desc = {
};
/* -- module initialisation -- */
-static const __devinitdata struct usb_device_id device_table[] = {
+static const struct usb_device_id device_table[] = {
{USB_DEVICE(0x040a, 0x0002), .driver_info = KodakDVC325},
{USB_DEVICE(0x0497, 0xc001), .driver_info = SmileIntlCamera},
{USB_DEVICE(0x0506, 0x00df), .driver_info = ThreeComHomeConnectLite},
diff --git a/drivers/media/video/gspca/spca505.c b/drivers/media/video/gspca/spca505.c
index bc9dd90..e5bf865 100644
--- a/drivers/media/video/gspca/spca505.c
+++ b/drivers/media/video/gspca/spca505.c
@@ -786,7 +786,7 @@ static const struct sd_desc sd_desc = {
};
/* -- module initialisation -- */
-static const __devinitdata struct usb_device_id device_table[] = {
+static const struct usb_device_id device_table[] = {
{USB_DEVICE(0x041e, 0x401d), .driver_info = Nxultra},
{USB_DEVICE(0x0733, 0x0430), .driver_info = IntelPCCameraPro},
/*fixme: may be UsbGrabberPV321 BRIDGE_SPCA506 SENSOR_SAA7113 */
diff --git a/drivers/media/video/gspca/spca508.c b/drivers/media/video/gspca/spca508.c
index 7307638..3483193 100644
--- a/drivers/media/video/gspca/spca508.c
+++ b/drivers/media/video/gspca/spca508.c
@@ -1509,7 +1509,7 @@ static const struct sd_desc sd_desc = {
};
/* -- module initialisation -- */
-static const __devinitdata struct usb_device_id device_table[] = {
+static const struct usb_device_id device_table[] = {
{USB_DEVICE(0x0130, 0x0130), .driver_info = HamaUSBSightcam},
{USB_DEVICE(0x041e, 0x4018), .driver_info = CreativeVista},
{USB_DEVICE(0x0733, 0x0110), .driver_info = ViewQuestVQ110},
diff --git a/drivers/media/video/gspca/spca561.c b/drivers/media/video/gspca/spca561.c
index 3a162c6..e836e77 100644
--- a/drivers/media/video/gspca/spca561.c
+++ b/drivers/media/video/gspca/spca561.c
@@ -1061,7 +1061,7 @@ static const struct sd_desc *sd_desc[2] = {
};
/* -- module initialisation -- */
-static const __devinitdata struct usb_device_id device_table[] = {
+static const struct usb_device_id device_table[] = {
{USB_DEVICE(0x041e, 0x401a), .driver_info = Rev072A},
{USB_DEVICE(0x041e, 0x403b), .driver_info = Rev012A},
{USB_DEVICE(0x0458, 0x7004), .driver_info = Rev072A},
diff --git a/drivers/media/video/gspca/sq905.c b/drivers/media/video/gspca/sq905.c
index 4040677..2e9c061 100644
--- a/drivers/media/video/gspca/sq905.c
+++ b/drivers/media/video/gspca/sq905.c
@@ -396,7 +396,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
}
/* Table of supported USB devices */
-static const __devinitdata struct usb_device_id device_table[] = {
+static const struct usb_device_id device_table[] = {
{USB_DEVICE(0x2770, 0x9120)},
{}
};
diff --git a/drivers/media/video/gspca/sq905c.c b/drivers/media/video/gspca/sq905c.c
index 8ba1995..457563b 100644
--- a/drivers/media/video/gspca/sq905c.c
+++ b/drivers/media/video/gspca/sq905c.c
@@ -298,7 +298,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
}
/* Table of supported USB devices */
-static const __devinitdata struct usb_device_id device_table[] = {
+static const struct usb_device_id device_table[] = {
{USB_DEVICE(0x2770, 0x905c)},
{USB_DEVICE(0x2770, 0x9050)},
{USB_DEVICE(0x2770, 0x9051)},
diff --git a/drivers/media/video/gspca/sq930x.c b/drivers/media/video/gspca/sq930x.c
index a4a9881..8215d5d 100644
--- a/drivers/media/video/gspca/sq930x.c
+++ b/drivers/media/video/gspca/sq930x.c
@@ -1163,7 +1163,7 @@ static const struct sd_desc sd_desc = {
#define ST(sensor, type) \
.driver_info = (SENSOR_ ## sensor << 8) \
| (type)
-static const __devinitdata struct usb_device_id device_table[] = {
+static const struct usb_device_id device_table[] = {
{USB_DEVICE(0x041e, 0x4038), ST(MI0360, 0)},
{USB_DEVICE(0x041e, 0x403c), ST(LZ24BP, 0)},
{USB_DEVICE(0x041e, 0x403d), ST(LZ24BP, 0)},
diff --git a/drivers/media/video/gspca/stk014.c b/drivers/media/video/gspca/stk014.c
index 11a192b..87be52b 100644
--- a/drivers/media/video/gspca/stk014.c
+++ b/drivers/media/video/gspca/stk014.c
@@ -495,7 +495,7 @@ static const struct sd_desc sd_desc = {
};
/* -- module initialisation -- */
-static const __devinitdata struct usb_device_id device_table[] = {
+static const struct usb_device_id device_table[] = {
{USB_DEVICE(0x05e1, 0x0893)},
{}
};
diff --git a/drivers/media/video/gspca/stv0680.c b/drivers/media/video/gspca/stv0680.c
index b199ad4..e2ef41c 100644
--- a/drivers/media/video/gspca/stv0680.c
+++ b/drivers/media/video/gspca/stv0680.c
@@ -327,7 +327,7 @@ static const struct sd_desc sd_desc = {
};
/* -- module initialisation -- */
-static const __devinitdata struct usb_device_id device_table[] = {
+static const struct usb_device_id device_table[] = {
{USB_DEVICE(0x0553, 0x0202)},
{USB_DEVICE(0x041e, 0x4007)},
{}
diff --git a/drivers/media/video/gspca/stv06xx/stv06xx.c b/drivers/media/video/gspca/stv06xx/stv06xx.c
index 28ea417..7e06614 100644
--- a/drivers/media/video/gspca/stv06xx/stv06xx.c
+++ b/drivers/media/video/gspca/stv06xx/stv06xx.c
@@ -564,7 +564,7 @@ static int stv06xx_config(struct gspca_dev *gspca_dev,
/* -- module initialisation -- */
-static const __devinitdata struct usb_device_id device_table[] = {
+static const struct usb_device_id device_table[] = {
/* QuickCam Express */
{USB_DEVICE(0x046d, 0x0840), .driver_info = BRIDGE_STV600 },
/* LEGO cam / QuickCam Web */
diff --git a/drivers/media/video/gspca/sunplus.c b/drivers/media/video/gspca/sunplus.c
index a9cbcd6..543542a 100644
--- a/drivers/media/video/gspca/sunplus.c
+++ b/drivers/media/video/gspca/sunplus.c
@@ -1162,7 +1162,7 @@ static const struct sd_desc sd_desc = {
#define BS(bridge, subtype) \
.driver_info = (BRIDGE_ ## bridge << 8) \
| (subtype)
-static const __devinitdata struct usb_device_id device_table[] = {
+static const struct usb_device_id device_table[] = {
{USB_DEVICE(0x041e, 0x400b), BS(SPCA504C, 0)},
{USB_DEVICE(0x041e, 0x4012), BS(SPCA504C, 0)},
{USB_DEVICE(0x041e, 0x4013), BS(SPCA504C, 0)},
diff --git a/drivers/media/video/gspca/t613.c b/drivers/media/video/gspca/t613.c
index 8f0c331..a3eccd8 100644
--- a/drivers/media/video/gspca/t613.c
+++ b/drivers/media/video/gspca/t613.c
@@ -1416,7 +1416,7 @@ static const struct sd_desc sd_desc = {
};
/* -- module initialisation -- */
-static const __devinitdata struct usb_device_id device_table[] = {
+static const struct usb_device_id device_table[] = {
{USB_DEVICE(0x17a1, 0x0128)},
{}
};
diff --git a/drivers/media/video/gspca/tv8532.c b/drivers/media/video/gspca/tv8532.c
index 38c22f0..933ef2c 100644
--- a/drivers/media/video/gspca/tv8532.c
+++ b/drivers/media/video/gspca/tv8532.c
@@ -388,7 +388,7 @@ static const struct sd_desc sd_desc = {
};
/* -- module initialisation -- */
-static const __devinitdata struct usb_device_id device_table[] = {
+static const struct usb_device_id device_table[] = {
{USB_DEVICE(0x046d, 0x0920)},
{USB_DEVICE(0x046d, 0x0921)},
{USB_DEVICE(0x0545, 0x808b)},
diff --git a/drivers/media/video/gspca/vc032x.c b/drivers/media/video/gspca/vc032x.c
index 9b2ae1b..6caed73 100644
--- a/drivers/media/video/gspca/vc032x.c
+++ b/drivers/media/video/gspca/vc032x.c
@@ -4192,7 +4192,7 @@ static const struct sd_desc sd_desc = {
#define BF(bridge, flags) \
.driver_info = (BRIDGE_ ## bridge << 8) \
| (flags)
-static const __devinitdata struct usb_device_id device_table[] = {
+static const struct usb_device_id device_table[] = {
{USB_DEVICE(0x041e, 0x405b), BF(VC0323, FL_VFLIP)},
{USB_DEVICE(0x046d, 0x0892), BF(VC0321, 0)},
{USB_DEVICE(0x046d, 0x0896), BF(VC0321, 0)},
diff --git a/drivers/media/video/gspca/xirlink_cit.c b/drivers/media/video/gspca/xirlink_cit.c
index 5b5039a..c089a0f 100644
--- a/drivers/media/video/gspca/xirlink_cit.c
+++ b/drivers/media/video/gspca/xirlink_cit.c
@@ -3270,7 +3270,7 @@ static const struct sd_desc sd_desc_isoc_nego = {
};
/* -- module initialisation -- */
-static const __devinitdata struct usb_device_id device_table[] = {
+static const struct usb_device_id device_table[] = {
{ USB_DEVICE_VER(0x0545, 0x8080, 0x0001, 0x0001), .driver_info = CIT_MODEL0 },
{ USB_DEVICE_VER(0x0545, 0x8080, 0x0002, 0x0002), .driver_info = CIT_MODEL1 },
{ USB_DEVICE_VER(0x0545, 0x8080, 0x030a, 0x030a), .driver_info = CIT_MODEL2 },
diff --git a/drivers/media/video/gspca/zc3xx.c b/drivers/media/video/gspca/zc3xx.c
index 14b85d4..865216e 100644
--- a/drivers/media/video/gspca/zc3xx.c
+++ b/drivers/media/video/gspca/zc3xx.c
@@ -6909,7 +6909,7 @@ static const struct sd_desc sd_desc = {
#endif
};
-static const __devinitdata struct usb_device_id device_table[] = {
+static const struct usb_device_id device_table[] = {
{USB_DEVICE(0x041e, 0x041e)},
{USB_DEVICE(0x041e, 0x4017)},
{USB_DEVICE(0x041e, 0x401c), .driver_info = SENSOR_PAS106},
diff --git a/drivers/media/video/hdpvr/Makefile b/drivers/media/video/hdpvr/Makefile
index e0230fc..3baa9f6 100644
--- a/drivers/media/video/hdpvr/Makefile
+++ b/drivers/media/video/hdpvr/Makefile
@@ -1,6 +1,4 @@
-hdpvr-objs := hdpvr-control.o hdpvr-core.o hdpvr-video.o
-
-hdpvr-$(CONFIG_I2C) += hdpvr-i2c.o
+hdpvr-objs := hdpvr-control.o hdpvr-core.o hdpvr-video.o hdpvr-i2c.o
obj-$(CONFIG_VIDEO_HDPVR) += hdpvr.o
diff --git a/drivers/media/video/hdpvr/hdpvr-core.c b/drivers/media/video/hdpvr/hdpvr-core.c
index f7d1ee5..a6572e5 100644
--- a/drivers/media/video/hdpvr/hdpvr-core.c
+++ b/drivers/media/video/hdpvr/hdpvr-core.c
@@ -378,19 +378,17 @@ static int hdpvr_probe(struct usb_interface *interface,
goto error;
}
-#ifdef CONFIG_I2C
- /* until i2c is working properly */
- retval = 0; /* hdpvr_register_i2c_adapter(dev); */
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+ retval = hdpvr_register_i2c_adapter(dev);
if (retval < 0) {
v4l2_err(&dev->v4l2_dev, "registering i2c adapter failed\n");
goto error;
}
- /* until i2c is working properly */
- retval = 0; /* hdpvr_register_i2c_ir(dev); */
+ retval = hdpvr_register_i2c_ir(dev);
if (retval < 0)
v4l2_err(&dev->v4l2_dev, "registering i2c IR devices failed\n");
-#endif /* CONFIG_I2C */
+#endif
/* let the user know what node this device is now attached to */
v4l2_info(&dev->v4l2_dev, "device now attached to %s\n",
diff --git a/drivers/media/video/hdpvr/hdpvr-i2c.c b/drivers/media/video/hdpvr/hdpvr-i2c.c
index 24966aa..89b71fa 100644
--- a/drivers/media/video/hdpvr/hdpvr-i2c.c
+++ b/drivers/media/video/hdpvr/hdpvr-i2c.c
@@ -13,6 +13,8 @@
*
*/
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+
#include <linux/i2c.h>
#include <linux/slab.h>
@@ -28,106 +30,78 @@
#define Z8F0811_IR_TX_I2C_ADDR 0x70
#define Z8F0811_IR_RX_I2C_ADDR 0x71
-static const u8 ir_i2c_addrs[] = {
- Z8F0811_IR_TX_I2C_ADDR,
- Z8F0811_IR_RX_I2C_ADDR,
-};
-static const char * const ir_devicenames[] = {
- "ir_tx_z8f0811_hdpvr",
- "ir_rx_z8f0811_hdpvr",
+static struct i2c_board_info hdpvr_i2c_board_info = {
+ I2C_BOARD_INFO("ir_tx_z8f0811_hdpvr", Z8F0811_IR_TX_I2C_ADDR),
+ I2C_BOARD_INFO("ir_rx_z8f0811_hdpvr", Z8F0811_IR_RX_I2C_ADDR),
};
-static int hdpvr_new_i2c_ir(struct hdpvr_device *dev, struct i2c_adapter *adap,
- const char *type, u8 addr)
+int hdpvr_register_i2c_ir(struct hdpvr_device *dev)
{
- struct i2c_board_info info;
+ struct i2c_client *c;
struct IR_i2c_init_data *init_data = &dev->ir_i2c_init_data;
- unsigned short addr_list[2] = { addr, I2C_CLIENT_END };
-
- memset(&info, 0, sizeof(struct i2c_board_info));
- strlcpy(info.type, type, I2C_NAME_SIZE);
/* Our default information for ir-kbd-i2c.c to use */
- switch (addr) {
- case Z8F0811_IR_RX_I2C_ADDR:
- init_data->ir_codes = RC_MAP_HAUPPAUGE_NEW;
- init_data->internal_get_key_func = IR_KBD_GET_KEY_HAUP_XVR;
- init_data->type = RC_TYPE_RC5;
- init_data->name = "HD PVR";
- info.platform_data = init_data;
- break;
- }
+ init_data->ir_codes = RC_MAP_HAUPPAUGE_NEW;
+ init_data->internal_get_key_func = IR_KBD_GET_KEY_HAUP_XVR;
+ init_data->type = RC_TYPE_RC5;
+ init_data->name = "HD PVR";
+ hdpvr_i2c_board_info.platform_data = init_data;
- return i2c_new_probed_device(adap, &info, addr_list, NULL) == NULL ?
- -1 : 0;
-}
+ c = i2c_new_device(&dev->i2c_adapter, &hdpvr_i2c_board_info);
-int hdpvr_register_i2c_ir(struct hdpvr_device *dev)
-{
- int i;
- int ret = 0;
-
- for (i = 0; i < ARRAY_SIZE(ir_i2c_addrs); i++)
- ret += hdpvr_new_i2c_ir(dev, dev->i2c_adapter,
- ir_devicenames[i], ir_i2c_addrs[i]);
-
- return ret;
+ return (c == NULL) ? -ENODEV : 0;
}
-static int hdpvr_i2c_read(struct hdpvr_device *dev, unsigned char addr,
- char *data, int len)
+static int hdpvr_i2c_read(struct hdpvr_device *dev, int bus,
+ unsigned char addr, char *data, int len)
{
int ret;
- char *buf = kmalloc(len, GFP_KERNEL);
- if (!buf)
- return -ENOMEM;
+
+ if (len > sizeof(dev->i2c_buf))
+ return -EINVAL;
ret = usb_control_msg(dev->udev,
usb_rcvctrlpipe(dev->udev, 0),
REQTYPE_I2C_READ, CTRL_READ_REQUEST,
- 0x100|addr, 0, buf, len, 1000);
+ (bus << 8) | addr, 0, &dev->i2c_buf, len, 1000);
if (ret == len) {
- memcpy(data, buf, len);
+ memcpy(data, &dev->i2c_buf, len);
ret = 0;
} else if (ret >= 0)
ret = -EIO;
- kfree(buf);
-
return ret;
}
-static int hdpvr_i2c_write(struct hdpvr_device *dev, unsigned char addr,
- char *data, int len)
+static int hdpvr_i2c_write(struct hdpvr_device *dev, int bus,
+ unsigned char addr, char *data, int len)
{
int ret;
- char *buf = kmalloc(len, GFP_KERNEL);
- if (!buf)
- return -ENOMEM;
- memcpy(buf, data, len);
+ if (len > sizeof(dev->i2c_buf))
+ return -EINVAL;
+
+ memcpy(&dev->i2c_buf, data, len);
ret = usb_control_msg(dev->udev,
usb_sndctrlpipe(dev->udev, 0),
REQTYPE_I2C_WRITE, CTRL_WRITE_REQUEST,
- 0x100|addr, 0, buf, len, 1000);
+ (bus << 8) | addr, 0, &dev->i2c_buf, len, 1000);
if (ret < 0)
- goto error;
+ return ret;
ret = usb_control_msg(dev->udev,
usb_rcvctrlpipe(dev->udev, 0),
REQTYPE_I2C_WRITE_STATT, CTRL_READ_REQUEST,
- 0, 0, buf, 2, 1000);
+ 0, 0, &dev->i2c_buf, 2, 1000);
- if (ret == 2)
+ if ((ret == 2) && (dev->i2c_buf[1] == (len - 1)))
ret = 0;
else if (ret >= 0)
ret = -EIO;
-error:
- kfree(buf);
return ret;
}
@@ -146,10 +120,10 @@ static int hdpvr_transfer(struct i2c_adapter *i2c_adapter, struct i2c_msg *msgs,
addr = msgs[i].addr << 1;
if (msgs[i].flags & I2C_M_RD)
- retval = hdpvr_i2c_read(dev, addr, msgs[i].buf,
+ retval = hdpvr_i2c_read(dev, 1, addr, msgs[i].buf,
msgs[i].len);
else
- retval = hdpvr_i2c_write(dev, addr, msgs[i].buf,
+ retval = hdpvr_i2c_write(dev, 1, addr, msgs[i].buf,
msgs[i].len);
}
@@ -168,30 +142,47 @@ static struct i2c_algorithm hdpvr_algo = {
.functionality = hdpvr_functionality,
};
+static struct i2c_adapter hdpvr_i2c_adapter_template = {
+ .name = "Hauppage HD PVR I2C",
+ .owner = THIS_MODULE,
+ .algo = &hdpvr_algo,
+};
+
+static int hdpvr_activate_ir(struct hdpvr_device *dev)
+{
+ char buffer[8];
+
+ mutex_lock(&dev->i2c_mutex);
+
+ hdpvr_i2c_read(dev, 0, 0x54, buffer, 1);
+
+ buffer[0] = 0;
+ buffer[1] = 0x8;
+ hdpvr_i2c_write(dev, 1, 0x54, buffer, 2);
+
+ buffer[1] = 0x18;
+ hdpvr_i2c_write(dev, 1, 0x54, buffer, 2);
+
+ mutex_unlock(&dev->i2c_mutex);
+
+ return 0;
+}
+
int hdpvr_register_i2c_adapter(struct hdpvr_device *dev)
{
- struct i2c_adapter *i2c_adap;
int retval = -ENOMEM;
- i2c_adap = kzalloc(sizeof(struct i2c_adapter), GFP_KERNEL);
- if (i2c_adap == NULL)
- goto error;
-
- strlcpy(i2c_adap->name, "Hauppauge HD PVR I2C",
- sizeof(i2c_adap->name));
- i2c_adap->algo = &hdpvr_algo;
- i2c_adap->owner = THIS_MODULE;
- i2c_adap->dev.parent = &dev->udev->dev;
+ hdpvr_activate_ir(dev);
- i2c_set_adapdata(i2c_adap, dev);
+ memcpy(&dev->i2c_adapter, &hdpvr_i2c_adapter_template,
+ sizeof(struct i2c_adapter));
+ dev->i2c_adapter.dev.parent = &dev->udev->dev;
- retval = i2c_add_adapter(i2c_adap);
+ i2c_set_adapdata(&dev->i2c_adapter, dev);
- if (!retval)
- dev->i2c_adapter = i2c_adap;
- else
- kfree(i2c_adap);
+ retval = i2c_add_adapter(&dev->i2c_adapter);
-error:
return retval;
}
+
+#endif
diff --git a/drivers/media/video/hdpvr/hdpvr-video.c b/drivers/media/video/hdpvr/hdpvr-video.c
index d38fe10..514aea7 100644
--- a/drivers/media/video/hdpvr/hdpvr-video.c
+++ b/drivers/media/video/hdpvr/hdpvr-video.c
@@ -1220,12 +1220,9 @@ static void hdpvr_device_release(struct video_device *vdev)
v4l2_device_unregister(&dev->v4l2_dev);
/* deregister I2C adapter */
-#ifdef CONFIG_I2C
+#if defined(CONFIG_I2C) || (CONFIG_I2C_MODULE)
mutex_lock(&dev->i2c_mutex);
- if (dev->i2c_adapter)
- i2c_del_adapter(dev->i2c_adapter);
- kfree(dev->i2c_adapter);
- dev->i2c_adapter = NULL;
+ i2c_del_adapter(&dev->i2c_adapter);
mutex_unlock(&dev->i2c_mutex);
#endif /* CONFIG_I2C */
diff --git a/drivers/media/video/hdpvr/hdpvr.h b/drivers/media/video/hdpvr/hdpvr.h
index 37f1e4c..ee74e3b 100644
--- a/drivers/media/video/hdpvr/hdpvr.h
+++ b/drivers/media/video/hdpvr/hdpvr.h
@@ -25,6 +25,7 @@
KERNEL_VERSION(HDPVR_MAJOR_VERSION, HDPVR_MINOR_VERSION, HDPVR_RELEASE)
#define HDPVR_MAX 8
+#define HDPVR_I2C_MAX_SIZE 128
/* Define these values to match your devices */
#define HD_PVR_VENDOR_ID 0x2040
@@ -106,9 +107,11 @@ struct hdpvr_device {
struct work_struct worker;
/* I2C adapter */
- struct i2c_adapter *i2c_adapter;
+ struct i2c_adapter i2c_adapter;
/* I2C lock */
struct mutex i2c_mutex;
+ /* I2C message buffer space */
+ char i2c_buf[HDPVR_I2C_MAX_SIZE];
/* For passing data to ir-kbd-i2c */
struct IR_i2c_init_data ir_i2c_init_data;
diff --git a/drivers/media/video/ir-kbd-i2c.c b/drivers/media/video/ir-kbd-i2c.c
index c87b6bc..d2b20ad 100644
--- a/drivers/media/video/ir-kbd-i2c.c
+++ b/drivers/media/video/ir-kbd-i2c.c
@@ -244,15 +244,17 @@ static void ir_key_poll(struct IR_i2c *ir)
static u32 ir_key, ir_raw;
int rc;
- dprintk(2,"ir_poll_key\n");
+ dprintk(3, "%s\n", __func__);
rc = ir->get_key(ir, &ir_key, &ir_raw);
if (rc < 0) {
dprintk(2,"error\n");
return;
}
- if (rc)
+ if (rc) {
+ dprintk(1, "%s: keycode = 0x%04x\n", __func__, ir_key);
rc_keydown(ir->rc, ir_key, 0);
+ }
}
static void ir_work(struct work_struct *work)
@@ -321,6 +323,12 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
rc_type = RC_TYPE_OTHER;
ir_codes = RC_MAP_AVERMEDIA_CARDBUS;
break;
+ case 0x71:
+ name = "Hauppauge/Zilog Z8";
+ ir->get_key = get_key_haup_xvr;
+ rc_type = RC_TYPE_RC5;
+ ir_codes = hauppauge ? RC_MAP_HAUPPAUGE_NEW : RC_MAP_RC5_TV;
+ break;
}
/* Let the caller override settings */
diff --git a/drivers/media/video/ivtv/ivtv-i2c.c b/drivers/media/video/ivtv/ivtv-i2c.c
index e103b8f..9fb86a0 100644
--- a/drivers/media/video/ivtv/ivtv-i2c.c
+++ b/drivers/media/video/ivtv/ivtv-i2c.c
@@ -300,10 +300,15 @@ int ivtv_i2c_register(struct ivtv *itv, unsigned idx)
adap, type, 0, I2C_ADDRS(hw_addrs[idx]));
} else if (hw == IVTV_HW_CX25840) {
struct cx25840_platform_data pdata;
+ struct i2c_board_info cx25840_info = {
+ .type = "cx25840",
+ .addr = hw_addrs[idx],
+ .platform_data = &pdata,
+ };
pdata.pvr150_workaround = itv->pvr150_workaround;
- sd = v4l2_i2c_new_subdev_cfg(&itv->v4l2_dev,
- adap, type, 0, &pdata, hw_addrs[idx], NULL);
+ sd = v4l2_i2c_new_subdev_board(&itv->v4l2_dev, adap,
+ &cx25840_info, NULL);
} else {
sd = v4l2_i2c_new_subdev(&itv->v4l2_dev,
adap, type, hw_addrs[idx], NULL);
diff --git a/drivers/media/video/mt9v011.c b/drivers/media/video/mt9v011.c
index 209ff97..4904d25 100644
--- a/drivers/media/video/mt9v011.c
+++ b/drivers/media/video/mt9v011.c
@@ -12,17 +12,41 @@
#include <asm/div64.h>
#include <media/v4l2-device.h>
#include <media/v4l2-chip-ident.h>
-#include "mt9v011.h"
+#include <media/mt9v011.h>
MODULE_DESCRIPTION("Micron mt9v011 sensor driver");
MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
MODULE_LICENSE("GPL");
-
static int debug;
module_param(debug, int, 0);
MODULE_PARM_DESC(debug, "Debug level (0-2)");
+#define R00_MT9V011_CHIP_VERSION 0x00
+#define R01_MT9V011_ROWSTART 0x01
+#define R02_MT9V011_COLSTART 0x02
+#define R03_MT9V011_HEIGHT 0x03
+#define R04_MT9V011_WIDTH 0x04
+#define R05_MT9V011_HBLANK 0x05
+#define R06_MT9V011_VBLANK 0x06
+#define R07_MT9V011_OUT_CTRL 0x07
+#define R09_MT9V011_SHUTTER_WIDTH 0x09
+#define R0A_MT9V011_CLK_SPEED 0x0a
+#define R0B_MT9V011_RESTART 0x0b
+#define R0C_MT9V011_SHUTTER_DELAY 0x0c
+#define R0D_MT9V011_RESET 0x0d
+#define R1E_MT9V011_DIGITAL_ZOOM 0x1e
+#define R20_MT9V011_READ_MODE 0x20
+#define R2B_MT9V011_GREEN_1_GAIN 0x2b
+#define R2C_MT9V011_BLUE_GAIN 0x2c
+#define R2D_MT9V011_RED_GAIN 0x2d
+#define R2E_MT9V011_GREEN_2_GAIN 0x2e
+#define R35_MT9V011_GLOBAL_GAIN 0x35
+#define RF1_MT9V011_CHIP_ENABLE 0xf1
+
+#define MT9V011_VERSION 0x8232
+#define MT9V011_REV_B_VERSION 0x8243
+
/* supported controls */
static struct v4l2_queryctrl mt9v011_qctrl[] = {
{
@@ -469,23 +493,6 @@ static int mt9v011_s_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt
return 0;
}
-static int mt9v011_s_config(struct v4l2_subdev *sd, int dumb, void *data)
-{
- struct mt9v011 *core = to_mt9v011(sd);
- unsigned *xtal = data;
-
- v4l2_dbg(1, debug, sd, "s_config called\n");
-
- if (xtal) {
- core->xtal = *xtal;
- v4l2_dbg(1, debug, sd, "xtal set to %d.%03d MHz\n",
- *xtal / 1000000, (*xtal / 1000) % 1000);
- }
-
- return 0;
-}
-
-
#ifdef CONFIG_VIDEO_ADV_DEBUG
static int mt9v011_g_register(struct v4l2_subdev *sd,
struct v4l2_dbg_register *reg)
@@ -536,7 +543,6 @@ static const struct v4l2_subdev_core_ops mt9v011_core_ops = {
.g_ctrl = mt9v011_g_ctrl,
.s_ctrl = mt9v011_s_ctrl,
.reset = mt9v011_reset,
- .s_config = mt9v011_s_config,
.g_chip_ident = mt9v011_g_chip_ident,
#ifdef CONFIG_VIDEO_ADV_DEBUG
.g_register = mt9v011_g_register,
@@ -596,6 +602,14 @@ static int mt9v011_probe(struct i2c_client *c,
core->height = 480;
core->xtal = 27000000; /* Hz */
+ if (c->dev.platform_data) {
+ struct mt9v011_platform_data *pdata = c->dev.platform_data;
+
+ core->xtal = pdata->xtal;
+ v4l2_dbg(1, debug, sd, "xtal set to %d.%03d MHz\n",
+ core->xtal / 1000000, (core->xtal / 1000) % 1000);
+ }
+
v4l_info(c, "chip found @ 0x%02x (%s - chip version 0x%04x)\n",
c->addr << 1, c->adapter->name, version);
diff --git a/drivers/media/video/mt9v011.h b/drivers/media/video/mt9v011.h
deleted file mode 100644
index 3350fd6..0000000
--- a/drivers/media/video/mt9v011.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * mt9v011 -Micron 1/4-Inch VGA Digital Image Sensor
- *
- * Copyright (c) 2009 Mauro Carvalho Chehab (mchehab@redhat.com)
- * This code is placed under the terms of the GNU General Public License v2
- */
-
-#ifndef MT9V011_H_
-#define MT9V011_H_
-
-#define R00_MT9V011_CHIP_VERSION 0x00
-#define R01_MT9V011_ROWSTART 0x01
-#define R02_MT9V011_COLSTART 0x02
-#define R03_MT9V011_HEIGHT 0x03
-#define R04_MT9V011_WIDTH 0x04
-#define R05_MT9V011_HBLANK 0x05
-#define R06_MT9V011_VBLANK 0x06
-#define R07_MT9V011_OUT_CTRL 0x07
-#define R09_MT9V011_SHUTTER_WIDTH 0x09
-#define R0A_MT9V011_CLK_SPEED 0x0a
-#define R0B_MT9V011_RESTART 0x0b
-#define R0C_MT9V011_SHUTTER_DELAY 0x0c
-#define R0D_MT9V011_RESET 0x0d
-#define R1E_MT9V011_DIGITAL_ZOOM 0x1e
-#define R20_MT9V011_READ_MODE 0x20
-#define R2B_MT9V011_GREEN_1_GAIN 0x2b
-#define R2C_MT9V011_BLUE_GAIN 0x2c
-#define R2D_MT9V011_RED_GAIN 0x2d
-#define R2E_MT9V011_GREEN_2_GAIN 0x2e
-#define R35_MT9V011_GLOBAL_GAIN 0x35
-#define RF1_MT9V011_CHIP_ENABLE 0xf1
-
-#define MT9V011_VERSION 0x8232
-#define MT9V011_REV_B_VERSION 0x8243
-
-#endif
diff --git a/drivers/media/video/ov7670.c b/drivers/media/video/ov7670.c
index c881a64..d4e7c11 100644
--- a/drivers/media/video/ov7670.c
+++ b/drivers/media/video/ov7670.c
@@ -1449,47 +1449,6 @@ static int ov7670_g_chip_ident(struct v4l2_subdev *sd,
return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_OV7670, 0);
}
-static int ov7670_s_config(struct v4l2_subdev *sd, int dumb, void *data)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct ov7670_config *config = data;
- struct ov7670_info *info = to_state(sd);
- int ret;
-
- info->clock_speed = 30; /* default: a guess */
-
- /*
- * Must apply configuration before initializing device, because it
- * selects I/O method.
- */
- if (config) {
- info->min_width = config->min_width;
- info->min_height = config->min_height;
- info->use_smbus = config->use_smbus;
-
- if (config->clock_speed)
- info->clock_speed = config->clock_speed;
- }
-
- /* Make sure it's an ov7670 */
- ret = ov7670_detect(sd);
- if (ret) {
- v4l_dbg(1, debug, client,
- "chip found @ 0x%x (%s) is not an ov7670 chip.\n",
- client->addr << 1, client->adapter->name);
- kfree(info);
- return ret;
- }
- v4l_info(client, "chip found @ 0x%02x (%s)\n",
- client->addr << 1, client->adapter->name);
-
- info->fmt = &ov7670_formats[0];
- info->sat = 128; /* Review this */
- info->clkrc = info->clock_speed / 30;
-
- return 0;
-}
-
#ifdef CONFIG_VIDEO_ADV_DEBUG
static int ov7670_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
{
@@ -1528,7 +1487,6 @@ static const struct v4l2_subdev_core_ops ov7670_core_ops = {
.s_ctrl = ov7670_s_ctrl,
.queryctrl = ov7670_queryctrl,
.reset = ov7670_reset,
- .s_config = ov7670_s_config,
.init = ov7670_init,
#ifdef CONFIG_VIDEO_ADV_DEBUG
.g_register = ov7670_g_register,
@@ -1558,6 +1516,7 @@ static int ov7670_probe(struct i2c_client *client,
{
struct v4l2_subdev *sd;
struct ov7670_info *info;
+ int ret;
info = kzalloc(sizeof(struct ov7670_info), GFP_KERNEL);
if (info == NULL)
@@ -1565,6 +1524,37 @@ static int ov7670_probe(struct i2c_client *client,
sd = &info->sd;
v4l2_i2c_subdev_init(sd, client, &ov7670_ops);
+ info->clock_speed = 30; /* default: a guess */
+ if (client->dev.platform_data) {
+ struct ov7670_config *config = client->dev.platform_data;
+
+ /*
+ * Must apply configuration before initializing device, because it
+ * selects I/O method.
+ */
+ info->min_width = config->min_width;
+ info->min_height = config->min_height;
+ info->use_smbus = config->use_smbus;
+
+ if (config->clock_speed)
+ info->clock_speed = config->clock_speed;
+ }
+
+ /* Make sure it's an ov7670 */
+ ret = ov7670_detect(sd);
+ if (ret) {
+ v4l_dbg(1, debug, client,
+ "chip found @ 0x%x (%s) is not an ov7670 chip.\n",
+ client->addr << 1, client->adapter->name);
+ kfree(info);
+ return ret;
+ }
+ v4l_info(client, "chip found @ 0x%02x (%s)\n",
+ client->addr << 1, client->adapter->name);
+
+ info->fmt = &ov7670_formats[0];
+ info->sat = 128; /* Review this */
+ info->clkrc = info->clock_speed / 30;
return 0;
}
diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h b/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
index ac94a8b..305e6aa 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
+++ b/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
@@ -40,6 +40,7 @@
#include "pvrusb2-io.h"
#include <media/v4l2-device.h>
#include <media/cx2341x.h>
+#include <media/ir-kbd-i2c.h>
#include "pvrusb2-devattr.h"
/* Legal values for PVR2_CID_HSM */
@@ -202,6 +203,7 @@ struct pvr2_hdw {
/* IR related */
unsigned int ir_scheme_active; /* IR scheme as seen from the outside */
+ struct IR_i2c_init_data ir_init_data; /* params passed to IR modules */
/* Frequency table */
unsigned int freqTable[FREQTABLE_SIZE];
diff --git a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
index 7cbe18c..ccc8849 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
@@ -19,6 +19,7 @@
*/
#include <linux/i2c.h>
+#include <media/ir-kbd-i2c.h>
#include "pvrusb2-i2c-core.h"
#include "pvrusb2-hdw-internal.h"
#include "pvrusb2-debug.h"
@@ -48,13 +49,6 @@ module_param_named(disable_autoload_ir_video, pvr2_disable_ir_video,
MODULE_PARM_DESC(disable_autoload_ir_video,
"1=do not try to autoload ir_video IR receiver");
-/* Mapping of IR schemes to known I2C addresses - if any */
-static const unsigned char ir_video_addresses[] = {
- [PVR2_IR_SCHEME_ZILOG] = 0x71,
- [PVR2_IR_SCHEME_29XXX] = 0x18,
- [PVR2_IR_SCHEME_24XXX] = 0x18,
-};
-
static int pvr2_i2c_write(struct pvr2_hdw *hdw, /* Context */
u8 i2c_addr, /* I2C address we're talking to */
u8 *data, /* Data to write */
@@ -574,26 +568,56 @@ static void do_i2c_scan(struct pvr2_hdw *hdw)
static void pvr2_i2c_register_ir(struct pvr2_hdw *hdw)
{
struct i2c_board_info info;
- unsigned char addr = 0;
+ struct IR_i2c_init_data *init_data = &hdw->ir_init_data;
if (pvr2_disable_ir_video) {
pvr2_trace(PVR2_TRACE_INFO,
"Automatic binding of ir_video has been disabled.");
return;
}
- if (hdw->ir_scheme_active < ARRAY_SIZE(ir_video_addresses)) {
- addr = ir_video_addresses[hdw->ir_scheme_active];
- }
- if (!addr) {
+ memset(&info, 0, sizeof(struct i2c_board_info));
+ switch (hdw->ir_scheme_active) {
+ case PVR2_IR_SCHEME_24XXX: /* FX2-controlled IR */
+ case PVR2_IR_SCHEME_29XXX: /* Original 29xxx device */
+ init_data->ir_codes = RC_MAP_HAUPPAUGE_NEW;
+ init_data->internal_get_key_func = IR_KBD_GET_KEY_HAUP;
+ init_data->type = RC_TYPE_RC5;
+ init_data->name = hdw->hdw_desc->description;
+ init_data->polling_interval = 100; /* ms From ir-kbd-i2c */
+ /* IR Receiver */
+ info.addr = 0x18;
+ info.platform_data = init_data;
+ strlcpy(info.type, "ir_video", I2C_NAME_SIZE);
+ pvr2_trace(PVR2_TRACE_INFO, "Binding %s to i2c address 0x%02x.",
+ info.type, info.addr);
+ i2c_new_device(&hdw->i2c_adap, &info);
+ break;
+ case PVR2_IR_SCHEME_ZILOG: /* HVR-1950 style */
+ case PVR2_IR_SCHEME_24XXX_MCE: /* 24xxx MCE device */
+ init_data->ir_codes = RC_MAP_HAUPPAUGE_NEW;
+ init_data->internal_get_key_func = IR_KBD_GET_KEY_HAUP_XVR;
+ init_data->type = RC_TYPE_RC5;
+ init_data->name = hdw->hdw_desc->description;
+ init_data->polling_interval = 260; /* ms From lirc_zilog */
+ /* IR Receiver */
+ info.addr = 0x71;
+ info.platform_data = init_data;
+ strlcpy(info.type, "ir_rx_z8f0811_haup", I2C_NAME_SIZE);
+ pvr2_trace(PVR2_TRACE_INFO, "Binding %s to i2c address 0x%02x.",
+ info.type, info.addr);
+ i2c_new_device(&hdw->i2c_adap, &info);
+ /* IR Trasmitter */
+ info.addr = 0x70;
+ info.platform_data = init_data;
+ strlcpy(info.type, "ir_tx_z8f0811_haup", I2C_NAME_SIZE);
+ pvr2_trace(PVR2_TRACE_INFO, "Binding %s to i2c address 0x%02x.",
+ info.type, info.addr);
+ i2c_new_device(&hdw->i2c_adap, &info);
+ break;
+ default:
/* The device either doesn't support I2C-based IR or we
don't know (yet) how to operate IR on the device. */
- return;
+ break;
}
- pvr2_trace(PVR2_TRACE_INFO,
- "Binding ir_video to i2c address 0x%02x.", addr);
- memset(&info, 0, sizeof(struct i2c_board_info));
- strlcpy(info.type, "ir_video", I2C_NAME_SIZE);
- info.addr = addr;
- i2c_new_device(&hdw->i2c_adap, &info);
}
void pvr2_i2c_core_init(struct pvr2_hdw *hdw)
diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c
index e7aa588..deb8fcf 100644
--- a/drivers/media/video/saa7134/saa7134-cards.c
+++ b/drivers/media/video/saa7134/saa7134-cards.c
@@ -5179,18 +5179,8 @@ struct saa7134_board saa7134_boards[] = {
[SAA7134_BOARD_KWORLD_PCI_SBTVD_FULLSEG] = {
.name = "Kworld PCI SBTVD/ISDB-T Full-Seg Hybrid",
.audio_clock = 0x00187de7,
-#if 0
- /*
- * FIXME: Analog mode doesn't work, if digital is enabled. The proper
- * fix is to use tda8290 driver, but Kworld seems to use an
- * unsupported version of tda8295.
- */
- .tuner_type = TUNER_NXP_TDA18271, /* TUNER_PHILIPS_TDA8290 */
- .tuner_addr = 0x60,
-#else
- .tuner_type = UNSET,
+ .tuner_type = TUNER_PHILIPS_TDA8290,
.tuner_addr = ADDR_UNSET,
-#endif
.radio_type = UNSET,
.radio_addr = ADDR_UNSET,
.gpiomask = 0x8e054000,
@@ -6932,10 +6922,17 @@ static inline int saa7134_kworld_sbtvd_toggle_agc(struct saa7134_dev *dev,
/* toggle AGC switch through GPIO 27 */
switch (mode) {
case TDA18271_ANALOG:
- saa7134_set_gpio(dev, 27, 0);
+ saa_writel(SAA7134_GPIO_GPMODE0 >> 2, 0x4000);
+ saa_writel(SAA7134_GPIO_GPSTATUS0 >> 2, 0x4000);
+ msleep(20);
break;
case TDA18271_DIGITAL:
- saa7134_set_gpio(dev, 27, 1);
+ saa_writel(SAA7134_GPIO_GPMODE0 >> 2, 0x14000);
+ saa_writel(SAA7134_GPIO_GPSTATUS0 >> 2, 0x14000);
+ msleep(20);
+ saa_writel(SAA7134_GPIO_GPMODE0 >> 2, 0x54000);
+ saa_writel(SAA7134_GPIO_GPSTATUS0 >> 2, 0x54000);
+ msleep(30);
break;
default:
return -EINVAL;
@@ -6993,6 +6990,7 @@ static int saa7134_tda8290_callback(struct saa7134_dev *dev,
int saa7134_tuner_callback(void *priv, int component, int command, int arg)
{
struct saa7134_dev *dev = priv;
+
if (dev != NULL) {
switch (dev->tuner_type) {
case TUNER_PHILIPS_TDA8290:
@@ -7659,36 +7657,11 @@ int saa7134_board_init2(struct saa7134_dev *dev)
break;
}
case SAA7134_BOARD_KWORLD_PCI_SBTVD_FULLSEG:
- {
- struct i2c_msg msg = { .addr = 0x4b, .flags = 0 };
- int i;
- static u8 buffer[][2] = {
- {0x30, 0x31},
- {0xff, 0x00},
- {0x41, 0x03},
- {0x41, 0x1a},
- {0xff, 0x02},
- {0x34, 0x00},
- {0x45, 0x97},
- {0x45, 0xc1},
- };
saa_writel(SAA7134_GPIO_GPMODE0 >> 2, 0x4000);
saa_writel(SAA7134_GPIO_GPSTATUS0 >> 2, 0x4000);
- /*
- * FIXME: identify what device is at addr 0x4b and what means
- * this initialization
- */
- for (i = 0; i < ARRAY_SIZE(buffer); i++) {
- msg.buf = &buffer[i][0];
- msg.len = ARRAY_SIZE(buffer[0]);
- if (i2c_transfer(&dev->i2c_adap, &msg, 1) != 1)
- printk(KERN_WARNING
- "%s: Unable to enable tuner(%i).\n",
- dev->name, i);
- }
+ saa7134_set_gpio(dev, 27, 0);
break;
- }
} /* switch() */
/* initialize tuner */
diff --git a/drivers/media/video/saa7134/saa7134-dvb.c b/drivers/media/video/saa7134/saa7134-dvb.c
index 3315a48..f65cad2 100644
--- a/drivers/media/video/saa7134/saa7134-dvb.c
+++ b/drivers/media/video/saa7134/saa7134-dvb.c
@@ -237,12 +237,39 @@ static struct tda18271_std_map mb86a20s_tda18271_std_map = {
static struct tda18271_config kworld_tda18271_config = {
.std_map = &mb86a20s_tda18271_std_map,
.gate = TDA18271_GATE_DIGITAL,
+ .config = 3, /* Use tuner callback for AGC */
+
};
static const struct mb86a20s_config kworld_mb86a20s_config = {
.demod_address = 0x10,
};
+static int kworld_sbtvd_gate_ctrl(struct dvb_frontend* fe, int enable)
+{
+ struct saa7134_dev *dev = fe->dvb->priv;
+
+ unsigned char initmsg[] = {0x45, 0x97};
+ unsigned char msg_enable[] = {0x45, 0xc1};
+ unsigned char msg_disable[] = {0x45, 0x81};
+ struct i2c_msg msg = {.addr = 0x4b, .flags = 0, .buf = initmsg, .len = 2};
+
+ if (i2c_transfer(&dev->i2c_adap, &msg, 1) != 1) {
+ wprintk("could not access the I2C gate\n");
+ return -EIO;
+ }
+ if (enable)
+ msg.buf = msg_enable;
+ else
+ msg.buf = msg_disable;
+ if (i2c_transfer(&dev->i2c_adap, &msg, 1) != 1) {
+ wprintk("could not access the I2C gate\n");
+ return -EIO;
+ }
+ msleep(20);
+ return 0;
+}
+
/* ==================================================================
* tda1004x based DVB-T cards, helper functions
*/
@@ -623,37 +650,6 @@ static struct tda827x_config tda827x_cfg_2_sw42 = {
/* ------------------------------------------------------------------ */
-static int __kworld_sbtvd_i2c_gate_ctrl(struct saa7134_dev *dev, int enable)
-{
- unsigned char initmsg[] = {0x45, 0x97};
- unsigned char msg_enable[] = {0x45, 0xc1};
- unsigned char msg_disable[] = {0x45, 0x81};
- struct i2c_msg msg = {.addr = 0x4b, .flags = 0, .buf = initmsg, .len = 2};
-
- if (i2c_transfer(&dev->i2c_adap, &msg, 1) != 1) {
- wprintk("could not access the I2C gate\n");
- return -EIO;
- }
- if (enable)
- msg.buf = msg_enable;
- else
- msg.buf = msg_disable;
- if (i2c_transfer(&dev->i2c_adap, &msg, 1) != 1) {
- wprintk("could not access the I2C gate\n");
- return -EIO;
- }
- msleep(20);
- return 0;
-}
-static int kworld_sbtvd_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
-{
- struct saa7134_dev *dev = fe->dvb->priv;
-
- return __kworld_sbtvd_i2c_gate_ctrl(dev, enable);
-}
-
-/* ------------------------------------------------------------------ */
-
static struct tda1004x_config tda827x_lifeview_config = {
.demod_address = 0x08,
.invert = 1,
@@ -1660,27 +1656,23 @@ static int dvb_init(struct saa7134_dev *dev)
}
break;
case SAA7134_BOARD_KWORLD_PCI_SBTVD_FULLSEG:
- __kworld_sbtvd_i2c_gate_ctrl(dev, 0);
- saa_writel(SAA7134_GPIO_GPMODE0 >> 2, 0x14000);
- saa_writel(SAA7134_GPIO_GPSTATUS0 >> 2, 0x14000);
- msleep(20);
- saa_writel(SAA7134_GPIO_GPMODE0 >> 2, 0x54000);
- saa_writel(SAA7134_GPIO_GPSTATUS0 >> 2, 0x54000);
- msleep(20);
+ /* Switch to digital mode */
+ saa7134_tuner_callback(dev, 0,
+ TDA18271_CALLBACK_CMD_AGC_ENABLE, 1);
fe0->dvb.frontend = dvb_attach(mb86a20s_attach,
&kworld_mb86a20s_config,
&dev->i2c_adap);
- __kworld_sbtvd_i2c_gate_ctrl(dev, 1);
if (fe0->dvb.frontend != NULL) {
+ dvb_attach(tda829x_attach, fe0->dvb.frontend,
+ &dev->i2c_adap, 0x4b,
+ &tda829x_no_probe);
dvb_attach(tda18271_attach, fe0->dvb.frontend,
0x60, &dev->i2c_adap,
&kworld_tda18271_config);
- /*
- * Only after success, it can initialize the gate, otherwise
- * an OOPS will hit, due to kfree(fe0->dvb.frontend)
- */
- fe0->dvb.frontend->ops.i2c_gate_ctrl = kworld_sbtvd_i2c_gate_ctrl;
+ fe0->dvb.frontend->ops.i2c_gate_ctrl = kworld_sbtvd_gate_ctrl;
}
+
+ /* mb86a20s need to use the I2C gateway */
break;
default:
wprintk("Huh? unknown DVB card?\n");
diff --git a/drivers/media/video/sn9c102/sn9c102_devtable.h b/drivers/media/video/sn9c102/sn9c102_devtable.h
index 41064c7..b3d2cc7 100644
--- a/drivers/media/video/sn9c102/sn9c102_devtable.h
+++ b/drivers/media/video/sn9c102/sn9c102_devtable.h
@@ -47,8 +47,8 @@ static const struct usb_device_id sn9c102_id_table[] = {
{ SN9C102_USB_DEVICE(0x0c45, 0x6009, BRIDGE_SN9C102), },
{ SN9C102_USB_DEVICE(0x0c45, 0x600d, BRIDGE_SN9C102), },
/* { SN9C102_USB_DEVICE(0x0c45, 0x6011, BRIDGE_SN9C102), }, OV6650 */
-#endif
{ SN9C102_USB_DEVICE(0x0c45, 0x6019, BRIDGE_SN9C102), },
+#endif
{ SN9C102_USB_DEVICE(0x0c45, 0x6024, BRIDGE_SN9C102), },
{ SN9C102_USB_DEVICE(0x0c45, 0x6025, BRIDGE_SN9C102), },
#if !defined CONFIG_USB_GSPCA_SONIXB && !defined CONFIG_USB_GSPCA_SONIXB_MODULE
@@ -56,78 +56,68 @@ static const struct usb_device_id sn9c102_id_table[] = {
{ SN9C102_USB_DEVICE(0x0c45, 0x6029, BRIDGE_SN9C102), },
{ SN9C102_USB_DEVICE(0x0c45, 0x602a, BRIDGE_SN9C102), },
#endif
- { SN9C102_USB_DEVICE(0x0c45, 0x602b, BRIDGE_SN9C102), },
+ { SN9C102_USB_DEVICE(0x0c45, 0x602b, BRIDGE_SN9C102), }, /* not in sonixb */
#if !defined CONFIG_USB_GSPCA_SONIXB && !defined CONFIG_USB_GSPCA_SONIXB_MODULE
{ SN9C102_USB_DEVICE(0x0c45, 0x602c, BRIDGE_SN9C102), },
/* { SN9C102_USB_DEVICE(0x0c45, 0x602d, BRIDGE_SN9C102), }, HV7131R */
{ SN9C102_USB_DEVICE(0x0c45, 0x602e, BRIDGE_SN9C102), },
#endif
- { SN9C102_USB_DEVICE(0x0c45, 0x6030, BRIDGE_SN9C102), },
+ { SN9C102_USB_DEVICE(0x0c45, 0x6030, BRIDGE_SN9C102), }, /* not in sonixb */
/* SN9C103 */
- { SN9C102_USB_DEVICE(0x0c45, 0x6080, BRIDGE_SN9C103), },
- { SN9C102_USB_DEVICE(0x0c45, 0x6082, BRIDGE_SN9C103), },
+/* { SN9C102_USB_DEVICE(0x0c45, 0x6080, BRIDGE_SN9C103), }, non existent ? */
+ { SN9C102_USB_DEVICE(0x0c45, 0x6082, BRIDGE_SN9C103), }, /* not in sonixb */
+#if !defined CONFIG_USB_GSPCA_SONIXB && !defined CONFIG_USB_GSPCA_SONIXB_MODULE
/* { SN9C102_USB_DEVICE(0x0c45, 0x6083, BRIDGE_SN9C103), }, HY7131D/E */
- { SN9C102_USB_DEVICE(0x0c45, 0x6088, BRIDGE_SN9C103), },
- { SN9C102_USB_DEVICE(0x0c45, 0x608a, BRIDGE_SN9C103), },
- { SN9C102_USB_DEVICE(0x0c45, 0x608b, BRIDGE_SN9C103), },
+/* { SN9C102_USB_DEVICE(0x0c45, 0x6088, BRIDGE_SN9C103), }, non existent ? */
+/* { SN9C102_USB_DEVICE(0x0c45, 0x608a, BRIDGE_SN9C103), }, non existent ? */
+/* { SN9C102_USB_DEVICE(0x0c45, 0x608b, BRIDGE_SN9C103), }, non existent ? */
{ SN9C102_USB_DEVICE(0x0c45, 0x608c, BRIDGE_SN9C103), },
/* { SN9C102_USB_DEVICE(0x0c45, 0x608e, BRIDGE_SN9C103), }, CISVF10 */
-#if !defined CONFIG_USB_GSPCA_SONIXB && !defined CONFIG_USB_GSPCA_SONIXB_MODULE
{ SN9C102_USB_DEVICE(0x0c45, 0x608f, BRIDGE_SN9C103), },
-#endif
- { SN9C102_USB_DEVICE(0x0c45, 0x60a0, BRIDGE_SN9C103), },
- { SN9C102_USB_DEVICE(0x0c45, 0x60a2, BRIDGE_SN9C103), },
- { SN9C102_USB_DEVICE(0x0c45, 0x60a3, BRIDGE_SN9C103), },
+/* { SN9C102_USB_DEVICE(0x0c45, 0x60a0, BRIDGE_SN9C103), }, non existent ? */
+/* { SN9C102_USB_DEVICE(0x0c45, 0x60a2, BRIDGE_SN9C103), }, non existent ? */
+/* { SN9C102_USB_DEVICE(0x0c45, 0x60a3, BRIDGE_SN9C103), }, non existent ? */
/* { SN9C102_USB_DEVICE(0x0c45, 0x60a8, BRIDGE_SN9C103), }, PAS106 */
/* { SN9C102_USB_DEVICE(0x0c45, 0x60aa, BRIDGE_SN9C103), }, TAS5130 */
-/* { SN9C102_USB_DEVICE(0x0c45, 0x60ab, BRIDGE_SN9C103), }, TAS5130 */
- { SN9C102_USB_DEVICE(0x0c45, 0x60ac, BRIDGE_SN9C103), },
- { SN9C102_USB_DEVICE(0x0c45, 0x60ae, BRIDGE_SN9C103), },
+/* { SN9C102_USB_DEVICE(0x0c45, 0x60ab, BRIDGE_SN9C103), }, TAS5110, non existent */
+/* { SN9C102_USB_DEVICE(0x0c45, 0x60ac, BRIDGE_SN9C103), }, non existent ? */
+/* { SN9C102_USB_DEVICE(0x0c45, 0x60ae, BRIDGE_SN9C103), }, non existent ? */
{ SN9C102_USB_DEVICE(0x0c45, 0x60af, BRIDGE_SN9C103), },
-#if !defined CONFIG_USB_GSPCA_SONIXB && !defined CONFIG_USB_GSPCA_SONIXB_MODULE
{ SN9C102_USB_DEVICE(0x0c45, 0x60b0, BRIDGE_SN9C103), },
+/* { SN9C102_USB_DEVICE(0x0c45, 0x60b2, BRIDGE_SN9C103), }, non existent ? */
+/* { SN9C102_USB_DEVICE(0x0c45, 0x60b3, BRIDGE_SN9C103), }, non existent ? */
+/* { SN9C102_USB_DEVICE(0x0c45, 0x60b8, BRIDGE_SN9C103), }, non existent ? */
+/* { SN9C102_USB_DEVICE(0x0c45, 0x60ba, BRIDGE_SN9C103), }, non existent ? */
+/* { SN9C102_USB_DEVICE(0x0c45, 0x60bb, BRIDGE_SN9C103), }, non existent ? */
+/* { SN9C102_USB_DEVICE(0x0c45, 0x60bc, BRIDGE_SN9C103), }, non existent ? */
+/* { SN9C102_USB_DEVICE(0x0c45, 0x60be, BRIDGE_SN9C103), }, non existent ? */
#endif
- { SN9C102_USB_DEVICE(0x0c45, 0x60b2, BRIDGE_SN9C103), },
- { SN9C102_USB_DEVICE(0x0c45, 0x60b3, BRIDGE_SN9C103), },
- { SN9C102_USB_DEVICE(0x0c45, 0x60b8, BRIDGE_SN9C103), },
- { SN9C102_USB_DEVICE(0x0c45, 0x60ba, BRIDGE_SN9C103), },
- { SN9C102_USB_DEVICE(0x0c45, 0x60bb, BRIDGE_SN9C103), },
- { SN9C102_USB_DEVICE(0x0c45, 0x60bc, BRIDGE_SN9C103), },
- { SN9C102_USB_DEVICE(0x0c45, 0x60be, BRIDGE_SN9C103), },
/* SN9C105 */
#if !defined CONFIG_USB_GSPCA_SONIXJ && !defined CONFIG_USB_GSPCA_SONIXJ_MODULE
{ SN9C102_USB_DEVICE(0x045e, 0x00f5, BRIDGE_SN9C105), },
{ SN9C102_USB_DEVICE(0x045e, 0x00f7, BRIDGE_SN9C105), },
{ SN9C102_USB_DEVICE(0x0471, 0x0327, BRIDGE_SN9C105), },
{ SN9C102_USB_DEVICE(0x0471, 0x0328, BRIDGE_SN9C105), },
-#endif
{ SN9C102_USB_DEVICE(0x0c45, 0x60c0, BRIDGE_SN9C105), },
- { SN9C102_USB_DEVICE(0x0c45, 0x60c2, BRIDGE_SN9C105), },
- { SN9C102_USB_DEVICE(0x0c45, 0x60c8, BRIDGE_SN9C105), },
- { SN9C102_USB_DEVICE(0x0c45, 0x60cc, BRIDGE_SN9C105), },
- { SN9C102_USB_DEVICE(0x0c45, 0x60ea, BRIDGE_SN9C105), },
- { SN9C102_USB_DEVICE(0x0c45, 0x60ec, BRIDGE_SN9C105), },
- { SN9C102_USB_DEVICE(0x0c45, 0x60ef, BRIDGE_SN9C105), },
- { SN9C102_USB_DEVICE(0x0c45, 0x60fa, BRIDGE_SN9C105), },
+/* { SN9C102_USB_DEVICE(0x0c45, 0x60c2, BRIDGE_SN9C105), }, PO1030 */
+/* { SN9C102_USB_DEVICE(0x0c45, 0x60c8, BRIDGE_SN9C105), }, OM6801 */
+/* { SN9C102_USB_DEVICE(0x0c45, 0x60cc, BRIDGE_SN9C105), }, HV7131GP */
+/* { SN9C102_USB_DEVICE(0x0c45, 0x60ea, BRIDGE_SN9C105), }, non existent ? */
+/* { SN9C102_USB_DEVICE(0x0c45, 0x60ec, BRIDGE_SN9C105), }, MO4000 */
+/* { SN9C102_USB_DEVICE(0x0c45, 0x60ef, BRIDGE_SN9C105), }, ICM105C */
+/* { SN9C102_USB_DEVICE(0x0c45, 0x60fa, BRIDGE_SN9C105), }, OV7648 */
{ SN9C102_USB_DEVICE(0x0c45, 0x60fb, BRIDGE_SN9C105), },
{ SN9C102_USB_DEVICE(0x0c45, 0x60fc, BRIDGE_SN9C105), },
{ SN9C102_USB_DEVICE(0x0c45, 0x60fe, BRIDGE_SN9C105), },
/* SN9C120 */
{ SN9C102_USB_DEVICE(0x0458, 0x7025, BRIDGE_SN9C120), },
-#if !defined CONFIG_USB_GSPCA_SONIXJ && !defined CONFIG_USB_GSPCA_SONIXJ_MODULE
- { SN9C102_USB_DEVICE(0x0c45, 0x6102, BRIDGE_SN9C120), },
-#endif
- { SN9C102_USB_DEVICE(0x0c45, 0x6108, BRIDGE_SN9C120), },
- { SN9C102_USB_DEVICE(0x0c45, 0x610f, BRIDGE_SN9C120), },
-#if !defined CONFIG_USB_GSPCA_SONIXJ && !defined CONFIG_USB_GSPCA_SONIXJ_MODULE
+/* { SN9C102_USB_DEVICE(0x0c45, 0x6102, BRIDGE_SN9C120), }, po2030 */
+/* { SN9C102_USB_DEVICE(0x0c45, 0x6108, BRIDGE_SN9C120), }, om6801 */
+/* { SN9C102_USB_DEVICE(0x0c45, 0x610f, BRIDGE_SN9C120), }, S5K53BEB */
{ SN9C102_USB_DEVICE(0x0c45, 0x6130, BRIDGE_SN9C120), },
-#endif
/* { SN9C102_USB_DEVICE(0x0c45, 0x6138, BRIDGE_SN9C120), }, MO8000 */
-#if !defined CONFIG_USB_GSPCA_SONIXJ && !defined CONFIG_USB_GSPCA_SONIXJ_MODULE
{ SN9C102_USB_DEVICE(0x0c45, 0x613a, BRIDGE_SN9C120), },
-#endif
{ SN9C102_USB_DEVICE(0x0c45, 0x613b, BRIDGE_SN9C120), },
-#if !defined CONFIG_USB_GSPCA_SONIXJ && !defined CONFIG_USB_GSPCA_SONIXJ_MODULE
{ SN9C102_USB_DEVICE(0x0c45, 0x613c, BRIDGE_SN9C120), },
{ SN9C102_USB_DEVICE(0x0c45, 0x613e, BRIDGE_SN9C120), },
#endif
diff --git a/drivers/media/video/sr030pc30.c b/drivers/media/video/sr030pc30.c
index 864696b..c901721 100644
--- a/drivers/media/video/sr030pc30.c
+++ b/drivers/media/video/sr030pc30.c
@@ -714,15 +714,6 @@ static int sr030pc30_base_config(struct v4l2_subdev *sd)
return ret;
}
-static int sr030pc30_s_config(struct v4l2_subdev *sd,
- int irq, void *platform_data)
-{
- struct sr030pc30_info *info = to_sr030pc30(sd);
-
- info->pdata = platform_data;
- return 0;
-}
-
static int sr030pc30_s_stream(struct v4l2_subdev *sd, int enable)
{
return 0;
@@ -763,7 +754,6 @@ static int sr030pc30_s_power(struct v4l2_subdev *sd, int on)
}
static const struct v4l2_subdev_core_ops sr030pc30_core_ops = {
- .s_config = sr030pc30_s_config,
.s_power = sr030pc30_s_power,
.queryctrl = sr030pc30_queryctrl,
.s_ctrl = sr030pc30_s_ctrl,
diff --git a/drivers/media/video/tda9875.c b/drivers/media/video/tda9875.c
deleted file mode 100644
index 35b6ff5..0000000
--- a/drivers/media/video/tda9875.c
+++ /dev/null
@@ -1,411 +0,0 @@
-/*
- * For the TDA9875 chip
- * (The TDA9875 is used on the Diamond DTV2000 french version
- * Other cards probably use these chips as well.)
- * This driver will not complain if used with any
- * other i2c device with the same address.
- *
- * Copyright (c) 2000 Guillaume Delvit based on Gerd Knorr source and
- * Eric Sandeen
- * Copyright (c) 2006 Mauro Carvalho Chehab <mchehab@infradead.org>
- * This code is placed under the terms of the GNU General Public License
- * Based on tda9855.c by Steve VanDeBogart (vandebo@uclink.berkeley.edu)
- * Which was based on tda8425.c by Greg Alexander (c) 1998
- *
- * OPTIONS:
- * debug - set to 1 if you'd like to see debug messages
- *
- * Revision: 0.1 - original version
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/timer.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/slab.h>
-#include <linux/i2c.h>
-#include <linux/videodev2.h>
-#include <media/v4l2-device.h>
-#include <media/i2c-addr.h>
-
-static int debug; /* insmod parameter */
-module_param(debug, int, S_IRUGO | S_IWUSR);
-MODULE_LICENSE("GPL");
-
-
-/* This is a superset of the TDA9875 */
-struct tda9875 {
- struct v4l2_subdev sd;
- int rvol, lvol;
- int bass, treble;
-};
-
-static inline struct tda9875 *to_state(struct v4l2_subdev *sd)
-{
- return container_of(sd, struct tda9875, sd);
-}
-
-#define dprintk if (debug) printk
-
-/* The TDA9875 is made by Philips Semiconductor
- * http://www.semiconductors.philips.com
- * TDA9875: I2C-bus controlled DSP audio processor, FM demodulator
- *
- */
-
- /* subaddresses for TDA9875 */
-#define TDA9875_MUT 0x12 /*General mute (value --> 0b11001100*/
-#define TDA9875_CFG 0x01 /* Config register (value --> 0b00000000 */
-#define TDA9875_DACOS 0x13 /*DAC i/o select (ADC) 0b0000100*/
-#define TDA9875_LOSR 0x16 /*Line output select regirter 0b0100 0001*/
-
-#define TDA9875_CH1V 0x0c /*Channel 1 volume (mute)*/
-#define TDA9875_CH2V 0x0d /*Channel 2 volume (mute)*/
-#define TDA9875_SC1 0x14 /*SCART 1 in (mono)*/
-#define TDA9875_SC2 0x15 /*SCART 2 in (mono)*/
-
-#define TDA9875_ADCIS 0x17 /*ADC input select (mono) 0b0110 000*/
-#define TDA9875_AER 0x19 /*Audio effect (AVL+Pseudo) 0b0000 0110*/
-#define TDA9875_MCS 0x18 /*Main channel select (DAC) 0b0000100*/
-#define TDA9875_MVL 0x1a /* Main volume gauche */
-#define TDA9875_MVR 0x1b /* Main volume droite */
-#define TDA9875_MBA 0x1d /* Main Basse */
-#define TDA9875_MTR 0x1e /* Main treble */
-#define TDA9875_ACS 0x1f /* Auxilary channel select (FM) 0b0000000*/
-#define TDA9875_AVL 0x20 /* Auxilary volume gauche */
-#define TDA9875_AVR 0x21 /* Auxilary volume droite */
-#define TDA9875_ABA 0x22 /* Auxilary Basse */
-#define TDA9875_ATR 0x23 /* Auxilary treble */
-
-#define TDA9875_MSR 0x02 /* Monitor select register */
-#define TDA9875_C1MSB 0x03 /* Carrier 1 (FM) frequency register MSB */
-#define TDA9875_C1MIB 0x04 /* Carrier 1 (FM) frequency register (16-8]b */
-#define TDA9875_C1LSB 0x05 /* Carrier 1 (FM) frequency register LSB */
-#define TDA9875_C2MSB 0x06 /* Carrier 2 (nicam) frequency register MSB */
-#define TDA9875_C2MIB 0x07 /* Carrier 2 (nicam) frequency register (16-8]b */
-#define TDA9875_C2LSB 0x08 /* Carrier 2 (nicam) frequency register LSB */
-#define TDA9875_DCR 0x09 /* Demodulateur configuration regirter*/
-#define TDA9875_DEEM 0x0a /* FM de-emphasis regirter*/
-#define TDA9875_FMAT 0x0b /* FM Matrix regirter*/
-
-/* values */
-#define TDA9875_MUTE_ON 0xff /* general mute */
-#define TDA9875_MUTE_OFF 0xcc /* general no mute */
-
-
-
-/* Begin code */
-
-static int tda9875_write(struct v4l2_subdev *sd, int subaddr, unsigned char val)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- unsigned char buffer[2];
-
- v4l2_dbg(1, debug, sd, "Writing %d 0x%x\n", subaddr, val);
- buffer[0] = subaddr;
- buffer[1] = val;
- if (2 != i2c_master_send(client, buffer, 2)) {
- v4l2_warn(sd, "I/O error, trying (write %d 0x%x)\n",
- subaddr, val);
- return -1;
- }
- return 0;
-}
-
-
-static int i2c_read_register(struct i2c_client *client, int addr, int reg)
-{
- unsigned char write[1];
- unsigned char read[1];
- struct i2c_msg msgs[2] = {
- { addr, 0, 1, write },
- { addr, I2C_M_RD, 1, read }
- };
-
- write[0] = reg;
-
- if (2 != i2c_transfer(client->adapter, msgs, 2)) {
- v4l_warn(client, "I/O error (read2)\n");
- return -1;
- }
- v4l_dbg(1, debug, client, "chip_read2: reg%d=0x%x\n", reg, read[0]);
- return read[0];
-}
-
-static void tda9875_set(struct v4l2_subdev *sd)
-{
- struct tda9875 *tda = to_state(sd);
- unsigned char a;
-
- v4l2_dbg(1, debug, sd, "tda9875_set(%04x,%04x,%04x,%04x)\n",
- tda->lvol, tda->rvol, tda->bass, tda->treble);
-
- a = tda->lvol & 0xff;
- tda9875_write(sd, TDA9875_MVL, a);
- a =tda->rvol & 0xff;
- tda9875_write(sd, TDA9875_MVR, a);
- a =tda->bass & 0xff;
- tda9875_write(sd, TDA9875_MBA, a);
- a =tda->treble & 0xff;
- tda9875_write(sd, TDA9875_MTR, a);
-}
-
-static void do_tda9875_init(struct v4l2_subdev *sd)
-{
- struct tda9875 *t = to_state(sd);
-
- v4l2_dbg(1, debug, sd, "In tda9875_init\n");
- tda9875_write(sd, TDA9875_CFG, 0xd0); /*reg de config 0 (reset)*/
- tda9875_write(sd, TDA9875_MSR, 0x03); /* Monitor 0b00000XXX*/
- tda9875_write(sd, TDA9875_C1MSB, 0x00); /*Car1(FM) MSB XMHz*/
- tda9875_write(sd, TDA9875_C1MIB, 0x00); /*Car1(FM) MIB XMHz*/
- tda9875_write(sd, TDA9875_C1LSB, 0x00); /*Car1(FM) LSB XMHz*/
- tda9875_write(sd, TDA9875_C2MSB, 0x00); /*Car2(NICAM) MSB XMHz*/
- tda9875_write(sd, TDA9875_C2MIB, 0x00); /*Car2(NICAM) MIB XMHz*/
- tda9875_write(sd, TDA9875_C2LSB, 0x00); /*Car2(NICAM) LSB XMHz*/
- tda9875_write(sd, TDA9875_DCR, 0x00); /*Demod config 0x00*/
- tda9875_write(sd, TDA9875_DEEM, 0x44); /*DE-Emph 0b0100 0100*/
- tda9875_write(sd, TDA9875_FMAT, 0x00); /*FM Matrix reg 0x00*/
- tda9875_write(sd, TDA9875_SC1, 0x00); /* SCART 1 (SC1)*/
- tda9875_write(sd, TDA9875_SC2, 0x01); /* SCART 2 (sc2)*/
-
- tda9875_write(sd, TDA9875_CH1V, 0x10); /* Channel volume 1 mute*/
- tda9875_write(sd, TDA9875_CH2V, 0x10); /* Channel volume 2 mute */
- tda9875_write(sd, TDA9875_DACOS, 0x02); /* sig DAC i/o(in:nicam)*/
- tda9875_write(sd, TDA9875_ADCIS, 0x6f); /* sig ADC input(in:mono)*/
- tda9875_write(sd, TDA9875_LOSR, 0x00); /* line out (in:mono)*/
- tda9875_write(sd, TDA9875_AER, 0x00); /*06 Effect (AVL+PSEUDO) */
- tda9875_write(sd, TDA9875_MCS, 0x44); /* Main ch select (DAC) */
- tda9875_write(sd, TDA9875_MVL, 0x03); /* Vol Main left 10dB */
- tda9875_write(sd, TDA9875_MVR, 0x03); /* Vol Main right 10dB*/
- tda9875_write(sd, TDA9875_MBA, 0x00); /* Main Bass Main 0dB*/
- tda9875_write(sd, TDA9875_MTR, 0x00); /* Main Treble Main 0dB*/
- tda9875_write(sd, TDA9875_ACS, 0x44); /* Aux chan select (dac)*/
- tda9875_write(sd, TDA9875_AVL, 0x00); /* Vol Aux left 0dB*/
- tda9875_write(sd, TDA9875_AVR, 0x00); /* Vol Aux right 0dB*/
- tda9875_write(sd, TDA9875_ABA, 0x00); /* Aux Bass Main 0dB*/
- tda9875_write(sd, TDA9875_ATR, 0x00); /* Aux Aigus Main 0dB*/
-
- tda9875_write(sd, TDA9875_MUT, 0xcc); /* General mute */
-
- t->lvol = t->rvol = 0; /* 0dB */
- t->bass = 0; /* 0dB */
- t->treble = 0; /* 0dB */
- tda9875_set(sd);
-}
-
-
-static int tda9875_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
-{
- struct tda9875 *t = to_state(sd);
-
- switch (ctrl->id) {
- case V4L2_CID_AUDIO_VOLUME:
- {
- int left = (t->lvol+84)*606;
- int right = (t->rvol+84)*606;
-
- ctrl->value=max(left,right);
- return 0;
- }
- case V4L2_CID_AUDIO_BALANCE:
- {
- int left = (t->lvol+84)*606;
- int right = (t->rvol+84)*606;
- int volume = max(left,right);
- int balance = (32768*min(left,right))/
- (volume ? volume : 1);
- ctrl->value=(left<right)?
- (65535-balance) : balance;
- return 0;
- }
- case V4L2_CID_AUDIO_BASS:
- ctrl->value = (t->bass+12)*2427; /* min -12 max +15 */
- return 0;
- case V4L2_CID_AUDIO_TREBLE:
- ctrl->value = (t->treble+12)*2730;/* min -12 max +12 */
- return 0;
- }
- return -EINVAL;
-}
-
-static int tda9875_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
-{
- struct tda9875 *t = to_state(sd);
- int chvol = 0, volume = 0, balance = 0, left, right;
-
- switch (ctrl->id) {
- case V4L2_CID_AUDIO_VOLUME:
- left = (t->lvol+84)*606;
- right = (t->rvol+84)*606;
-
- volume = max(left,right);
- balance = (32768*min(left,right))/
- (volume ? volume : 1);
- balance =(left<right)?
- (65535-balance) : balance;
-
- volume = ctrl->value;
-
- chvol=1;
- break;
- case V4L2_CID_AUDIO_BALANCE:
- left = (t->lvol+84)*606;
- right = (t->rvol+84)*606;
-
- volume=max(left,right);
-
- balance = ctrl->value;
-
- chvol=1;
- break;
- case V4L2_CID_AUDIO_BASS:
- t->bass = ((ctrl->value/2400)-12) & 0xff;
- if (t->bass > 15)
- t->bass = 15;
- if (t->bass < -12)
- t->bass = -12 & 0xff;
- break;
- case V4L2_CID_AUDIO_TREBLE:
- t->treble = ((ctrl->value/2700)-12) & 0xff;
- if (t->treble > 12)
- t->treble = 12;
- if (t->treble < -12)
- t->treble = -12 & 0xff;
- break;
- default:
- return -EINVAL;
- }
-
- if (chvol) {
- left = (min(65536 - balance,32768) *
- volume) / 32768;
- right = (min(balance,32768) *
- volume) / 32768;
- t->lvol = ((left/606)-84) & 0xff;
- if (t->lvol > 24)
- t->lvol = 24;
- if (t->lvol < -84)
- t->lvol = -84 & 0xff;
-
- t->rvol = ((right/606)-84) & 0xff;
- if (t->rvol > 24)
- t->rvol = 24;
- if (t->rvol < -84)
- t->rvol = -84 & 0xff;
- }
-
- tda9875_set(sd);
- return 0;
-}
-
-static int tda9875_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
-{
- switch (qc->id) {
- case V4L2_CID_AUDIO_VOLUME:
- return v4l2_ctrl_query_fill(qc, 0, 65535, 65535 / 100, 58880);
- case V4L2_CID_AUDIO_BASS:
- case V4L2_CID_AUDIO_TREBLE:
- return v4l2_ctrl_query_fill(qc, 0, 65535, 65535 / 100, 32768);
- }
- return -EINVAL;
-}
-
-/* ----------------------------------------------------------------------- */
-
-static const struct v4l2_subdev_core_ops tda9875_core_ops = {
- .queryctrl = tda9875_queryctrl,
- .g_ctrl = tda9875_g_ctrl,
- .s_ctrl = tda9875_s_ctrl,
-};
-
-static const struct v4l2_subdev_ops tda9875_ops = {
- .core = &tda9875_core_ops,
-};
-
-/* ----------------------------------------------------------------------- */
-
-
-/* *********************** *
- * i2c interface functions *
- * *********************** */
-
-static int tda9875_checkit(struct i2c_client *client, int addr)
-{
- int dic, rev;
-
- dic = i2c_read_register(client, addr, 254);
- rev = i2c_read_register(client, addr, 255);
-
- if (dic == 0 || dic == 2) { /* tda9875 and tda9875A */
- v4l_info(client, "tda9875%s rev. %d detected at 0x%02x\n",
- dic == 0 ? "" : "A", rev, addr << 1);
- return 1;
- }
- v4l_info(client, "no such chip at 0x%02x (dic=0x%x rev=0x%x)\n",
- addr << 1, dic, rev);
- return 0;
-}
-
-static int tda9875_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
-{
- struct tda9875 *t;
- struct v4l2_subdev *sd;
-
- v4l_info(client, "chip found @ 0x%02x (%s)\n",
- client->addr << 1, client->adapter->name);
-
- if (!tda9875_checkit(client, client->addr))
- return -ENODEV;
-
- t = kzalloc(sizeof(*t), GFP_KERNEL);
- if (!t)
- return -ENOMEM;
- sd = &t->sd;
- v4l2_i2c_subdev_init(sd, client, &tda9875_ops);
-
- do_tda9875_init(sd);
- return 0;
-}
-
-static int tda9875_remove(struct i2c_client *client)
-{
- struct v4l2_subdev *sd = i2c_get_clientdata(client);
-
- do_tda9875_init(sd);
- v4l2_device_unregister_subdev(sd);
- kfree(to_state(sd));
- return 0;
-}
-
-static const struct i2c_device_id tda9875_id[] = {
- { "tda9875", 0 },
- { }
-};
-MODULE_DEVICE_TABLE(i2c, tda9875_id);
-
-static struct i2c_driver tda9875_driver = {
- .driver = {
- .owner = THIS_MODULE,
- .name = "tda9875",
- },
- .probe = tda9875_probe,
- .remove = tda9875_remove,
- .id_table = tda9875_id,
-};
-
-static __init int init_tda9875(void)
-{
- return i2c_add_driver(&tda9875_driver);
-}
-
-static __exit void exit_tda9875(void)
-{
- i2c_del_driver(&tda9875_driver);
-}
-
-module_init(init_tda9875);
-module_exit(exit_tda9875);
diff --git a/drivers/media/video/tlg2300/pd-video.c b/drivers/media/video/tlg2300/pd-video.c
index a1ffe18..df33a1d 100644
--- a/drivers/media/video/tlg2300/pd-video.c
+++ b/drivers/media/video/tlg2300/pd-video.c
@@ -512,19 +512,20 @@ int alloc_bulk_urbs_generic(struct urb **urb_array, int num,
int buf_size, gfp_t gfp_flags,
usb_complete_t complete_fn, void *context)
{
- struct urb *urb;
- void *mem;
- int i;
+ int i = 0;
- for (i = 0; i < num; i++) {
- urb = usb_alloc_urb(0, gfp_flags);
+ for (; i < num; i++) {
+ void *mem;
+ struct urb *urb = usb_alloc_urb(0, gfp_flags);
if (urb == NULL)
return i;
mem = usb_alloc_coherent(udev, buf_size, gfp_flags,
&urb->transfer_dma);
- if (mem == NULL)
+ if (mem == NULL) {
+ usb_free_urb(urb);
return i;
+ }
usb_fill_bulk_urb(urb, udev, usb_rcvbulkpipe(udev, ep_addr),
mem, buf_size, complete_fn, context);
diff --git a/drivers/media/video/v4l2-common.c b/drivers/media/video/v4l2-common.c
index 3f0871b..810eef4 100644
--- a/drivers/media/video/v4l2-common.c
+++ b/drivers/media/video/v4l2-common.c
@@ -407,18 +407,6 @@ struct v4l2_subdev *v4l2_i2c_new_subdev_board(struct v4l2_device *v4l2_dev,
/* Decrease the module use count to match the first try_module_get. */
module_put(client->driver->driver.owner);
- if (sd) {
- /* We return errors from v4l2_subdev_call only if we have the
- callback as the .s_config is not mandatory */
- int err = v4l2_subdev_call(sd, core, s_config,
- info->irq, info->platform_data);
-
- if (err && err != -ENOIOCTLCMD) {
- v4l2_device_unregister_subdev(sd);
- sd = NULL;
- }
- }
-
error:
/* If we have a client but no subdev, then something went wrong and
we must unregister the client. */
@@ -428,9 +416,8 @@ error:
}
EXPORT_SYMBOL_GPL(v4l2_i2c_new_subdev_board);
-struct v4l2_subdev *v4l2_i2c_new_subdev_cfg(struct v4l2_device *v4l2_dev,
+struct v4l2_subdev *v4l2_i2c_new_subdev(struct v4l2_device *v4l2_dev,
struct i2c_adapter *adapter, const char *client_type,
- int irq, void *platform_data,
u8 addr, const unsigned short *probe_addrs)
{
struct i2c_board_info info;
@@ -440,12 +427,10 @@ struct v4l2_subdev *v4l2_i2c_new_subdev_cfg(struct v4l2_device *v4l2_dev,
memset(&info, 0, sizeof(info));
strlcpy(info.type, client_type, sizeof(info.type));
info.addr = addr;
- info.irq = irq;
- info.platform_data = platform_data;
return v4l2_i2c_new_subdev_board(v4l2_dev, adapter, &info, probe_addrs);
}
-EXPORT_SYMBOL_GPL(v4l2_i2c_new_subdev_cfg);
+EXPORT_SYMBOL_GPL(v4l2_i2c_new_subdev);
/* Return i2c client address of v4l2_subdev. */
unsigned short v4l2_i2c_subdev_addr(struct v4l2_subdev *sd)
diff --git a/drivers/media/video/v4l2-ctrls.c b/drivers/media/video/v4l2-ctrls.c
index 8f81efc..ef66d2a 100644
--- a/drivers/media/video/v4l2-ctrls.c
+++ b/drivers/media/video/v4l2-ctrls.c
@@ -569,7 +569,7 @@ static int user_to_new(struct v4l2_ext_control *c,
int ret;
u32 size;
- ctrl->has_new = 1;
+ ctrl->is_new = 1;
switch (ctrl->type) {
case V4L2_CTRL_TYPE_INTEGER64:
ctrl->val64 = c->value64;
@@ -1280,8 +1280,12 @@ int v4l2_ctrl_handler_setup(struct v4l2_ctrl_handler *hdl)
if (ctrl->done)
continue;
- for (i = 0; i < master->ncontrols; i++)
- cur_to_new(master->cluster[i]);
+ for (i = 0; i < master->ncontrols; i++) {
+ if (master->cluster[i]) {
+ cur_to_new(master->cluster[i]);
+ master->cluster[i]->is_new = 1;
+ }
+ }
/* Skip button controls and read-only controls. */
if (ctrl->type == V4L2_CTRL_TYPE_BUTTON ||
@@ -1340,12 +1344,15 @@ int v4l2_queryctrl(struct v4l2_ctrl_handler *hdl, struct v4l2_queryctrl *qc)
ctrl = ref->ctrl;
memset(qc, 0, sizeof(*qc));
- qc->id = ctrl->id;
+ if (id >= V4L2_CID_PRIVATE_BASE)
+ qc->id = id;
+ else
+ qc->id = ctrl->id;
strlcpy(qc->name, ctrl->name, sizeof(qc->name));
qc->minimum = ctrl->minimum;
qc->maximum = ctrl->maximum;
qc->default_value = ctrl->default_value;
- if (qc->type == V4L2_CTRL_TYPE_MENU)
+ if (ctrl->type == V4L2_CTRL_TYPE_MENU)
qc->step = 1;
else
qc->step = ctrl->step;
@@ -1645,7 +1652,7 @@ static int try_or_set_control_cluster(struct v4l2_ctrl *master, bool set)
if (ctrl == NULL)
continue;
- if (ctrl->has_new) {
+ if (ctrl->is_new) {
/* Double check this: it may have changed since the
last check in try_or_set_ext_ctrls(). */
if (set && (ctrl->flags & V4L2_CTRL_FLAG_GRABBED))
@@ -1719,13 +1726,13 @@ static int try_or_set_ext_ctrls(struct v4l2_ctrl_handler *hdl,
v4l2_ctrl_lock(ctrl);
- /* Reset the 'has_new' flags of the cluster */
+ /* Reset the 'is_new' flags of the cluster */
for (j = 0; j < master->ncontrols; j++)
if (master->cluster[j])
- master->cluster[j]->has_new = 0;
+ master->cluster[j]->is_new = 0;
/* Copy the new caller-supplied control values.
- user_to_new() sets 'has_new' to 1. */
+ user_to_new() sets 'is_new' to 1. */
ret = cluster_walk(i, cs, helpers, user_to_new);
if (!ret)
@@ -1820,15 +1827,18 @@ static int set_ctrl(struct v4l2_ctrl *ctrl, s32 *val)
int ret;
int i;
+ if (ctrl->flags & V4L2_CTRL_FLAG_READ_ONLY)
+ return -EACCES;
+
v4l2_ctrl_lock(ctrl);
- /* Reset the 'has_new' flags of the cluster */
+ /* Reset the 'is_new' flags of the cluster */
for (i = 0; i < master->ncontrols; i++)
if (master->cluster[i])
- master->cluster[i]->has_new = 0;
+ master->cluster[i]->is_new = 0;
ctrl->val = *val;
- ctrl->has_new = 1;
+ ctrl->is_new = 1;
ret = try_or_set_control_cluster(master, false);
if (!ret)
ret = try_or_set_control_cluster(master, true);
diff --git a/drivers/media/video/v4l2-dev.c b/drivers/media/video/v4l2-dev.c
index 359e232..341764a 100644
--- a/drivers/media/video/v4l2-dev.c
+++ b/drivers/media/video/v4l2-dev.c
@@ -419,6 +419,10 @@ static int get_index(struct video_device *vdev)
* The registration code assigns minor numbers and device node numbers
* based on the requested type and registers the new device node with
* the kernel.
+ *
+ * This function assumes that struct video_device was zeroed when it
+ * was allocated and does not contain any stale date.
+ *
* An error is returned if no free minor or device node number could be
* found, or if the registration of the device node failed.
*
@@ -440,7 +444,6 @@ static int __video_register_device(struct video_device *vdev, int type, int nr,
int minor_offset = 0;
int minor_cnt = VIDEO_NUM_DEVICES;
const char *name_base;
- void *priv = vdev->dev.p;
/* A minor value of -1 marks this video device as never
having been registered */
@@ -559,10 +562,6 @@ static int __video_register_device(struct video_device *vdev, int type, int nr,
}
/* Part 4: register the device with sysfs */
- memset(&vdev->dev, 0, sizeof(vdev->dev));
- /* The memset above cleared the device's device_private, so
- put back the copy we made earlier. */
- vdev->dev.p = priv;
vdev->dev.class = &video_class;
vdev->dev.devt = MKDEV(VIDEO_MAJOR, vdev->minor);
if (vdev->parent)
diff --git a/drivers/media/video/v4l2-device.c b/drivers/media/video/v4l2-device.c
index 7fe6f92..ce64fe1 100644
--- a/drivers/media/video/v4l2-device.c
+++ b/drivers/media/video/v4l2-device.c
@@ -100,6 +100,7 @@ void v4l2_device_unregister(struct v4l2_device *v4l2_dev)
is a platform bus, then it is never deleted. */
if (client)
i2c_unregister_device(client);
+ continue;
}
#endif
#if defined(CONFIG_SPI)
@@ -108,6 +109,7 @@ void v4l2_device_unregister(struct v4l2_device *v4l2_dev)
if (spi)
spi_unregister_device(spi);
+ continue;
}
#endif
}
@@ -126,11 +128,19 @@ int v4l2_device_register_subdev(struct v4l2_device *v4l2_dev,
WARN_ON(sd->v4l2_dev != NULL);
if (!try_module_get(sd->owner))
return -ENODEV;
+ sd->v4l2_dev = v4l2_dev;
+ if (sd->internal_ops && sd->internal_ops->registered) {
+ err = sd->internal_ops->registered(sd);
+ if (err)
+ return err;
+ }
/* This just returns 0 if either of the two args is NULL */
err = v4l2_ctrl_add_handler(v4l2_dev->ctrl_handler, sd->ctrl_handler);
- if (err)
+ if (err) {
+ if (sd->internal_ops && sd->internal_ops->unregistered)
+ sd->internal_ops->unregistered(sd);
return err;
- sd->v4l2_dev = v4l2_dev;
+ }
spin_lock(&v4l2_dev->lock);
list_add_tail(&sd->list, &v4l2_dev->subdevs);
spin_unlock(&v4l2_dev->lock);
@@ -146,6 +156,8 @@ void v4l2_device_unregister_subdev(struct v4l2_subdev *sd)
spin_lock(&sd->v4l2_dev->lock);
list_del(&sd->list);
spin_unlock(&sd->v4l2_dev->lock);
+ if (sd->internal_ops && sd->internal_ops->unregistered)
+ sd->internal_ops->unregistered(sd);
sd->v4l2_dev = NULL;
module_put(sd->owner);
}
diff --git a/drivers/media/video/v4l2-ioctl.c b/drivers/media/video/v4l2-ioctl.c
index 7e47f15..f51327e 100644
--- a/drivers/media/video/v4l2-ioctl.c
+++ b/drivers/media/video/v4l2-ioctl.c
@@ -1659,20 +1659,24 @@ static long __video_do_ioctl(struct file *file,
{
struct v4l2_dbg_register *p = arg;
- if (!capable(CAP_SYS_ADMIN))
- ret = -EPERM;
- else if (ops->vidioc_g_register)
- ret = ops->vidioc_g_register(file, fh, p);
+ if (ops->vidioc_g_register) {
+ if (!capable(CAP_SYS_ADMIN))
+ ret = -EPERM;
+ else
+ ret = ops->vidioc_g_register(file, fh, p);
+ }
break;
}
case VIDIOC_DBG_S_REGISTER:
{
struct v4l2_dbg_register *p = arg;
- if (!capable(CAP_SYS_ADMIN))
- ret = -EPERM;
- else if (ops->vidioc_s_register)
- ret = ops->vidioc_s_register(file, fh, p);
+ if (ops->vidioc_s_register) {
+ if (!capable(CAP_SYS_ADMIN))
+ ret = -EPERM;
+ else
+ ret = ops->vidioc_s_register(file, fh, p);
+ }
break;
}
#endif
diff --git a/drivers/media/video/w9966.c b/drivers/media/video/w9966.c
index 019ee20..fa35639 100644
--- a/drivers/media/video/w9966.c
+++ b/drivers/media/video/w9966.c
@@ -937,6 +937,7 @@ static void w9966_term(struct w9966 *cam)
parport_unregister_device(cam->pdev);
w9966_set_state(cam, W9966_STATE_PDEV, 0);
}
+ memset(cam, 0, sizeof(*cam));
}
diff --git a/drivers/media/video/zoran/zoran_card.c b/drivers/media/video/zoran/zoran_card.c
index 9cdc3bb..9f2bac5 100644
--- a/drivers/media/video/zoran/zoran_card.c
+++ b/drivers/media/video/zoran/zoran_card.c
@@ -1041,7 +1041,7 @@ zr36057_init (struct zoran *zr)
/* allocate memory *before* doing anything to the hardware
* in case allocation fails */
zr->stat_com = kzalloc(BUZ_NUM_STAT_COM * 4, GFP_KERNEL);
- zr->video_dev = kmalloc(sizeof(struct video_device), GFP_KERNEL);
+ zr->video_dev = video_device_alloc();
if (!zr->stat_com || !zr->video_dev) {
dprintk(1,
KERN_ERR
diff --git a/drivers/mfd/88pm860x-core.c b/drivers/mfd/88pm860x-core.c
index 20895e7..793300c 100644
--- a/drivers/mfd/88pm860x-core.c
+++ b/drivers/mfd/88pm860x-core.c
@@ -361,12 +361,6 @@ static struct pm860x_irq_data pm860x_irqs[] = {
},
};
-static inline struct pm860x_irq_data *irq_to_pm860x(struct pm860x_chip *chip,
- int irq)
-{
- return &pm860x_irqs[irq - chip->irq_base];
-}
-
static irqreturn_t pm860x_irq(int irq, void *data)
{
struct pm860x_chip *chip = data;
@@ -388,16 +382,16 @@ static irqreturn_t pm860x_irq(int irq, void *data)
return IRQ_HANDLED;
}
-static void pm860x_irq_lock(unsigned int irq)
+static void pm860x_irq_lock(struct irq_data *data)
{
- struct pm860x_chip *chip = get_irq_chip_data(irq);
+ struct pm860x_chip *chip = irq_data_get_irq_chip_data(data);
mutex_lock(&chip->irq_lock);
}
-static void pm860x_irq_sync_unlock(unsigned int irq)
+static void pm860x_irq_sync_unlock(struct irq_data *data)
{
- struct pm860x_chip *chip = get_irq_chip_data(irq);
+ struct pm860x_chip *chip = irq_data_get_irq_chip_data(data);
struct pm860x_irq_data *irq_data;
struct i2c_client *i2c;
static unsigned char cached[3] = {0x0, 0x0, 0x0};
@@ -439,25 +433,25 @@ static void pm860x_irq_sync_unlock(unsigned int irq)
mutex_unlock(&chip->irq_lock);
}
-static void pm860x_irq_enable(unsigned int irq)
+static void pm860x_irq_enable(struct irq_data *data)
{
- struct pm860x_chip *chip = get_irq_chip_data(irq);
- pm860x_irqs[irq - chip->irq_base].enable
- = pm860x_irqs[irq - chip->irq_base].offs;
+ struct pm860x_chip *chip = irq_data_get_irq_chip_data(data);
+ pm860x_irqs[data->irq - chip->irq_base].enable
+ = pm860x_irqs[data->irq - chip->irq_base].offs;
}
-static void pm860x_irq_disable(unsigned int irq)
+static void pm860x_irq_disable(struct irq_data *data)
{
- struct pm860x_chip *chip = get_irq_chip_data(irq);
- pm860x_irqs[irq - chip->irq_base].enable = 0;
+ struct pm860x_chip *chip = irq_data_get_irq_chip_data(data);
+ pm860x_irqs[data->irq - chip->irq_base].enable = 0;
}
static struct irq_chip pm860x_irq_chip = {
.name = "88pm860x",
- .bus_lock = pm860x_irq_lock,
- .bus_sync_unlock = pm860x_irq_sync_unlock,
- .enable = pm860x_irq_enable,
- .disable = pm860x_irq_disable,
+ .irq_bus_lock = pm860x_irq_lock,
+ .irq_bus_sync_unlock = pm860x_irq_sync_unlock,
+ .irq_enable = pm860x_irq_enable,
+ .irq_disable = pm860x_irq_disable,
};
static int __devinit device_gpadc_init(struct pm860x_chip *chip,
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index da9d297..fd01836 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -496,13 +496,13 @@ config EZX_PCAP
config AB8500_CORE
bool "ST-Ericsson AB8500 Mixed Signal Power Management chip"
- depends on GENERIC_HARDIRQS && ABX500_CORE && SPI_MASTER && ARCH_U8500
+ depends on GENERIC_HARDIRQS && ABX500_CORE
select MFD_CORE
help
Select this option to enable access to AB8500 power management
- chip. This connects to U8500 either on the SSP/SPI bus
- or the I2C bus via PRCMU. It also adds the irq_chip
- parts for handling the Mixed Signal chip events.
+ chip. This connects to U8500 either on the SSP/SPI bus (deprecated
+ since hardware version v1.0) or the I2C bus via PRCMU. It also adds
+ the irq_chip parts for handling the Mixed Signal chip events.
This chip embeds various other multimedia funtionalities as well.
config AB8500_I2C_CORE
@@ -537,6 +537,14 @@ config AB3550_CORE
LEDs, vibrator, system power and temperature, power management
and ALSA sound.
+config MFD_CS5535
+ tristate "Support for CS5535 and CS5536 southbridge core functions"
+ select MFD_CORE
+ depends on PCI
+ ---help---
+ This is the core driver for CS5535/CS5536 MFD functions. This is
+ necessary for using the board's GPIO and MFGPT functionality.
+
config MFD_TIMBERDALE
tristate "Support for the Timberdale FPGA"
select MFD_CORE
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 848e7ea..a54e2c7 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -70,7 +70,7 @@ obj-$(CONFIG_ABX500_CORE) += abx500-core.o
obj-$(CONFIG_AB3100_CORE) += ab3100-core.o
obj-$(CONFIG_AB3100_OTP) += ab3100-otp.o
obj-$(CONFIG_AB3550_CORE) += ab3550-core.o
-obj-$(CONFIG_AB8500_CORE) += ab8500-core.o ab8500-spi.o
+obj-$(CONFIG_AB8500_CORE) += ab8500-core.o
obj-$(CONFIG_AB8500_I2C_CORE) += ab8500-i2c.o
obj-$(CONFIG_AB8500_DEBUG) += ab8500-debugfs.o
obj-$(CONFIG_MFD_TIMBERDALE) += timberdale.o
@@ -82,3 +82,4 @@ obj-$(CONFIG_MFD_JZ4740_ADC) += jz4740-adc.o
obj-$(CONFIG_MFD_TPS6586X) += tps6586x.o
obj-$(CONFIG_MFD_VX855) += vx855.o
obj-$(CONFIG_MFD_WL1273_CORE) += wl1273-core.o
+obj-$(CONFIG_MFD_CS5535) += cs5535-mfd.o
diff --git a/drivers/mfd/ab3550-core.c b/drivers/mfd/ab3550-core.c
index 8a98739..5fbca34 100644
--- a/drivers/mfd/ab3550-core.c
+++ b/drivers/mfd/ab3550-core.c
@@ -1159,15 +1159,16 @@ static void ab3550_mask_work(struct work_struct *work)
}
}
-static void ab3550_mask(unsigned int irq)
+static void ab3550_mask(struct irq_data *data)
{
unsigned long flags;
struct ab3550 *ab;
struct ab3550_platform_data *plf_data;
+ int irq;
- ab = get_irq_chip_data(irq);
+ ab = irq_data_get_irq_chip_data(data);
plf_data = ab->i2c_client[0]->dev.platform_data;
- irq -= plf_data->irq.base;
+ irq = data->irq - plf_data->irq.base;
spin_lock_irqsave(&ab->event_lock, flags);
ab->event_mask[irq / 8] |= BIT(irq % 8);
@@ -1176,15 +1177,16 @@ static void ab3550_mask(unsigned int irq)
schedule_work(&ab->mask_work);
}
-static void ab3550_unmask(unsigned int irq)
+static void ab3550_unmask(struct irq_data *data)
{
unsigned long flags;
struct ab3550 *ab;
struct ab3550_platform_data *plf_data;
+ int irq;
- ab = get_irq_chip_data(irq);
+ ab = irq_data_get_irq_chip_data(data);
plf_data = ab->i2c_client[0]->dev.platform_data;
- irq -= plf_data->irq.base;
+ irq = data->irq - plf_data->irq.base;
spin_lock_irqsave(&ab->event_lock, flags);
ab->event_mask[irq / 8] &= ~BIT(irq % 8);
@@ -1193,20 +1195,16 @@ static void ab3550_unmask(unsigned int irq)
schedule_work(&ab->mask_work);
}
-static void noop(unsigned int irq)
+static void noop(struct irq_data *data)
{
}
static struct irq_chip ab3550_irq_chip = {
.name = "ab3550-core", /* Keep the same name as the request */
- .startup = NULL, /* defaults to enable */
- .shutdown = NULL, /* defaults to disable */
- .enable = NULL, /* defaults to unmask */
- .disable = ab3550_mask, /* No default to mask in chip.c */
- .ack = noop,
- .mask = ab3550_mask,
- .unmask = ab3550_unmask,
- .end = NULL,
+ .irq_disable = ab3550_mask, /* No default to mask in chip.c */
+ .irq_ack = noop,
+ .irq_mask = ab3550_mask,
+ .irq_unmask = ab3550_unmask,
};
struct ab_family_id {
diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c
index d9640a6..b688701 100644
--- a/drivers/mfd/ab8500-core.c
+++ b/drivers/mfd/ab8500-core.c
@@ -52,6 +52,7 @@
#define AB8500_IT_LATCH8_REG 0x27
#define AB8500_IT_LATCH9_REG 0x28
#define AB8500_IT_LATCH10_REG 0x29
+#define AB8500_IT_LATCH12_REG 0x2B
#define AB8500_IT_LATCH19_REG 0x32
#define AB8500_IT_LATCH20_REG 0x33
#define AB8500_IT_LATCH21_REG 0x34
@@ -98,13 +99,17 @@
* offset 0.
*/
static const int ab8500_irq_regoffset[AB8500_NUM_IRQ_REGS] = {
- 0, 1, 2, 3, 4, 6, 7, 8, 9, 18, 19, 20, 21,
+ 0, 1, 2, 3, 4, 6, 7, 8, 9, 11, 18, 19, 20, 21,
};
static int ab8500_get_chip_id(struct device *dev)
{
- struct ab8500 *ab8500 = dev_get_drvdata(dev->parent);
- return (int)ab8500->chip_id;
+ struct ab8500 *ab8500;
+
+ if (!dev)
+ return -EINVAL;
+ ab8500 = dev_get_drvdata(dev->parent);
+ return ab8500 ? (int)ab8500->chip_id : -EINVAL;
}
static int set_register_interruptible(struct ab8500 *ab8500, u8 bank,
@@ -228,16 +233,16 @@ static struct abx500_ops ab8500_ops = {
.startup_irq_enabled = NULL,
};
-static void ab8500_irq_lock(unsigned int irq)
+static void ab8500_irq_lock(struct irq_data *data)
{
- struct ab8500 *ab8500 = get_irq_chip_data(irq);
+ struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data);
mutex_lock(&ab8500->irq_lock);
}
-static void ab8500_irq_sync_unlock(unsigned int irq)
+static void ab8500_irq_sync_unlock(struct irq_data *data)
{
- struct ab8500 *ab8500 = get_irq_chip_data(irq);
+ struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data);
int i;
for (i = 0; i < AB8500_NUM_IRQ_REGS; i++) {
@@ -248,6 +253,10 @@ static void ab8500_irq_sync_unlock(unsigned int irq)
if (new == old)
continue;
+ /* Interrupt register 12 does'nt exist prior to version 0x20 */
+ if (ab8500_irq_regoffset[i] == 11 && ab8500->chip_id < 0x20)
+ continue;
+
ab8500->oldmask[i] = new;
reg = AB8500_IT_MASK1_REG + ab8500_irq_regoffset[i];
@@ -257,20 +266,20 @@ static void ab8500_irq_sync_unlock(unsigned int irq)
mutex_unlock(&ab8500->irq_lock);
}
-static void ab8500_irq_mask(unsigned int irq)
+static void ab8500_irq_mask(struct irq_data *data)
{
- struct ab8500 *ab8500 = get_irq_chip_data(irq);
- int offset = irq - ab8500->irq_base;
+ struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data);
+ int offset = data->irq - ab8500->irq_base;
int index = offset / 8;
int mask = 1 << (offset % 8);
ab8500->mask[index] |= mask;
}
-static void ab8500_irq_unmask(unsigned int irq)
+static void ab8500_irq_unmask(struct irq_data *data)
{
- struct ab8500 *ab8500 = get_irq_chip_data(irq);
- int offset = irq - ab8500->irq_base;
+ struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data);
+ int offset = data->irq - ab8500->irq_base;
int index = offset / 8;
int mask = 1 << (offset % 8);
@@ -279,10 +288,10 @@ static void ab8500_irq_unmask(unsigned int irq)
static struct irq_chip ab8500_irq_chip = {
.name = "ab8500",
- .bus_lock = ab8500_irq_lock,
- .bus_sync_unlock = ab8500_irq_sync_unlock,
- .mask = ab8500_irq_mask,
- .unmask = ab8500_irq_unmask,
+ .irq_bus_lock = ab8500_irq_lock,
+ .irq_bus_sync_unlock = ab8500_irq_sync_unlock,
+ .irq_mask = ab8500_irq_mask,
+ .irq_unmask = ab8500_irq_unmask,
};
static irqreturn_t ab8500_irq(int irq, void *dev)
@@ -297,6 +306,10 @@ static irqreturn_t ab8500_irq(int irq, void *dev)
int status;
u8 value;
+ /* Interrupt register 12 does'nt exist prior to version 0x20 */
+ if (regoffset == 11 && ab8500->chip_id < 0x20)
+ continue;
+
status = get_register_interruptible(ab8500, AB8500_INTERRUPT,
AB8500_IT_LATCH1_REG + regoffset, &value);
if (status < 0 || value == 0)
@@ -393,13 +406,195 @@ static struct resource ab8500_poweronkey_db_resources[] = {
},
};
+static struct resource ab8500_bm_resources[] = {
+ {
+ .name = "MAIN_EXT_CH_NOT_OK",
+ .start = AB8500_INT_MAIN_EXT_CH_NOT_OK,
+ .end = AB8500_INT_MAIN_EXT_CH_NOT_OK,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "BATT_OVV",
+ .start = AB8500_INT_BATT_OVV,
+ .end = AB8500_INT_BATT_OVV,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "MAIN_CH_UNPLUG_DET",
+ .start = AB8500_INT_MAIN_CH_UNPLUG_DET,
+ .end = AB8500_INT_MAIN_CH_UNPLUG_DET,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "MAIN_CHARGE_PLUG_DET",
+ .start = AB8500_INT_MAIN_CH_PLUG_DET,
+ .end = AB8500_INT_MAIN_CH_PLUG_DET,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "VBUS_DET_F",
+ .start = AB8500_INT_VBUS_DET_F,
+ .end = AB8500_INT_VBUS_DET_F,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "VBUS_DET_R",
+ .start = AB8500_INT_VBUS_DET_R,
+ .end = AB8500_INT_VBUS_DET_R,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "BAT_CTRL_INDB",
+ .start = AB8500_INT_BAT_CTRL_INDB,
+ .end = AB8500_INT_BAT_CTRL_INDB,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "CH_WD_EXP",
+ .start = AB8500_INT_CH_WD_EXP,
+ .end = AB8500_INT_CH_WD_EXP,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "VBUS_OVV",
+ .start = AB8500_INT_VBUS_OVV,
+ .end = AB8500_INT_VBUS_OVV,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "NCONV_ACCU",
+ .start = AB8500_INT_CCN_CONV_ACC,
+ .end = AB8500_INT_CCN_CONV_ACC,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "LOW_BAT_F",
+ .start = AB8500_INT_LOW_BAT_F,
+ .end = AB8500_INT_LOW_BAT_F,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "LOW_BAT_R",
+ .start = AB8500_INT_LOW_BAT_R,
+ .end = AB8500_INT_LOW_BAT_R,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "BTEMP_LOW",
+ .start = AB8500_INT_BTEMP_LOW,
+ .end = AB8500_INT_BTEMP_LOW,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "BTEMP_HIGH",
+ .start = AB8500_INT_BTEMP_HIGH,
+ .end = AB8500_INT_BTEMP_HIGH,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "USB_CHARGER_NOT_OKR",
+ .start = AB8500_INT_USB_CHARGER_NOT_OK,
+ .end = AB8500_INT_USB_CHARGER_NOT_OK,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "USB_CHARGE_DET_DONE",
+ .start = AB8500_INT_USB_CHG_DET_DONE,
+ .end = AB8500_INT_USB_CHG_DET_DONE,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "USB_CH_TH_PROT_R",
+ .start = AB8500_INT_USB_CH_TH_PROT_R,
+ .end = AB8500_INT_USB_CH_TH_PROT_R,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "MAIN_CH_TH_PROT_R",
+ .start = AB8500_INT_MAIN_CH_TH_PROT_R,
+ .end = AB8500_INT_MAIN_CH_TH_PROT_R,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "USB_CHARGER_NOT_OKF",
+ .start = AB8500_INT_USB_CHARGER_NOT_OKF,
+ .end = AB8500_INT_USB_CHARGER_NOT_OKF,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct resource ab8500_debug_resources[] = {
+ {
+ .name = "IRQ_FIRST",
+ .start = AB8500_INT_MAIN_EXT_CH_NOT_OK,
+ .end = AB8500_INT_MAIN_EXT_CH_NOT_OK,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "IRQ_LAST",
+ .start = AB8500_INT_USB_CHARGER_NOT_OKF,
+ .end = AB8500_INT_USB_CHARGER_NOT_OKF,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct resource ab8500_usb_resources[] = {
+ {
+ .name = "ID_WAKEUP_R",
+ .start = AB8500_INT_ID_WAKEUP_R,
+ .end = AB8500_INT_ID_WAKEUP_R,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "ID_WAKEUP_F",
+ .start = AB8500_INT_ID_WAKEUP_F,
+ .end = AB8500_INT_ID_WAKEUP_F,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "VBUS_DET_F",
+ .start = AB8500_INT_VBUS_DET_F,
+ .end = AB8500_INT_VBUS_DET_F,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "VBUS_DET_R",
+ .start = AB8500_INT_VBUS_DET_R,
+ .end = AB8500_INT_VBUS_DET_R,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "USB_LINK_STATUS",
+ .start = AB8500_INT_USB_LINK_STATUS,
+ .end = AB8500_INT_USB_LINK_STATUS,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct resource ab8500_temp_resources[] = {
+ {
+ .name = "AB8500_TEMP_WARM",
+ .start = AB8500_INT_TEMP_WARM,
+ .end = AB8500_INT_TEMP_WARM,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
static struct mfd_cell ab8500_devs[] = {
#ifdef CONFIG_DEBUG_FS
{
.name = "ab8500-debug",
+ .num_resources = ARRAY_SIZE(ab8500_debug_resources),
+ .resources = ab8500_debug_resources,
},
#endif
{
+ .name = "ab8500-sysctrl",
+ },
+ {
+ .name = "ab8500-regulator",
+ },
+ {
.name = "ab8500-gpadc",
.num_resources = ARRAY_SIZE(ab8500_gpadc_resources),
.resources = ab8500_gpadc_resources,
@@ -410,6 +605,22 @@ static struct mfd_cell ab8500_devs[] = {
.resources = ab8500_rtc_resources,
},
{
+ .name = "ab8500-bm",
+ .num_resources = ARRAY_SIZE(ab8500_bm_resources),
+ .resources = ab8500_bm_resources,
+ },
+ { .name = "ab8500-codec", },
+ {
+ .name = "ab8500-usb",
+ .num_resources = ARRAY_SIZE(ab8500_usb_resources),
+ .resources = ab8500_usb_resources,
+ },
+ {
+ .name = "ab8500-poweron-key",
+ .num_resources = ARRAY_SIZE(ab8500_poweronkey_db_resources),
+ .resources = ab8500_poweronkey_db_resources,
+ },
+ {
.name = "ab8500-pwm",
.id = 1,
},
@@ -421,17 +632,37 @@ static struct mfd_cell ab8500_devs[] = {
.name = "ab8500-pwm",
.id = 3,
},
- { .name = "ab8500-charger", },
- { .name = "ab8500-audio", },
- { .name = "ab8500-usb", },
- { .name = "ab8500-regulator", },
+ { .name = "ab8500-leds", },
{
- .name = "ab8500-poweron-key",
- .num_resources = ARRAY_SIZE(ab8500_poweronkey_db_resources),
- .resources = ab8500_poweronkey_db_resources,
+ .name = "ab8500-denc",
+ },
+ {
+ .name = "ab8500-temp",
+ .num_resources = ARRAY_SIZE(ab8500_temp_resources),
+ .resources = ab8500_temp_resources,
},
};
+static ssize_t show_chip_id(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct ab8500 *ab8500;
+
+ ab8500 = dev_get_drvdata(dev);
+ return sprintf(buf, "%#x\n", ab8500 ? ab8500->chip_id : -EINVAL);
+}
+
+static DEVICE_ATTR(chip_id, S_IRUGO, show_chip_id, NULL);
+
+static struct attribute *ab8500_sysfs_entries[] = {
+ &dev_attr_chip_id.attr,
+ NULL,
+};
+
+static struct attribute_group ab8500_attr_group = {
+ .attrs = ab8500_sysfs_entries,
+};
+
int __devinit ab8500_init(struct ab8500 *ab8500)
{
struct ab8500_platform_data *plat = dev_get_platdata(ab8500->dev);
@@ -454,8 +685,9 @@ int __devinit ab8500_init(struct ab8500 *ab8500)
* 0x0 - Early Drop
* 0x10 - Cut 1.0
* 0x11 - Cut 1.1
+ * 0x20 - Cut 2.0
*/
- if (value == 0x0 || value == 0x10 || value == 0x11) {
+ if (value == 0x0 || value == 0x10 || value == 0x11 || value == 0x20) {
ab8500->revision = value;
dev_info(ab8500->dev, "detected chip, revision: %#x\n", value);
} else {
@@ -468,18 +700,16 @@ int __devinit ab8500_init(struct ab8500 *ab8500)
plat->init(ab8500);
/* Clear and mask all interrupts */
- for (i = 0; i < 10; i++) {
- get_register_interruptible(ab8500, AB8500_INTERRUPT,
- AB8500_IT_LATCH1_REG + i, &value);
- set_register_interruptible(ab8500, AB8500_INTERRUPT,
- AB8500_IT_MASK1_REG + i, 0xff);
- }
+ for (i = 0; i < AB8500_NUM_IRQ_REGS; i++) {
+ /* Interrupt register 12 does'nt exist prior to version 0x20 */
+ if (ab8500_irq_regoffset[i] == 11 && ab8500->chip_id < 0x20)
+ continue;
- for (i = 18; i < 24; i++) {
get_register_interruptible(ab8500, AB8500_INTERRUPT,
- AB8500_IT_LATCH1_REG + i, &value);
+ AB8500_IT_LATCH1_REG + ab8500_irq_regoffset[i],
+ &value);
set_register_interruptible(ab8500, AB8500_INTERRUPT,
- AB8500_IT_MASK1_REG + i, 0xff);
+ AB8500_IT_MASK1_REG + ab8500_irq_regoffset[i], 0xff);
}
ret = abx500_register_ops(ab8500->dev, &ab8500_ops);
@@ -495,7 +725,8 @@ int __devinit ab8500_init(struct ab8500 *ab8500)
return ret;
ret = request_threaded_irq(ab8500->irq, NULL, ab8500_irq,
- IRQF_ONESHOT, "ab8500", ab8500);
+ IRQF_ONESHOT | IRQF_NO_SUSPEND,
+ "ab8500", ab8500);
if (ret)
goto out_removeirq;
}
@@ -506,6 +737,10 @@ int __devinit ab8500_init(struct ab8500 *ab8500)
if (ret)
goto out_freeirq;
+ ret = sysfs_create_group(&ab8500->dev->kobj, &ab8500_attr_group);
+ if (ret)
+ dev_err(ab8500->dev, "error creating sysfs entries\n");
+
return ret;
out_freeirq:
@@ -519,6 +754,7 @@ out_removeirq:
int __devexit ab8500_exit(struct ab8500 *ab8500)
{
+ sysfs_remove_group(&ab8500->dev->kobj, &ab8500_attr_group);
mfd_remove_devices(ab8500->dev);
if (ab8500->irq_base) {
free_irq(ab8500->irq, ab8500);
diff --git a/drivers/mfd/ab8500-debugfs.c b/drivers/mfd/ab8500-debugfs.c
index 8d1e05a..3c1541a 100644
--- a/drivers/mfd/ab8500-debugfs.c
+++ b/drivers/mfd/ab8500-debugfs.c
@@ -24,9 +24,9 @@ static u32 debug_address;
* @perm: access permissions for the range
*/
struct ab8500_reg_range {
- u8 first;
- u8 last;
- u8 perm;
+ u8 first;
+ u8 last;
+ u8 perm;
};
/**
@@ -36,9 +36,9 @@ struct ab8500_reg_range {
* @range: the list of register ranges
*/
struct ab8500_i2c_ranges {
- u8 num_ranges;
- u8 bankid;
- const struct ab8500_reg_range *range;
+ u8 num_ranges;
+ u8 bankid;
+ const struct ab8500_reg_range *range;
};
#define AB8500_NAME_STRING "ab8500"
@@ -47,521 +47,521 @@ struct ab8500_i2c_ranges {
#define AB8500_REV_REG 0x80
static struct ab8500_i2c_ranges debug_ranges[AB8500_NUM_BANKS] = {
- [0x0] = {
- .num_ranges = 0,
- .range = 0,
- },
- [AB8500_SYS_CTRL1_BLOCK] = {
- .num_ranges = 3,
- .range = (struct ab8500_reg_range[]) {
- {
- .first = 0x00,
- .last = 0x02,
- },
- {
- .first = 0x42,
- .last = 0x42,
- },
- {
- .first = 0x80,
- .last = 0x81,
- },
- },
- },
- [AB8500_SYS_CTRL2_BLOCK] = {
- .num_ranges = 4,
- .range = (struct ab8500_reg_range[]) {
- {
- .first = 0x00,
- .last = 0x0D,
- },
- {
- .first = 0x0F,
- .last = 0x17,
- },
- {
- .first = 0x30,
- .last = 0x30,
- },
- {
- .first = 0x32,
- .last = 0x33,
- },
- },
- },
- [AB8500_REGU_CTRL1] = {
- .num_ranges = 3,
- .range = (struct ab8500_reg_range[]) {
- {
- .first = 0x00,
- .last = 0x00,
- },
- {
- .first = 0x03,
- .last = 0x10,
- },
- {
- .first = 0x80,
- .last = 0x84,
- },
- },
- },
- [AB8500_REGU_CTRL2] = {
- .num_ranges = 5,
- .range = (struct ab8500_reg_range[]) {
- {
- .first = 0x00,
- .last = 0x15,
- },
- {
- .first = 0x17,
- .last = 0x19,
- },
- {
- .first = 0x1B,
- .last = 0x1D,
- },
- {
- .first = 0x1F,
- .last = 0x22,
- },
- {
- .first = 0x40,
- .last = 0x44,
- },
- /* 0x80-0x8B is SIM registers and should
- * not be accessed from here */
- },
- },
- [AB8500_USB] = {
- .num_ranges = 2,
- .range = (struct ab8500_reg_range[]) {
- {
- .first = 0x80,
- .last = 0x83,
- },
- {
- .first = 0x87,
- .last = 0x8A,
- },
- },
- },
- [AB8500_TVOUT] = {
- .num_ranges = 9,
- .range = (struct ab8500_reg_range[]) {
- {
- .first = 0x00,
- .last = 0x12,
- },
- {
- .first = 0x15,
- .last = 0x17,
- },
- {
- .first = 0x19,
- .last = 0x21,
- },
- {
- .first = 0x27,
- .last = 0x2C,
- },
- {
- .first = 0x41,
- .last = 0x41,
- },
- {
- .first = 0x45,
- .last = 0x5B,
- },
- {
- .first = 0x5D,
- .last = 0x5D,
- },
- {
- .first = 0x69,
- .last = 0x69,
- },
- {
- .first = 0x80,
- .last = 0x81,
- },
- },
- },
- [AB8500_DBI] = {
- .num_ranges = 0,
- .range = 0,
- },
- [AB8500_ECI_AV_ACC] = {
- .num_ranges = 1,
- .range = (struct ab8500_reg_range[]) {
- {
- .first = 0x80,
- .last = 0x82,
- },
- },
- },
- [0x9] = {
- .num_ranges = 0,
- .range = 0,
- },
- [AB8500_GPADC] = {
- .num_ranges = 1,
- .range = (struct ab8500_reg_range[]) {
- {
- .first = 0x00,
- .last = 0x08,
- },
- },
- },
- [AB8500_CHARGER] = {
- .num_ranges = 8,
- .range = (struct ab8500_reg_range[]) {
- {
- .first = 0x00,
- .last = 0x03,
- },
- {
- .first = 0x05,
- .last = 0x05,
- },
- {
- .first = 0x40,
- .last = 0x40,
- },
- {
- .first = 0x42,
- .last = 0x42,
- },
- {
- .first = 0x44,
- .last = 0x44,
- },
- {
- .first = 0x50,
- .last = 0x55,
- },
- {
- .first = 0x80,
- .last = 0x82,
- },
- {
- .first = 0xC0,
- .last = 0xC2,
- },
- },
- },
- [AB8500_GAS_GAUGE] = {
- .num_ranges = 3,
- .range = (struct ab8500_reg_range[]) {
- {
- .first = 0x00,
- .last = 0x00,
- },
- {
- .first = 0x07,
- .last = 0x0A,
- },
- {
- .first = 0x10,
- .last = 0x14,
- },
- },
- },
- [AB8500_AUDIO] = {
- .num_ranges = 1,
- .range = (struct ab8500_reg_range[]) {
- {
- .first = 0x00,
- .last = 0x6F,
- },
- },
- },
- [AB8500_INTERRUPT] = {
- .num_ranges = 0,
- .range = 0,
- },
- [AB8500_RTC] = {
- .num_ranges = 1,
- .range = (struct ab8500_reg_range[]) {
- {
- .first = 0x00,
- .last = 0x0F,
- },
- },
- },
- [AB8500_MISC] = {
- .num_ranges = 8,
- .range = (struct ab8500_reg_range[]) {
- {
- .first = 0x00,
- .last = 0x05,
- },
- {
- .first = 0x10,
- .last = 0x15,
- },
- {
- .first = 0x20,
- .last = 0x25,
- },
- {
- .first = 0x30,
- .last = 0x35,
- },
- {
- .first = 0x40,
- .last = 0x45,
- },
- {
- .first = 0x50,
- .last = 0x50,
- },
- {
- .first = 0x60,
- .last = 0x67,
- },
- {
- .first = 0x80,
- .last = 0x80,
- },
- },
- },
- [0x11] = {
- .num_ranges = 0,
- .range = 0,
- },
- [0x12] = {
- .num_ranges = 0,
- .range = 0,
- },
- [0x13] = {
- .num_ranges = 0,
- .range = 0,
- },
- [0x14] = {
- .num_ranges = 0,
- .range = 0,
- },
- [AB8500_OTP_EMUL] = {
- .num_ranges = 1,
- .range = (struct ab8500_reg_range[]) {
- {
- .first = 0x01,
- .last = 0x0F,
- },
- },
- },
+ [0x0] = {
+ .num_ranges = 0,
+ .range = 0,
+ },
+ [AB8500_SYS_CTRL1_BLOCK] = {
+ .num_ranges = 3,
+ .range = (struct ab8500_reg_range[]) {
+ {
+ .first = 0x00,
+ .last = 0x02,
+ },
+ {
+ .first = 0x42,
+ .last = 0x42,
+ },
+ {
+ .first = 0x80,
+ .last = 0x81,
+ },
+ },
+ },
+ [AB8500_SYS_CTRL2_BLOCK] = {
+ .num_ranges = 4,
+ .range = (struct ab8500_reg_range[]) {
+ {
+ .first = 0x00,
+ .last = 0x0D,
+ },
+ {
+ .first = 0x0F,
+ .last = 0x17,
+ },
+ {
+ .first = 0x30,
+ .last = 0x30,
+ },
+ {
+ .first = 0x32,
+ .last = 0x33,
+ },
+ },
+ },
+ [AB8500_REGU_CTRL1] = {
+ .num_ranges = 3,
+ .range = (struct ab8500_reg_range[]) {
+ {
+ .first = 0x00,
+ .last = 0x00,
+ },
+ {
+ .first = 0x03,
+ .last = 0x10,
+ },
+ {
+ .first = 0x80,
+ .last = 0x84,
+ },
+ },
+ },
+ [AB8500_REGU_CTRL2] = {
+ .num_ranges = 5,
+ .range = (struct ab8500_reg_range[]) {
+ {
+ .first = 0x00,
+ .last = 0x15,
+ },
+ {
+ .first = 0x17,
+ .last = 0x19,
+ },
+ {
+ .first = 0x1B,
+ .last = 0x1D,
+ },
+ {
+ .first = 0x1F,
+ .last = 0x22,
+ },
+ {
+ .first = 0x40,
+ .last = 0x44,
+ },
+ /* 0x80-0x8B is SIM registers and should
+ * not be accessed from here */
+ },
+ },
+ [AB8500_USB] = {
+ .num_ranges = 2,
+ .range = (struct ab8500_reg_range[]) {
+ {
+ .first = 0x80,
+ .last = 0x83,
+ },
+ {
+ .first = 0x87,
+ .last = 0x8A,
+ },
+ },
+ },
+ [AB8500_TVOUT] = {
+ .num_ranges = 9,
+ .range = (struct ab8500_reg_range[]) {
+ {
+ .first = 0x00,
+ .last = 0x12,
+ },
+ {
+ .first = 0x15,
+ .last = 0x17,
+ },
+ {
+ .first = 0x19,
+ .last = 0x21,
+ },
+ {
+ .first = 0x27,
+ .last = 0x2C,
+ },
+ {
+ .first = 0x41,
+ .last = 0x41,
+ },
+ {
+ .first = 0x45,
+ .last = 0x5B,
+ },
+ {
+ .first = 0x5D,
+ .last = 0x5D,
+ },
+ {
+ .first = 0x69,
+ .last = 0x69,
+ },
+ {
+ .first = 0x80,
+ .last = 0x81,
+ },
+ },
+ },
+ [AB8500_DBI] = {
+ .num_ranges = 0,
+ .range = NULL,
+ },
+ [AB8500_ECI_AV_ACC] = {
+ .num_ranges = 1,
+ .range = (struct ab8500_reg_range[]) {
+ {
+ .first = 0x80,
+ .last = 0x82,
+ },
+ },
+ },
+ [0x9] = {
+ .num_ranges = 0,
+ .range = NULL,
+ },
+ [AB8500_GPADC] = {
+ .num_ranges = 1,
+ .range = (struct ab8500_reg_range[]) {
+ {
+ .first = 0x00,
+ .last = 0x08,
+ },
+ },
+ },
+ [AB8500_CHARGER] = {
+ .num_ranges = 8,
+ .range = (struct ab8500_reg_range[]) {
+ {
+ .first = 0x00,
+ .last = 0x03,
+ },
+ {
+ .first = 0x05,
+ .last = 0x05,
+ },
+ {
+ .first = 0x40,
+ .last = 0x40,
+ },
+ {
+ .first = 0x42,
+ .last = 0x42,
+ },
+ {
+ .first = 0x44,
+ .last = 0x44,
+ },
+ {
+ .first = 0x50,
+ .last = 0x55,
+ },
+ {
+ .first = 0x80,
+ .last = 0x82,
+ },
+ {
+ .first = 0xC0,
+ .last = 0xC2,
+ },
+ },
+ },
+ [AB8500_GAS_GAUGE] = {
+ .num_ranges = 3,
+ .range = (struct ab8500_reg_range[]) {
+ {
+ .first = 0x00,
+ .last = 0x00,
+ },
+ {
+ .first = 0x07,
+ .last = 0x0A,
+ },
+ {
+ .first = 0x10,
+ .last = 0x14,
+ },
+ },
+ },
+ [AB8500_AUDIO] = {
+ .num_ranges = 1,
+ .range = (struct ab8500_reg_range[]) {
+ {
+ .first = 0x00,
+ .last = 0x6F,
+ },
+ },
+ },
+ [AB8500_INTERRUPT] = {
+ .num_ranges = 0,
+ .range = NULL,
+ },
+ [AB8500_RTC] = {
+ .num_ranges = 1,
+ .range = (struct ab8500_reg_range[]) {
+ {
+ .first = 0x00,
+ .last = 0x0F,
+ },
+ },
+ },
+ [AB8500_MISC] = {
+ .num_ranges = 8,
+ .range = (struct ab8500_reg_range[]) {
+ {
+ .first = 0x00,
+ .last = 0x05,
+ },
+ {
+ .first = 0x10,
+ .last = 0x15,
+ },
+ {
+ .first = 0x20,
+ .last = 0x25,
+ },
+ {
+ .first = 0x30,
+ .last = 0x35,
+ },
+ {
+ .first = 0x40,
+ .last = 0x45,
+ },
+ {
+ .first = 0x50,
+ .last = 0x50,
+ },
+ {
+ .first = 0x60,
+ .last = 0x67,
+ },
+ {
+ .first = 0x80,
+ .last = 0x80,
+ },
+ },
+ },
+ [0x11] = {
+ .num_ranges = 0,
+ .range = NULL,
+ },
+ [0x12] = {
+ .num_ranges = 0,
+ .range = NULL,
+ },
+ [0x13] = {
+ .num_ranges = 0,
+ .range = NULL,
+ },
+ [0x14] = {
+ .num_ranges = 0,
+ .range = NULL,
+ },
+ [AB8500_OTP_EMUL] = {
+ .num_ranges = 1,
+ .range = (struct ab8500_reg_range[]) {
+ {
+ .first = 0x01,
+ .last = 0x0F,
+ },
+ },
+ },
};
static int ab8500_registers_print(struct seq_file *s, void *p)
{
- struct device *dev = s->private;
- unsigned int i;
- u32 bank = debug_bank;
-
- seq_printf(s, AB8500_NAME_STRING " register values:\n");
-
- seq_printf(s, " bank %u:\n", bank);
- for (i = 0; i < debug_ranges[bank].num_ranges; i++) {
- u32 reg;
-
- for (reg = debug_ranges[bank].range[i].first;
- reg <= debug_ranges[bank].range[i].last;
- reg++) {
- u8 value;
- int err;
-
- err = abx500_get_register_interruptible(dev,
- (u8)bank, (u8)reg, &value);
- if (err < 0) {
- dev_err(dev, "ab->read fail %d\n", err);
- return err;
- }
-
- err = seq_printf(s, " [%u/0x%02X]: 0x%02X\n", bank,
- reg, value);
- if (err < 0) {
- dev_err(dev, "seq_printf overflow\n");
- /* Error is not returned here since
- * the output is wanted in any case */
- return 0;
- }
- }
- }
- return 0;
+ struct device *dev = s->private;
+ unsigned int i;
+ u32 bank = debug_bank;
+
+ seq_printf(s, AB8500_NAME_STRING " register values:\n");
+
+ seq_printf(s, " bank %u:\n", bank);
+ for (i = 0; i < debug_ranges[bank].num_ranges; i++) {
+ u32 reg;
+
+ for (reg = debug_ranges[bank].range[i].first;
+ reg <= debug_ranges[bank].range[i].last;
+ reg++) {
+ u8 value;
+ int err;
+
+ err = abx500_get_register_interruptible(dev,
+ (u8)bank, (u8)reg, &value);
+ if (err < 0) {
+ dev_err(dev, "ab->read fail %d\n", err);
+ return err;
+ }
+
+ err = seq_printf(s, " [%u/0x%02X]: 0x%02X\n", bank,
+ reg, value);
+ if (err < 0) {
+ dev_err(dev, "seq_printf overflow\n");
+ /* Error is not returned here since
+ * the output is wanted in any case */
+ return 0;
+ }
+ }
+ }
+ return 0;
}
static int ab8500_registers_open(struct inode *inode, struct file *file)
{
- return single_open(file, ab8500_registers_print, inode->i_private);
+ return single_open(file, ab8500_registers_print, inode->i_private);
}
static const struct file_operations ab8500_registers_fops = {
- .open = ab8500_registers_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
- .owner = THIS_MODULE,
+ .open = ab8500_registers_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
};
static int ab8500_bank_print(struct seq_file *s, void *p)
{
- return seq_printf(s, "%d\n", debug_bank);
+ return seq_printf(s, "%d\n", debug_bank);
}
static int ab8500_bank_open(struct inode *inode, struct file *file)
{
- return single_open(file, ab8500_bank_print, inode->i_private);
+ return single_open(file, ab8500_bank_print, inode->i_private);
}
static ssize_t ab8500_bank_write(struct file *file,
- const char __user *user_buf,
- size_t count, loff_t *ppos)
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
{
- struct device *dev = ((struct seq_file *)(file->private_data))->private;
- char buf[32];
- int buf_size;
- unsigned long user_bank;
- int err;
-
- /* Get userspace string and assure termination */
- buf_size = min(count, (sizeof(buf) - 1));
- if (copy_from_user(buf, user_buf, buf_size))
- return -EFAULT;
- buf[buf_size] = 0;
-
- err = strict_strtoul(buf, 0, &user_bank);
- if (err)
- return -EINVAL;
-
- if (user_bank >= AB8500_NUM_BANKS) {
- dev_err(dev, "debugfs error input > number of banks\n");
- return -EINVAL;
- }
-
- debug_bank = user_bank;
-
- return buf_size;
+ struct device *dev = ((struct seq_file *)(file->private_data))->private;
+ char buf[32];
+ int buf_size;
+ unsigned long user_bank;
+ int err;
+
+ /* Get userspace string and assure termination */
+ buf_size = min(count, (sizeof(buf) - 1));
+ if (copy_from_user(buf, user_buf, buf_size))
+ return -EFAULT;
+ buf[buf_size] = 0;
+
+ err = strict_strtoul(buf, 0, &user_bank);
+ if (err)
+ return -EINVAL;
+
+ if (user_bank >= AB8500_NUM_BANKS) {
+ dev_err(dev, "debugfs error input > number of banks\n");
+ return -EINVAL;
+ }
+
+ debug_bank = user_bank;
+
+ return buf_size;
}
static int ab8500_address_print(struct seq_file *s, void *p)
{
- return seq_printf(s, "0x%02X\n", debug_address);
+ return seq_printf(s, "0x%02X\n", debug_address);
}
static int ab8500_address_open(struct inode *inode, struct file *file)
{
- return single_open(file, ab8500_address_print, inode->i_private);
+ return single_open(file, ab8500_address_print, inode->i_private);
}
static ssize_t ab8500_address_write(struct file *file,
- const char __user *user_buf,
- size_t count, loff_t *ppos)
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
{
- struct device *dev = ((struct seq_file *)(file->private_data))->private;
- char buf[32];
- int buf_size;
- unsigned long user_address;
- int err;
-
- /* Get userspace string and assure termination */
- buf_size = min(count, (sizeof(buf) - 1));
- if (copy_from_user(buf, user_buf, buf_size))
- return -EFAULT;
- buf[buf_size] = 0;
-
- err = strict_strtoul(buf, 0, &user_address);
- if (err)
- return -EINVAL;
- if (user_address > 0xff) {
- dev_err(dev, "debugfs error input > 0xff\n");
- return -EINVAL;
- }
- debug_address = user_address;
- return buf_size;
+ struct device *dev = ((struct seq_file *)(file->private_data))->private;
+ char buf[32];
+ int buf_size;
+ unsigned long user_address;
+ int err;
+
+ /* Get userspace string and assure termination */
+ buf_size = min(count, (sizeof(buf) - 1));
+ if (copy_from_user(buf, user_buf, buf_size))
+ return -EFAULT;
+ buf[buf_size] = 0;
+
+ err = strict_strtoul(buf, 0, &user_address);
+ if (err)
+ return -EINVAL;
+ if (user_address > 0xff) {
+ dev_err(dev, "debugfs error input > 0xff\n");
+ return -EINVAL;
+ }
+ debug_address = user_address;
+ return buf_size;
}
static int ab8500_val_print(struct seq_file *s, void *p)
{
- struct device *dev = s->private;
- int ret;
- u8 regvalue;
-
- ret = abx500_get_register_interruptible(dev,
- (u8)debug_bank, (u8)debug_address, &regvalue);
- if (ret < 0) {
- dev_err(dev, "abx500_get_reg fail %d, %d\n",
- ret, __LINE__);
- return -EINVAL;
- }
- seq_printf(s, "0x%02X\n", regvalue);
-
- return 0;
+ struct device *dev = s->private;
+ int ret;
+ u8 regvalue;
+
+ ret = abx500_get_register_interruptible(dev,
+ (u8)debug_bank, (u8)debug_address, &regvalue);
+ if (ret < 0) {
+ dev_err(dev, "abx500_get_reg fail %d, %d\n",
+ ret, __LINE__);
+ return -EINVAL;
+ }
+ seq_printf(s, "0x%02X\n", regvalue);
+
+ return 0;
}
static int ab8500_val_open(struct inode *inode, struct file *file)
{
- return single_open(file, ab8500_val_print, inode->i_private);
+ return single_open(file, ab8500_val_print, inode->i_private);
}
static ssize_t ab8500_val_write(struct file *file,
- const char __user *user_buf,
- size_t count, loff_t *ppos)
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
{
- struct device *dev = ((struct seq_file *)(file->private_data))->private;
- char buf[32];
- int buf_size;
- unsigned long user_val;
- int err;
-
- /* Get userspace string and assure termination */
- buf_size = min(count, (sizeof(buf)-1));
- if (copy_from_user(buf, user_buf, buf_size))
- return -EFAULT;
- buf[buf_size] = 0;
-
- err = strict_strtoul(buf, 0, &user_val);
- if (err)
- return -EINVAL;
- if (user_val > 0xff) {
- dev_err(dev, "debugfs error input > 0xff\n");
- return -EINVAL;
- }
- err = abx500_set_register_interruptible(dev,
- (u8)debug_bank, debug_address, (u8)user_val);
- if (err < 0) {
- printk(KERN_ERR "abx500_set_reg failed %d, %d", err, __LINE__);
- return -EINVAL;
- }
-
- return buf_size;
+ struct device *dev = ((struct seq_file *)(file->private_data))->private;
+ char buf[32];
+ int buf_size;
+ unsigned long user_val;
+ int err;
+
+ /* Get userspace string and assure termination */
+ buf_size = min(count, (sizeof(buf)-1));
+ if (copy_from_user(buf, user_buf, buf_size))
+ return -EFAULT;
+ buf[buf_size] = 0;
+
+ err = strict_strtoul(buf, 0, &user_val);
+ if (err)
+ return -EINVAL;
+ if (user_val > 0xff) {
+ dev_err(dev, "debugfs error input > 0xff\n");
+ return -EINVAL;
+ }
+ err = abx500_set_register_interruptible(dev,
+ (u8)debug_bank, debug_address, (u8)user_val);
+ if (err < 0) {
+ printk(KERN_ERR "abx500_set_reg failed %d, %d", err, __LINE__);
+ return -EINVAL;
+ }
+
+ return buf_size;
}
static const struct file_operations ab8500_bank_fops = {
- .open = ab8500_bank_open,
- .write = ab8500_bank_write,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
- .owner = THIS_MODULE,
+ .open = ab8500_bank_open,
+ .write = ab8500_bank_write,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
};
static const struct file_operations ab8500_address_fops = {
- .open = ab8500_address_open,
- .write = ab8500_address_write,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
- .owner = THIS_MODULE,
+ .open = ab8500_address_open,
+ .write = ab8500_address_write,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
};
static const struct file_operations ab8500_val_fops = {
- .open = ab8500_val_open,
- .write = ab8500_val_write,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
- .owner = THIS_MODULE,
+ .open = ab8500_val_open,
+ .write = ab8500_val_write,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
};
static struct dentry *ab8500_dir;
@@ -572,77 +572,77 @@ static struct dentry *ab8500_val_file;
static int __devinit ab8500_debug_probe(struct platform_device *plf)
{
- debug_bank = AB8500_MISC;
- debug_address = AB8500_REV_REG & 0x00FF;
+ debug_bank = AB8500_MISC;
+ debug_address = AB8500_REV_REG & 0x00FF;
- ab8500_dir = debugfs_create_dir(AB8500_NAME_STRING, NULL);
- if (!ab8500_dir)
- goto exit_no_debugfs;
+ ab8500_dir = debugfs_create_dir(AB8500_NAME_STRING, NULL);
+ if (!ab8500_dir)
+ goto exit_no_debugfs;
- ab8500_reg_file = debugfs_create_file("all-bank-registers",
- S_IRUGO, ab8500_dir, &plf->dev, &ab8500_registers_fops);
- if (!ab8500_reg_file)
- goto exit_destroy_dir;
+ ab8500_reg_file = debugfs_create_file("all-bank-registers",
+ S_IRUGO, ab8500_dir, &plf->dev, &ab8500_registers_fops);
+ if (!ab8500_reg_file)
+ goto exit_destroy_dir;
- ab8500_bank_file = debugfs_create_file("register-bank",
- (S_IRUGO | S_IWUGO), ab8500_dir, &plf->dev, &ab8500_bank_fops);
- if (!ab8500_bank_file)
- goto exit_destroy_reg;
+ ab8500_bank_file = debugfs_create_file("register-bank",
+ (S_IRUGO | S_IWUGO), ab8500_dir, &plf->dev, &ab8500_bank_fops);
+ if (!ab8500_bank_file)
+ goto exit_destroy_reg;
- ab8500_address_file = debugfs_create_file("register-address",
- (S_IRUGO | S_IWUGO), ab8500_dir, &plf->dev,
- &ab8500_address_fops);
- if (!ab8500_address_file)
- goto exit_destroy_bank;
+ ab8500_address_file = debugfs_create_file("register-address",
+ (S_IRUGO | S_IWUGO), ab8500_dir, &plf->dev,
+ &ab8500_address_fops);
+ if (!ab8500_address_file)
+ goto exit_destroy_bank;
- ab8500_val_file = debugfs_create_file("register-value",
- (S_IRUGO | S_IWUGO), ab8500_dir, &plf->dev, &ab8500_val_fops);
- if (!ab8500_val_file)
- goto exit_destroy_address;
+ ab8500_val_file = debugfs_create_file("register-value",
+ (S_IRUGO | S_IWUGO), ab8500_dir, &plf->dev, &ab8500_val_fops);
+ if (!ab8500_val_file)
+ goto exit_destroy_address;
- return 0;
+ return 0;
exit_destroy_address:
- debugfs_remove(ab8500_address_file);
+ debugfs_remove(ab8500_address_file);
exit_destroy_bank:
- debugfs_remove(ab8500_bank_file);
+ debugfs_remove(ab8500_bank_file);
exit_destroy_reg:
- debugfs_remove(ab8500_reg_file);
+ debugfs_remove(ab8500_reg_file);
exit_destroy_dir:
- debugfs_remove(ab8500_dir);
+ debugfs_remove(ab8500_dir);
exit_no_debugfs:
- dev_err(&plf->dev, "failed to create debugfs entries.\n");
- return -ENOMEM;
+ dev_err(&plf->dev, "failed to create debugfs entries.\n");
+ return -ENOMEM;
}
static int __devexit ab8500_debug_remove(struct platform_device *plf)
{
- debugfs_remove(ab8500_val_file);
- debugfs_remove(ab8500_address_file);
- debugfs_remove(ab8500_bank_file);
- debugfs_remove(ab8500_reg_file);
- debugfs_remove(ab8500_dir);
+ debugfs_remove(ab8500_val_file);
+ debugfs_remove(ab8500_address_file);
+ debugfs_remove(ab8500_bank_file);
+ debugfs_remove(ab8500_reg_file);
+ debugfs_remove(ab8500_dir);
- return 0;
+ return 0;
}
static struct platform_driver ab8500_debug_driver = {
- .driver = {
- .name = "ab8500-debug",
- .owner = THIS_MODULE,
- },
- .probe = ab8500_debug_probe,
- .remove = __devexit_p(ab8500_debug_remove)
+ .driver = {
+ .name = "ab8500-debug",
+ .owner = THIS_MODULE,
+ },
+ .probe = ab8500_debug_probe,
+ .remove = __devexit_p(ab8500_debug_remove)
};
static int __init ab8500_debug_init(void)
{
- return platform_driver_register(&ab8500_debug_driver);
+ return platform_driver_register(&ab8500_debug_driver);
}
static void __exit ab8500_debug_exit(void)
{
- platform_driver_unregister(&ab8500_debug_driver);
+ platform_driver_unregister(&ab8500_debug_driver);
}
subsys_initcall(ab8500_debug_init);
module_exit(ab8500_debug_exit);
diff --git a/drivers/mfd/ab8500-spi.c b/drivers/mfd/ab8500-spi.c
deleted file mode 100644
index b165342..0000000
--- a/drivers/mfd/ab8500-spi.c
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * Copyright (C) ST-Ericsson SA 2010
- *
- * License Terms: GNU General Public License v2
- * Author: Srinidhi Kasagar <srinidhi.kasagar@stericsson.com>
- */
-
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/spi/spi.h>
-#include <linux/mfd/ab8500.h>
-
-/*
- * This funtion writes to any AB8500 registers using
- * SPI protocol & before it writes it packs the data
- * in the below 24 bit frame format
- *
- * *|------------------------------------|
- * *| 23|22...18|17.......10|9|8|7......0|
- * *| r/w bank adr data |
- * * ------------------------------------
- *
- * This function shouldn't be called from interrupt
- * context
- */
-static int ab8500_spi_write(struct ab8500 *ab8500, u16 addr, u8 data)
-{
- struct spi_device *spi = container_of(ab8500->dev, struct spi_device,
- dev);
- unsigned long spi_data = addr << 10 | data;
- struct spi_transfer xfer;
- struct spi_message msg;
-
- ab8500->tx_buf[0] = spi_data;
- ab8500->rx_buf[0] = 0;
-
- xfer.tx_buf = ab8500->tx_buf;
- xfer.rx_buf = NULL;
- xfer.len = sizeof(unsigned long);
-
- spi_message_init(&msg);
- spi_message_add_tail(&xfer, &msg);
-
- return spi_sync(spi, &msg);
-}
-
-static int ab8500_spi_read(struct ab8500 *ab8500, u16 addr)
-{
- struct spi_device *spi = container_of(ab8500->dev, struct spi_device,
- dev);
- unsigned long spi_data = 1 << 23 | addr << 10;
- struct spi_transfer xfer;
- struct spi_message msg;
- int ret;
-
- ab8500->tx_buf[0] = spi_data;
- ab8500->rx_buf[0] = 0;
-
- xfer.tx_buf = ab8500->tx_buf;
- xfer.rx_buf = ab8500->rx_buf;
- xfer.len = sizeof(unsigned long);
-
- spi_message_init(&msg);
- spi_message_add_tail(&xfer, &msg);
-
- ret = spi_sync(spi, &msg);
- if (!ret)
- /*
- * Only the 8 lowermost bytes are
- * defined with value, the rest may
- * vary depending on chip/board noise.
- */
- ret = ab8500->rx_buf[0] & 0xFFU;
-
- return ret;
-}
-
-static int __devinit ab8500_spi_probe(struct spi_device *spi)
-{
- struct ab8500 *ab8500;
- int ret;
-
- spi->bits_per_word = 24;
- ret = spi_setup(spi);
- if (ret < 0)
- return ret;
-
- ab8500 = kzalloc(sizeof *ab8500, GFP_KERNEL);
- if (!ab8500)
- return -ENOMEM;
-
- ab8500->dev = &spi->dev;
- ab8500->irq = spi->irq;
-
- ab8500->read = ab8500_spi_read;
- ab8500->write = ab8500_spi_write;
-
- spi_set_drvdata(spi, ab8500);
-
- ret = ab8500_init(ab8500);
- if (ret)
- kfree(ab8500);
-
- return ret;
-}
-
-static int __devexit ab8500_spi_remove(struct spi_device *spi)
-{
- struct ab8500 *ab8500 = spi_get_drvdata(spi);
-
- ab8500_exit(ab8500);
- kfree(ab8500);
-
- return 0;
-}
-
-static struct spi_driver ab8500_spi_driver = {
- .driver = {
- .name = "ab8500-spi",
- .owner = THIS_MODULE,
- },
- .probe = ab8500_spi_probe,
- .remove = __devexit_p(ab8500_spi_remove)
-};
-
-static int __init ab8500_spi_init(void)
-{
- return spi_register_driver(&ab8500_spi_driver);
-}
-subsys_initcall(ab8500_spi_init);
-
-static void __exit ab8500_spi_exit(void)
-{
- spi_unregister_driver(&ab8500_spi_driver);
-}
-module_exit(ab8500_spi_exit);
-
-MODULE_AUTHOR("Srinidhi KASAGAR <srinidhi.kasagar@stericsson.com");
-MODULE_DESCRIPTION("AB8500 SPI");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/mfd/asic3.c b/drivers/mfd/asic3.c
index 7de708d..6a1f940 100644
--- a/drivers/mfd/asic3.c
+++ b/drivers/mfd/asic3.c
@@ -57,7 +57,7 @@ struct asic3_clk {
.rate = _rate, \
}
-struct asic3_clk asic3_clk_init[] __initdata = {
+static struct asic3_clk asic3_clk_init[] __initdata = {
INIT_CDEX(SPI, 0),
INIT_CDEX(OWM, 5000000),
INIT_CDEX(PWM0, 0),
@@ -102,7 +102,7 @@ static inline u32 asic3_read_register(struct asic3 *asic,
(reg >> asic->bus_shift));
}
-void asic3_set_register(struct asic3 *asic, u32 reg, u32 bits, bool set)
+static void asic3_set_register(struct asic3 *asic, u32 reg, u32 bits, bool set)
{
unsigned long flags;
u32 val;
@@ -226,14 +226,14 @@ static inline int asic3_irq_to_index(struct asic3 *asic, int irq)
return (irq - asic->irq_base) & 0xf;
}
-static void asic3_mask_gpio_irq(unsigned int irq)
+static void asic3_mask_gpio_irq(struct irq_data *data)
{
- struct asic3 *asic = get_irq_chip_data(irq);
+ struct asic3 *asic = irq_data_get_irq_chip_data(data);
u32 val, bank, index;
unsigned long flags;
- bank = asic3_irq_to_bank(asic, irq);
- index = asic3_irq_to_index(asic, irq);
+ bank = asic3_irq_to_bank(asic, data->irq);
+ index = asic3_irq_to_index(asic, data->irq);
spin_lock_irqsave(&asic->lock, flags);
val = asic3_read_register(asic, bank + ASIC3_GPIO_MASK);
@@ -242,9 +242,9 @@ static void asic3_mask_gpio_irq(unsigned int irq)
spin_unlock_irqrestore(&asic->lock, flags);
}
-static void asic3_mask_irq(unsigned int irq)
+static void asic3_mask_irq(struct irq_data *data)
{
- struct asic3 *asic = get_irq_chip_data(irq);
+ struct asic3 *asic = irq_data_get_irq_chip_data(data);
int regval;
unsigned long flags;
@@ -254,7 +254,7 @@ static void asic3_mask_irq(unsigned int irq)
ASIC3_INTR_INT_MASK);
regval &= ~(ASIC3_INTMASK_MASK0 <<
- (irq - (asic->irq_base + ASIC3_NUM_GPIOS)));
+ (data->irq - (asic->irq_base + ASIC3_NUM_GPIOS)));
asic3_write_register(asic,
ASIC3_INTR_BASE +
@@ -263,14 +263,14 @@ static void asic3_mask_irq(unsigned int irq)
spin_unlock_irqrestore(&asic->lock, flags);
}
-static void asic3_unmask_gpio_irq(unsigned int irq)
+static void asic3_unmask_gpio_irq(struct irq_data *data)
{
- struct asic3 *asic = get_irq_chip_data(irq);
+ struct asic3 *asic = irq_data_get_irq_chip_data(data);
u32 val, bank, index;
unsigned long flags;
- bank = asic3_irq_to_bank(asic, irq);
- index = asic3_irq_to_index(asic, irq);
+ bank = asic3_irq_to_bank(asic, data->irq);
+ index = asic3_irq_to_index(asic, data->irq);
spin_lock_irqsave(&asic->lock, flags);
val = asic3_read_register(asic, bank + ASIC3_GPIO_MASK);
@@ -279,9 +279,9 @@ static void asic3_unmask_gpio_irq(unsigned int irq)
spin_unlock_irqrestore(&asic->lock, flags);
}
-static void asic3_unmask_irq(unsigned int irq)
+static void asic3_unmask_irq(struct irq_data *data)
{
- struct asic3 *asic = get_irq_chip_data(irq);
+ struct asic3 *asic = irq_data_get_irq_chip_data(data);
int regval;
unsigned long flags;
@@ -291,7 +291,7 @@ static void asic3_unmask_irq(unsigned int irq)
ASIC3_INTR_INT_MASK);
regval |= (ASIC3_INTMASK_MASK0 <<
- (irq - (asic->irq_base + ASIC3_NUM_GPIOS)));
+ (data->irq - (asic->irq_base + ASIC3_NUM_GPIOS)));
asic3_write_register(asic,
ASIC3_INTR_BASE +
@@ -300,15 +300,15 @@ static void asic3_unmask_irq(unsigned int irq)
spin_unlock_irqrestore(&asic->lock, flags);
}
-static int asic3_gpio_irq_type(unsigned int irq, unsigned int type)
+static int asic3_gpio_irq_type(struct irq_data *data, unsigned int type)
{
- struct asic3 *asic = get_irq_chip_data(irq);
+ struct asic3 *asic = irq_data_get_irq_chip_data(data);
u32 bank, index;
u16 trigger, level, edge, bit;
unsigned long flags;
- bank = asic3_irq_to_bank(asic, irq);
- index = asic3_irq_to_index(asic, irq);
+ bank = asic3_irq_to_bank(asic, data->irq);
+ index = asic3_irq_to_index(asic, data->irq);
bit = 1<<index;
spin_lock_irqsave(&asic->lock, flags);
@@ -318,7 +318,7 @@ static int asic3_gpio_irq_type(unsigned int irq, unsigned int type)
bank + ASIC3_GPIO_EDGE_TRIGGER);
trigger = asic3_read_register(asic,
bank + ASIC3_GPIO_TRIGGER_TYPE);
- asic->irq_bothedge[(irq - asic->irq_base) >> 4] &= ~bit;
+ asic->irq_bothedge[(data->irq - asic->irq_base) >> 4] &= ~bit;
if (type == IRQ_TYPE_EDGE_RISING) {
trigger |= bit;
@@ -328,11 +328,11 @@ static int asic3_gpio_irq_type(unsigned int irq, unsigned int type)
edge &= ~bit;
} else if (type == IRQ_TYPE_EDGE_BOTH) {
trigger |= bit;
- if (asic3_gpio_get(&asic->gpio, irq - asic->irq_base))
+ if (asic3_gpio_get(&asic->gpio, data->irq - asic->irq_base))
edge &= ~bit;
else
edge |= bit;
- asic->irq_bothedge[(irq - asic->irq_base) >> 4] |= bit;
+ asic->irq_bothedge[(data->irq - asic->irq_base) >> 4] |= bit;
} else if (type == IRQ_TYPE_LEVEL_LOW) {
trigger &= ~bit;
level &= ~bit;
@@ -359,17 +359,17 @@ static int asic3_gpio_irq_type(unsigned int irq, unsigned int type)
static struct irq_chip asic3_gpio_irq_chip = {
.name = "ASIC3-GPIO",
- .ack = asic3_mask_gpio_irq,
- .mask = asic3_mask_gpio_irq,
- .unmask = asic3_unmask_gpio_irq,
- .set_type = asic3_gpio_irq_type,
+ .irq_ack = asic3_mask_gpio_irq,
+ .irq_mask = asic3_mask_gpio_irq,
+ .irq_unmask = asic3_unmask_gpio_irq,
+ .irq_set_type = asic3_gpio_irq_type,
};
static struct irq_chip asic3_irq_chip = {
.name = "ASIC3",
- .ack = asic3_mask_irq,
- .mask = asic3_mask_irq,
- .unmask = asic3_unmask_irq,
+ .irq_ack = asic3_mask_irq,
+ .irq_mask = asic3_mask_irq,
+ .irq_unmask = asic3_unmask_irq,
};
static int __init asic3_irq_probe(struct platform_device *pdev)
@@ -635,7 +635,7 @@ static struct resource ds1wm_resources[] = {
},
{
.start = ASIC3_IRQ_OWM,
- .start = ASIC3_IRQ_OWM,
+ .end = ASIC3_IRQ_OWM,
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE,
},
};
diff --git a/drivers/mfd/cs5535-mfd.c b/drivers/mfd/cs5535-mfd.c
new file mode 100644
index 0000000..59ca6f1
--- /dev/null
+++ b/drivers/mfd/cs5535-mfd.c
@@ -0,0 +1,151 @@
+/*
+ * cs5535-mfd.c - core MFD driver for CS5535/CS5536 southbridges
+ *
+ * The CS5535 and CS5536 has an ISA bridge on the PCI bus that is
+ * used for accessing GPIOs, MFGPTs, ACPI, etc. Each subdevice has
+ * an IO range that's specified in a single BAR. The BAR order is
+ * hardcoded in the CS553x specifications.
+ *
+ * Copyright (c) 2010 Andres Salomon <dilinger@queued.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/mfd/core.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+
+#define DRV_NAME "cs5535-mfd"
+
+enum cs5535_mfd_bars {
+ SMB_BAR = 0,
+ GPIO_BAR = 1,
+ MFGPT_BAR = 2,
+ PMS_BAR = 4,
+ ACPI_BAR = 5,
+ NR_BARS,
+};
+
+static __devinitdata struct resource cs5535_mfd_resources[NR_BARS];
+
+static __devinitdata struct mfd_cell cs5535_mfd_cells[] = {
+ {
+ .id = SMB_BAR,
+ .name = "cs5535-smb",
+ .num_resources = 1,
+ .resources = &cs5535_mfd_resources[SMB_BAR],
+ },
+ {
+ .id = GPIO_BAR,
+ .name = "cs5535-gpio",
+ .num_resources = 1,
+ .resources = &cs5535_mfd_resources[GPIO_BAR],
+ },
+ {
+ .id = MFGPT_BAR,
+ .name = "cs5535-mfgpt",
+ .num_resources = 1,
+ .resources = &cs5535_mfd_resources[MFGPT_BAR],
+ },
+ {
+ .id = PMS_BAR,
+ .name = "cs5535-pms",
+ .num_resources = 1,
+ .resources = &cs5535_mfd_resources[PMS_BAR],
+ },
+ {
+ .id = ACPI_BAR,
+ .name = "cs5535-acpi",
+ .num_resources = 1,
+ .resources = &cs5535_mfd_resources[ACPI_BAR],
+ },
+};
+
+static int __devinit cs5535_mfd_probe(struct pci_dev *pdev,
+ const struct pci_device_id *id)
+{
+ int err, i;
+
+ err = pci_enable_device(pdev);
+ if (err)
+ return err;
+
+ /* fill in IO range for each cell; subdrivers handle the region */
+ for (i = 0; i < ARRAY_SIZE(cs5535_mfd_cells); i++) {
+ int bar = cs5535_mfd_cells[i].id;
+ struct resource *r = &cs5535_mfd_resources[bar];
+
+ r->flags = IORESOURCE_IO;
+ r->start = pci_resource_start(pdev, bar);
+ r->end = pci_resource_end(pdev, bar);
+
+ /* id is used for temporarily storing BAR; unset it now */
+ cs5535_mfd_cells[i].id = 0;
+ }
+
+ err = mfd_add_devices(&pdev->dev, -1, cs5535_mfd_cells,
+ ARRAY_SIZE(cs5535_mfd_cells), NULL, 0);
+ if (err) {
+ dev_err(&pdev->dev, "MFD add devices failed: %d\n", err);
+ goto err_disable;
+ }
+
+ dev_info(&pdev->dev, "%zu devices registered.\n",
+ ARRAY_SIZE(cs5535_mfd_cells));
+
+ return 0;
+
+err_disable:
+ pci_disable_device(pdev);
+ return err;
+}
+
+static void __devexit cs5535_mfd_remove(struct pci_dev *pdev)
+{
+ mfd_remove_devices(&pdev->dev);
+ pci_disable_device(pdev);
+}
+
+static struct pci_device_id cs5535_mfd_pci_tbl[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_CS5535_ISA) },
+ { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_ISA) },
+ { 0, }
+};
+MODULE_DEVICE_TABLE(pci, cs5535_mfd_pci_tbl);
+
+static struct pci_driver cs5535_mfd_drv = {
+ .name = DRV_NAME,
+ .id_table = cs5535_mfd_pci_tbl,
+ .probe = cs5535_mfd_probe,
+ .remove = __devexit_p(cs5535_mfd_remove),
+};
+
+static int __init cs5535_mfd_init(void)
+{
+ return pci_register_driver(&cs5535_mfd_drv);
+}
+
+static void __exit cs5535_mfd_exit(void)
+{
+ pci_unregister_driver(&cs5535_mfd_drv);
+}
+
+module_init(cs5535_mfd_init);
+module_exit(cs5535_mfd_exit);
+
+MODULE_AUTHOR("Andres Salomon <dilinger@queued.net>");
+MODULE_DESCRIPTION("MFD driver for CS5535/CS5536 southbridge's ISA PCI device");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/ezx-pcap.c b/drivers/mfd/ezx-pcap.c
index c2b698d..9e2d8dd 100644
--- a/drivers/mfd/ezx-pcap.c
+++ b/drivers/mfd/ezx-pcap.c
@@ -144,26 +144,26 @@ int pcap_to_irq(struct pcap_chip *pcap, int irq)
}
EXPORT_SYMBOL_GPL(pcap_to_irq);
-static void pcap_mask_irq(unsigned int irq)
+static void pcap_mask_irq(struct irq_data *d)
{
- struct pcap_chip *pcap = get_irq_chip_data(irq);
+ struct pcap_chip *pcap = irq_data_get_irq_chip_data(d);
- pcap->msr |= 1 << irq_to_pcap(pcap, irq);
+ pcap->msr |= 1 << irq_to_pcap(pcap, d->irq);
queue_work(pcap->workqueue, &pcap->msr_work);
}
-static void pcap_unmask_irq(unsigned int irq)
+static void pcap_unmask_irq(struct irq_data *d)
{
- struct pcap_chip *pcap = get_irq_chip_data(irq);
+ struct pcap_chip *pcap = irq_data_get_irq_chip_data(d);
- pcap->msr &= ~(1 << irq_to_pcap(pcap, irq));
+ pcap->msr &= ~(1 << irq_to_pcap(pcap, d->irq));
queue_work(pcap->workqueue, &pcap->msr_work);
}
static struct irq_chip pcap_irq_chip = {
- .name = "pcap",
- .mask = pcap_mask_irq,
- .unmask = pcap_unmask_irq,
+ .name = "pcap",
+ .irq_mask = pcap_mask_irq,
+ .irq_unmask = pcap_unmask_irq,
};
static void pcap_msr_work(struct work_struct *work)
@@ -199,8 +199,7 @@ static void pcap_isr_work(struct work_struct *work)
if (service & 1) {
struct irq_desc *desc = irq_to_desc(irq);
- if (WARN(!desc, KERN_WARNING
- "Invalid PCAP IRQ %d\n", irq))
+ if (WARN(!desc, "Invalid PCAP IRQ %d\n", irq))
break;
if (desc->status & IRQ_DISABLED)
@@ -218,7 +217,7 @@ static void pcap_irq_handler(unsigned int irq, struct irq_desc *desc)
{
struct pcap_chip *pcap = get_irq_data(irq);
- desc->chip->ack(irq);
+ desc->irq_data.chip->irq_ack(&desc->irq_data);
queue_work(pcap->workqueue, &pcap->isr_work);
return;
}
@@ -282,7 +281,7 @@ static irqreturn_t pcap_adc_irq(int irq, void *_pcap)
mutex_lock(&pcap->adc_mutex);
req = pcap->adc_queue[pcap->adc_head];
- if (WARN(!req, KERN_WARNING "adc irq without pending request\n")) {
+ if (WARN(!req, "adc irq without pending request\n")) {
mutex_unlock(&pcap->adc_mutex);
return IRQ_HANDLED;
}
diff --git a/drivers/mfd/htc-egpio.c b/drivers/mfd/htc-egpio.c
index d3e74f8..d00b6d1 100644
--- a/drivers/mfd/htc-egpio.c
+++ b/drivers/mfd/htc-egpio.c
@@ -70,31 +70,32 @@ static inline void ack_irqs(struct egpio_info *ei)
ei->ack_write, ei->ack_register << ei->bus_shift);
}
-static void egpio_ack(unsigned int irq)
+static void egpio_ack(struct irq_data *data)
{
}
/* There does not appear to be a way to proactively mask interrupts
* on the egpio chip itself. So, we simply ignore interrupts that
* aren't desired. */
-static void egpio_mask(unsigned int irq)
+static void egpio_mask(struct irq_data *data)
{
- struct egpio_info *ei = get_irq_chip_data(irq);
- ei->irqs_enabled &= ~(1 << (irq - ei->irq_start));
- pr_debug("EGPIO mask %d %04x\n", irq, ei->irqs_enabled);
+ struct egpio_info *ei = irq_data_get_irq_chip_data(data);
+ ei->irqs_enabled &= ~(1 << (data->irq - ei->irq_start));
+ pr_debug("EGPIO mask %d %04x\n", data->irq, ei->irqs_enabled);
}
-static void egpio_unmask(unsigned int irq)
+
+static void egpio_unmask(struct irq_data *data)
{
- struct egpio_info *ei = get_irq_chip_data(irq);
- ei->irqs_enabled |= 1 << (irq - ei->irq_start);
- pr_debug("EGPIO unmask %d %04x\n", irq, ei->irqs_enabled);
+ struct egpio_info *ei = irq_data_get_irq_chip_data(data);
+ ei->irqs_enabled |= 1 << (data->irq - ei->irq_start);
+ pr_debug("EGPIO unmask %d %04x\n", data->irq, ei->irqs_enabled);
}
static struct irq_chip egpio_muxed_chip = {
- .name = "htc-egpio",
- .ack = egpio_ack,
- .mask = egpio_mask,
- .unmask = egpio_unmask,
+ .name = "htc-egpio",
+ .irq_ack = egpio_ack,
+ .irq_mask = egpio_mask,
+ .irq_unmask = egpio_unmask,
};
static void egpio_handler(unsigned int irq, struct irq_desc *desc)
diff --git a/drivers/mfd/htc-i2cpld.c b/drivers/mfd/htc-i2cpld.c
index 594c9a8..296ad15 100644
--- a/drivers/mfd/htc-i2cpld.c
+++ b/drivers/mfd/htc-i2cpld.c
@@ -82,25 +82,25 @@ struct htcpld_data {
/* There does not appear to be a way to proactively mask interrupts
* on the htcpld chip itself. So, we simply ignore interrupts that
* aren't desired. */
-static void htcpld_mask(unsigned int irq)
+static void htcpld_mask(struct irq_data *data)
{
- struct htcpld_chip *chip = get_irq_chip_data(irq);
- chip->irqs_enabled &= ~(1 << (irq - chip->irq_start));
- pr_debug("HTCPLD mask %d %04x\n", irq, chip->irqs_enabled);
+ struct htcpld_chip *chip = irq_data_get_irq_chip_data(data);
+ chip->irqs_enabled &= ~(1 << (data->irq - chip->irq_start));
+ pr_debug("HTCPLD mask %d %04x\n", data->irq, chip->irqs_enabled);
}
-static void htcpld_unmask(unsigned int irq)
+static void htcpld_unmask(struct irq_data *data)
{
- struct htcpld_chip *chip = get_irq_chip_data(irq);
- chip->irqs_enabled |= 1 << (irq - chip->irq_start);
- pr_debug("HTCPLD unmask %d %04x\n", irq, chip->irqs_enabled);
+ struct htcpld_chip *chip = irq_data_get_irq_chip_data(data);
+ chip->irqs_enabled |= 1 << (data->irq - chip->irq_start);
+ pr_debug("HTCPLD unmask %d %04x\n", data->irq, chip->irqs_enabled);
}
-static int htcpld_set_type(unsigned int irq, unsigned int flags)
+static int htcpld_set_type(struct irq_data *data, unsigned int flags)
{
- struct irq_desc *d = irq_to_desc(irq);
+ struct irq_desc *d = irq_to_desc(data->irq);
if (!d) {
- pr_err("HTCPLD invalid IRQ: %d\n", irq);
+ pr_err("HTCPLD invalid IRQ: %d\n", data->irq);
return -EINVAL;
}
@@ -118,10 +118,10 @@ static int htcpld_set_type(unsigned int irq, unsigned int flags)
}
static struct irq_chip htcpld_muxed_chip = {
- .name = "htcpld",
- .mask = htcpld_mask,
- .unmask = htcpld_unmask,
- .set_type = htcpld_set_type,
+ .name = "htcpld",
+ .irq_mask = htcpld_mask,
+ .irq_unmask = htcpld_unmask,
+ .irq_set_type = htcpld_set_type,
};
/* To properly dispatch IRQ events, we need to read from the
@@ -235,7 +235,7 @@ static irqreturn_t htcpld_handler(int irq, void *dev)
* and that work is scheduled in the set routine. The kernel can then run
* the I2C functions, which will sleep, in process context.
*/
-void htcpld_chip_set(struct gpio_chip *chip, unsigned offset, int val)
+static void htcpld_chip_set(struct gpio_chip *chip, unsigned offset, int val)
{
struct i2c_client *client;
struct htcpld_chip *chip_data;
@@ -259,7 +259,7 @@ void htcpld_chip_set(struct gpio_chip *chip, unsigned offset, int val)
schedule_work(&(chip_data->set_val_work));
}
-void htcpld_chip_set_ni(struct work_struct *work)
+static void htcpld_chip_set_ni(struct work_struct *work)
{
struct htcpld_chip *chip_data;
struct i2c_client *client;
@@ -269,7 +269,7 @@ void htcpld_chip_set_ni(struct work_struct *work)
i2c_smbus_read_byte_data(client, chip_data->cache_out);
}
-int htcpld_chip_get(struct gpio_chip *chip, unsigned offset)
+static int htcpld_chip_get(struct gpio_chip *chip, unsigned offset)
{
struct htcpld_chip *chip_data;
int val = 0;
@@ -316,7 +316,7 @@ static int htcpld_direction_input(struct gpio_chip *chip,
return (offset < chip->ngpio) ? 0 : -EINVAL;
}
-int htcpld_chip_to_irq(struct gpio_chip *chip, unsigned offset)
+static int htcpld_chip_to_irq(struct gpio_chip *chip, unsigned offset)
{
struct htcpld_chip *chip_data;
@@ -328,7 +328,7 @@ int htcpld_chip_to_irq(struct gpio_chip *chip, unsigned offset)
return -EINVAL;
}
-void htcpld_chip_reset(struct i2c_client *client)
+static void htcpld_chip_reset(struct i2c_client *client)
{
struct htcpld_chip *chip_data = i2c_get_clientdata(client);
if (!chip_data)
diff --git a/drivers/mfd/jz4740-adc.c b/drivers/mfd/jz4740-adc.c
index 9dd1b33..0cc5979 100644
--- a/drivers/mfd/jz4740-adc.c
+++ b/drivers/mfd/jz4740-adc.c
@@ -84,31 +84,30 @@ static inline void jz4740_adc_irq_set_masked(struct jz4740_adc *adc, int irq,
spin_unlock_irqrestore(&adc->lock, flags);
}
-static void jz4740_adc_irq_mask(unsigned int irq)
+static void jz4740_adc_irq_mask(struct irq_data *data)
{
- struct jz4740_adc *adc = get_irq_chip_data(irq);
- jz4740_adc_irq_set_masked(adc, irq, true);
+ struct jz4740_adc *adc = irq_data_get_irq_chip_data(data);
+ jz4740_adc_irq_set_masked(adc, data->irq, true);
}
-static void jz4740_adc_irq_unmask(unsigned int irq)
+static void jz4740_adc_irq_unmask(struct irq_data *data)
{
- struct jz4740_adc *adc = get_irq_chip_data(irq);
- jz4740_adc_irq_set_masked(adc, irq, false);
+ struct jz4740_adc *adc = irq_data_get_irq_chip_data(data);
+ jz4740_adc_irq_set_masked(adc, data->irq, false);
}
-static void jz4740_adc_irq_ack(unsigned int irq)
+static void jz4740_adc_irq_ack(struct irq_data *data)
{
- struct jz4740_adc *adc = get_irq_chip_data(irq);
-
- irq -= adc->irq_base;
+ struct jz4740_adc *adc = irq_data_get_irq_chip_data(data);
+ unsigned int irq = data->irq - adc->irq_base;
writeb(BIT(irq), adc->base + JZ_REG_ADC_STATUS);
}
static struct irq_chip jz4740_adc_irq_chip = {
.name = "jz4740-adc",
- .mask = jz4740_adc_irq_mask,
- .unmask = jz4740_adc_irq_unmask,
- .ack = jz4740_adc_irq_ack,
+ .irq_mask = jz4740_adc_irq_mask,
+ .irq_unmask = jz4740_adc_irq_unmask,
+ .irq_ack = jz4740_adc_irq_ack,
};
static void jz4740_adc_irq_demux(unsigned int irq, struct irq_desc *desc)
diff --git a/drivers/mfd/max8925-core.c b/drivers/mfd/max8925-core.c
index 44695f5..0e998dc 100644
--- a/drivers/mfd/max8925-core.c
+++ b/drivers/mfd/max8925-core.c
@@ -407,16 +407,16 @@ static irqreturn_t max8925_tsc_irq(int irq, void *data)
return IRQ_HANDLED;
}
-static void max8925_irq_lock(unsigned int irq)
+static void max8925_irq_lock(struct irq_data *data)
{
- struct max8925_chip *chip = get_irq_chip_data(irq);
+ struct max8925_chip *chip = irq_data_get_irq_chip_data(data);
mutex_lock(&chip->irq_lock);
}
-static void max8925_irq_sync_unlock(unsigned int irq)
+static void max8925_irq_sync_unlock(struct irq_data *data)
{
- struct max8925_chip *chip = get_irq_chip_data(irq);
+ struct max8925_chip *chip = irq_data_get_irq_chip_data(data);
struct max8925_irq_data *irq_data;
static unsigned char cache_chg[2] = {0xff, 0xff};
static unsigned char cache_on[2] = {0xff, 0xff};
@@ -492,25 +492,25 @@ static void max8925_irq_sync_unlock(unsigned int irq)
mutex_unlock(&chip->irq_lock);
}
-static void max8925_irq_enable(unsigned int irq)
+static void max8925_irq_enable(struct irq_data *data)
{
- struct max8925_chip *chip = get_irq_chip_data(irq);
- max8925_irqs[irq - chip->irq_base].enable
- = max8925_irqs[irq - chip->irq_base].offs;
+ struct max8925_chip *chip = irq_data_get_irq_chip_data(data);
+ max8925_irqs[data->irq - chip->irq_base].enable
+ = max8925_irqs[data->irq - chip->irq_base].offs;
}
-static void max8925_irq_disable(unsigned int irq)
+static void max8925_irq_disable(struct irq_data *data)
{
- struct max8925_chip *chip = get_irq_chip_data(irq);
- max8925_irqs[irq - chip->irq_base].enable = 0;
+ struct max8925_chip *chip = irq_data_get_irq_chip_data(data);
+ max8925_irqs[data->irq - chip->irq_base].enable = 0;
}
static struct irq_chip max8925_irq_chip = {
.name = "max8925",
- .bus_lock = max8925_irq_lock,
- .bus_sync_unlock = max8925_irq_sync_unlock,
- .enable = max8925_irq_enable,
- .disable = max8925_irq_disable,
+ .irq_bus_lock = max8925_irq_lock,
+ .irq_bus_sync_unlock = max8925_irq_sync_unlock,
+ .irq_enable = max8925_irq_enable,
+ .irq_disable = max8925_irq_disable,
};
static int max8925_irq_init(struct max8925_chip *chip, int irq,
diff --git a/drivers/mfd/max8998-irq.c b/drivers/mfd/max8998-irq.c
index 45bfe77..3903e1f 100644
--- a/drivers/mfd/max8998-irq.c
+++ b/drivers/mfd/max8998-irq.c
@@ -102,16 +102,16 @@ irq_to_max8998_irq(struct max8998_dev *max8998, int irq)
return &max8998_irqs[irq - max8998->irq_base];
}
-static void max8998_irq_lock(unsigned int irq)
+static void max8998_irq_lock(struct irq_data *data)
{
- struct max8998_dev *max8998 = get_irq_chip_data(irq);
+ struct max8998_dev *max8998 = irq_data_get_irq_chip_data(data);
mutex_lock(&max8998->irqlock);
}
-static void max8998_irq_sync_unlock(unsigned int irq)
+static void max8998_irq_sync_unlock(struct irq_data *data)
{
- struct max8998_dev *max8998 = get_irq_chip_data(irq);
+ struct max8998_dev *max8998 = irq_data_get_irq_chip_data(data);
int i;
for (i = 0; i < ARRAY_SIZE(max8998->irq_masks_cur); i++) {
@@ -129,28 +129,30 @@ static void max8998_irq_sync_unlock(unsigned int irq)
mutex_unlock(&max8998->irqlock);
}
-static void max8998_irq_unmask(unsigned int irq)
+static void max8998_irq_unmask(struct irq_data *data)
{
- struct max8998_dev *max8998 = get_irq_chip_data(irq);
- struct max8998_irq_data *irq_data = irq_to_max8998_irq(max8998, irq);
+ struct max8998_dev *max8998 = irq_data_get_irq_chip_data(data);
+ struct max8998_irq_data *irq_data = irq_to_max8998_irq(max8998,
+ data->irq);
max8998->irq_masks_cur[irq_data->reg - 1] &= ~irq_data->mask;
}
-static void max8998_irq_mask(unsigned int irq)
+static void max8998_irq_mask(struct irq_data *data)
{
- struct max8998_dev *max8998 = get_irq_chip_data(irq);
- struct max8998_irq_data *irq_data = irq_to_max8998_irq(max8998, irq);
+ struct max8998_dev *max8998 = irq_data_get_irq_chip_data(data);
+ struct max8998_irq_data *irq_data = irq_to_max8998_irq(max8998,
+ data->irq);
max8998->irq_masks_cur[irq_data->reg - 1] |= irq_data->mask;
}
static struct irq_chip max8998_irq_chip = {
.name = "max8998",
- .bus_lock = max8998_irq_lock,
- .bus_sync_unlock = max8998_irq_sync_unlock,
- .mask = max8998_irq_mask,
- .unmask = max8998_irq_unmask,
+ .irq_bus_lock = max8998_irq_lock,
+ .irq_bus_sync_unlock = max8998_irq_sync_unlock,
+ .irq_mask = max8998_irq_mask,
+ .irq_unmask = max8998_irq_unmask,
};
static irqreturn_t max8998_irq_thread(int irq, void *data)
@@ -181,6 +183,13 @@ static irqreturn_t max8998_irq_thread(int irq, void *data)
return IRQ_HANDLED;
}
+int max8998_irq_resume(struct max8998_dev *max8998)
+{
+ if (max8998->irq && max8998->irq_base)
+ max8998_irq_thread(max8998->irq_base, max8998);
+ return 0;
+}
+
int max8998_irq_init(struct max8998_dev *max8998)
{
int i;
diff --git a/drivers/mfd/max8998.c b/drivers/mfd/max8998.c
index bb9977b..bbfe867 100644
--- a/drivers/mfd/max8998.c
+++ b/drivers/mfd/max8998.c
@@ -25,6 +25,8 @@
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/pm_runtime.h>
#include <linux/mutex.h>
#include <linux/mfd/core.h>
#include <linux/mfd/max8998.h>
@@ -40,6 +42,14 @@ static struct mfd_cell max8998_devs[] = {
},
};
+static struct mfd_cell lp3974_devs[] = {
+ {
+ .name = "lp3974-pmic",
+ }, {
+ .name = "lp3974-rtc",
+ },
+};
+
int max8998_read_reg(struct i2c_client *i2c, u8 reg, u8 *dest)
{
struct max8998_dev *max8998 = i2c_get_clientdata(i2c);
@@ -135,6 +145,7 @@ static int max8998_i2c_probe(struct i2c_client *i2c,
if (pdata) {
max8998->ono = pdata->ono;
max8998->irq_base = pdata->irq_base;
+ max8998->wakeup = pdata->wakeup;
}
mutex_init(&max8998->iolock);
@@ -143,9 +154,23 @@ static int max8998_i2c_probe(struct i2c_client *i2c,
max8998_irq_init(max8998);
- ret = mfd_add_devices(max8998->dev, -1,
- max8998_devs, ARRAY_SIZE(max8998_devs),
- NULL, 0);
+ pm_runtime_set_active(max8998->dev);
+
+ switch (id->driver_data) {
+ case TYPE_LP3974:
+ ret = mfd_add_devices(max8998->dev, -1,
+ lp3974_devs, ARRAY_SIZE(lp3974_devs),
+ NULL, 0);
+ break;
+ case TYPE_MAX8998:
+ ret = mfd_add_devices(max8998->dev, -1,
+ max8998_devs, ARRAY_SIZE(max8998_devs),
+ NULL, 0);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
if (ret < 0)
goto err;
@@ -178,10 +203,113 @@ static const struct i2c_device_id max8998_i2c_id[] = {
};
MODULE_DEVICE_TABLE(i2c, max8998_i2c_id);
+static int max8998_suspend(struct device *dev)
+{
+ struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
+ struct max8998_dev *max8998 = i2c_get_clientdata(i2c);
+
+ if (max8998->wakeup)
+ set_irq_wake(max8998->irq, 1);
+ return 0;
+}
+
+static int max8998_resume(struct device *dev)
+{
+ struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
+ struct max8998_dev *max8998 = i2c_get_clientdata(i2c);
+
+ if (max8998->wakeup)
+ set_irq_wake(max8998->irq, 0);
+ /*
+ * In LP3974, if IRQ registers are not "read & clear"
+ * when it's set during sleep, the interrupt becomes
+ * disabled.
+ */
+ return max8998_irq_resume(i2c_get_clientdata(i2c));
+}
+
+struct max8998_reg_dump {
+ u8 addr;
+ u8 val;
+};
+#define SAVE_ITEM(x) { .addr = (x), .val = 0x0, }
+struct max8998_reg_dump max8998_dump[] = {
+ SAVE_ITEM(MAX8998_REG_IRQM1),
+ SAVE_ITEM(MAX8998_REG_IRQM2),
+ SAVE_ITEM(MAX8998_REG_IRQM3),
+ SAVE_ITEM(MAX8998_REG_IRQM4),
+ SAVE_ITEM(MAX8998_REG_STATUSM1),
+ SAVE_ITEM(MAX8998_REG_STATUSM2),
+ SAVE_ITEM(MAX8998_REG_CHGR1),
+ SAVE_ITEM(MAX8998_REG_CHGR2),
+ SAVE_ITEM(MAX8998_REG_LDO_ACTIVE_DISCHARGE1),
+ SAVE_ITEM(MAX8998_REG_LDO_ACTIVE_DISCHARGE1),
+ SAVE_ITEM(MAX8998_REG_BUCK_ACTIVE_DISCHARGE3),
+ SAVE_ITEM(MAX8998_REG_ONOFF1),
+ SAVE_ITEM(MAX8998_REG_ONOFF2),
+ SAVE_ITEM(MAX8998_REG_ONOFF3),
+ SAVE_ITEM(MAX8998_REG_ONOFF4),
+ SAVE_ITEM(MAX8998_REG_BUCK1_VOLTAGE1),
+ SAVE_ITEM(MAX8998_REG_BUCK1_VOLTAGE2),
+ SAVE_ITEM(MAX8998_REG_BUCK1_VOLTAGE3),
+ SAVE_ITEM(MAX8998_REG_BUCK1_VOLTAGE4),
+ SAVE_ITEM(MAX8998_REG_BUCK2_VOLTAGE1),
+ SAVE_ITEM(MAX8998_REG_BUCK2_VOLTAGE2),
+ SAVE_ITEM(MAX8998_REG_LDO2_LDO3),
+ SAVE_ITEM(MAX8998_REG_LDO4),
+ SAVE_ITEM(MAX8998_REG_LDO5),
+ SAVE_ITEM(MAX8998_REG_LDO6),
+ SAVE_ITEM(MAX8998_REG_LDO7),
+ SAVE_ITEM(MAX8998_REG_LDO8_LDO9),
+ SAVE_ITEM(MAX8998_REG_LDO10_LDO11),
+ SAVE_ITEM(MAX8998_REG_LDO12),
+ SAVE_ITEM(MAX8998_REG_LDO13),
+ SAVE_ITEM(MAX8998_REG_LDO14),
+ SAVE_ITEM(MAX8998_REG_LDO15),
+ SAVE_ITEM(MAX8998_REG_LDO16),
+ SAVE_ITEM(MAX8998_REG_LDO17),
+ SAVE_ITEM(MAX8998_REG_BKCHR),
+ SAVE_ITEM(MAX8998_REG_LBCNFG1),
+ SAVE_ITEM(MAX8998_REG_LBCNFG2),
+};
+/* Save registers before hibernation */
+static int max8998_freeze(struct device *dev)
+{
+ struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(max8998_dump); i++)
+ max8998_read_reg(i2c, max8998_dump[i].addr,
+ &max8998_dump[i].val);
+
+ return 0;
+}
+
+/* Restore registers after hibernation */
+static int max8998_restore(struct device *dev)
+{
+ struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(max8998_dump); i++)
+ max8998_write_reg(i2c, max8998_dump[i].addr,
+ max8998_dump[i].val);
+
+ return 0;
+}
+
+const struct dev_pm_ops max8998_pm = {
+ .suspend = max8998_suspend,
+ .resume = max8998_resume,
+ .freeze = max8998_freeze,
+ .restore = max8998_restore,
+};
+
static struct i2c_driver max8998_i2c_driver = {
.driver = {
.name = "max8998",
.owner = THIS_MODULE,
+ .pm = &max8998_pm,
},
.probe = max8998_i2c_probe,
.remove = max8998_i2c_remove,
diff --git a/drivers/mfd/mc13xxx-core.c b/drivers/mfd/mc13xxx-core.c
index a2ac2ed..b9fcaf0 100644
--- a/drivers/mfd/mc13xxx-core.c
+++ b/drivers/mfd/mc13xxx-core.c
@@ -749,7 +749,7 @@ static int mc13xxx_probe(struct spi_device *spi)
if (ret) {
err_mask:
err_revision:
- mutex_unlock(&mc13xxx->lock);
+ mc13xxx_unlock(mc13xxx);
dev_set_drvdata(&spi->dev, NULL);
kfree(mc13xxx);
return ret;
diff --git a/drivers/mfd/mfd-core.c b/drivers/mfd/mfd-core.c
index ec99f68..d83ad0f 100644
--- a/drivers/mfd/mfd-core.c
+++ b/drivers/mfd/mfd-core.c
@@ -15,6 +15,7 @@
#include <linux/platform_device.h>
#include <linux/acpi.h>
#include <linux/mfd/core.h>
+#include <linux/pm_runtime.h>
#include <linux/slab.h>
static int mfd_add_device(struct device *parent, int id,
@@ -82,6 +83,9 @@ static int mfd_add_device(struct device *parent, int id,
if (ret)
goto fail_res;
+ if (cell->pm_runtime_no_callbacks)
+ pm_runtime_no_callbacks(&pdev->dev);
+
kfree(res);
return 0;
diff --git a/drivers/mfd/sm501.c b/drivers/mfd/sm501.c
index bc9275c..5de3a76 100644
--- a/drivers/mfd/sm501.c
+++ b/drivers/mfd/sm501.c
@@ -26,7 +26,7 @@
#include <linux/sm501-regs.h>
#include <linux/serial_8250.h>
-#include <asm/io.h>
+#include <linux/io.h>
struct sm501_device {
struct list_head list;
@@ -745,11 +745,8 @@ static int sm501_register_device(struct sm501_devdata *sm,
int ret;
for (ptr = 0; ptr < pdev->num_resources; ptr++) {
- printk(KERN_DEBUG "%s[%d] flags %08lx: %08llx..%08llx\n",
- pdev->name, ptr,
- pdev->resource[ptr].flags,
- (unsigned long long)pdev->resource[ptr].start,
- (unsigned long long)pdev->resource[ptr].end);
+ printk(KERN_DEBUG "%s[%d] %pR\n",
+ pdev->name, ptr, &pdev->resource[ptr]);
}
ret = platform_device_register(pdev);
diff --git a/drivers/mfd/stmpe.c b/drivers/mfd/stmpe.c
index b11487f..3e5732b 100644
--- a/drivers/mfd/stmpe.c
+++ b/drivers/mfd/stmpe.c
@@ -699,16 +699,16 @@ static irqreturn_t stmpe_irq(int irq, void *data)
return IRQ_HANDLED;
}
-static void stmpe_irq_lock(unsigned int irq)
+static void stmpe_irq_lock(struct irq_data *data)
{
- struct stmpe *stmpe = get_irq_chip_data(irq);
+ struct stmpe *stmpe = irq_data_get_irq_chip_data(data);
mutex_lock(&stmpe->irq_lock);
}
-static void stmpe_irq_sync_unlock(unsigned int irq)
+static void stmpe_irq_sync_unlock(struct irq_data *data)
{
- struct stmpe *stmpe = get_irq_chip_data(irq);
+ struct stmpe *stmpe = irq_data_get_irq_chip_data(data);
struct stmpe_variant_info *variant = stmpe->variant;
int num = DIV_ROUND_UP(variant->num_irqs, 8);
int i;
@@ -727,20 +727,20 @@ static void stmpe_irq_sync_unlock(unsigned int irq)
mutex_unlock(&stmpe->irq_lock);
}
-static void stmpe_irq_mask(unsigned int irq)
+static void stmpe_irq_mask(struct irq_data *data)
{
- struct stmpe *stmpe = get_irq_chip_data(irq);
- int offset = irq - stmpe->irq_base;
+ struct stmpe *stmpe = irq_data_get_irq_chip_data(data);
+ int offset = data->irq - stmpe->irq_base;
int regoffset = offset / 8;
int mask = 1 << (offset % 8);
stmpe->ier[regoffset] &= ~mask;
}
-static void stmpe_irq_unmask(unsigned int irq)
+static void stmpe_irq_unmask(struct irq_data *data)
{
- struct stmpe *stmpe = get_irq_chip_data(irq);
- int offset = irq - stmpe->irq_base;
+ struct stmpe *stmpe = irq_data_get_irq_chip_data(data);
+ int offset = data->irq - stmpe->irq_base;
int regoffset = offset / 8;
int mask = 1 << (offset % 8);
@@ -749,10 +749,10 @@ static void stmpe_irq_unmask(unsigned int irq)
static struct irq_chip stmpe_irq_chip = {
.name = "stmpe",
- .bus_lock = stmpe_irq_lock,
- .bus_sync_unlock = stmpe_irq_sync_unlock,
- .mask = stmpe_irq_mask,
- .unmask = stmpe_irq_unmask,
+ .irq_bus_lock = stmpe_irq_lock,
+ .irq_bus_sync_unlock = stmpe_irq_sync_unlock,
+ .irq_mask = stmpe_irq_mask,
+ .irq_unmask = stmpe_irq_unmask,
};
static int __devinit stmpe_irq_init(struct stmpe *stmpe)
diff --git a/drivers/mfd/t7l66xb.c b/drivers/mfd/t7l66xb.c
index 006c121..9caeb4a 100644
--- a/drivers/mfd/t7l66xb.c
+++ b/drivers/mfd/t7l66xb.c
@@ -199,37 +199,37 @@ static void t7l66xb_irq(unsigned int irq, struct irq_desc *desc)
generic_handle_irq(irq_base + i);
}
-static void t7l66xb_irq_mask(unsigned int irq)
+static void t7l66xb_irq_mask(struct irq_data *data)
{
- struct t7l66xb *t7l66xb = get_irq_chip_data(irq);
+ struct t7l66xb *t7l66xb = irq_data_get_irq_chip_data(data);
unsigned long flags;
u8 imr;
spin_lock_irqsave(&t7l66xb->lock, flags);
imr = tmio_ioread8(t7l66xb->scr + SCR_IMR);
- imr |= 1 << (irq - t7l66xb->irq_base);
+ imr |= 1 << (data->irq - t7l66xb->irq_base);
tmio_iowrite8(imr, t7l66xb->scr + SCR_IMR);
spin_unlock_irqrestore(&t7l66xb->lock, flags);
}
-static void t7l66xb_irq_unmask(unsigned int irq)
+static void t7l66xb_irq_unmask(struct irq_data *data)
{
- struct t7l66xb *t7l66xb = get_irq_chip_data(irq);
+ struct t7l66xb *t7l66xb = irq_data_get_irq_chip_data(data);
unsigned long flags;
u8 imr;
spin_lock_irqsave(&t7l66xb->lock, flags);
imr = tmio_ioread8(t7l66xb->scr + SCR_IMR);
- imr &= ~(1 << (irq - t7l66xb->irq_base));
+ imr &= ~(1 << (data->irq - t7l66xb->irq_base));
tmio_iowrite8(imr, t7l66xb->scr + SCR_IMR);
spin_unlock_irqrestore(&t7l66xb->lock, flags);
}
static struct irq_chip t7l66xb_chip = {
- .name = "t7l66xb",
- .ack = t7l66xb_irq_mask,
- .mask = t7l66xb_irq_mask,
- .unmask = t7l66xb_irq_unmask,
+ .name = "t7l66xb",
+ .irq_ack = t7l66xb_irq_mask,
+ .irq_mask = t7l66xb_irq_mask,
+ .irq_unmask = t7l66xb_irq_unmask,
};
/*--------------------------------------------------------------------------*/
diff --git a/drivers/mfd/tc6393xb.c b/drivers/mfd/tc6393xb.c
index 1ea80d8a..9a23863 100644
--- a/drivers/mfd/tc6393xb.c
+++ b/drivers/mfd/tc6393xb.c
@@ -527,41 +527,41 @@ tc6393xb_irq(unsigned int irq, struct irq_desc *desc)
}
}
-static void tc6393xb_irq_ack(unsigned int irq)
+static void tc6393xb_irq_ack(struct irq_data *data)
{
}
-static void tc6393xb_irq_mask(unsigned int irq)
+static void tc6393xb_irq_mask(struct irq_data *data)
{
- struct tc6393xb *tc6393xb = get_irq_chip_data(irq);
+ struct tc6393xb *tc6393xb = irq_data_get_irq_chip_data(data);
unsigned long flags;
u8 imr;
spin_lock_irqsave(&tc6393xb->lock, flags);
imr = tmio_ioread8(tc6393xb->scr + SCR_IMR);
- imr |= 1 << (irq - tc6393xb->irq_base);
+ imr |= 1 << (data->irq - tc6393xb->irq_base);
tmio_iowrite8(imr, tc6393xb->scr + SCR_IMR);
spin_unlock_irqrestore(&tc6393xb->lock, flags);
}
-static void tc6393xb_irq_unmask(unsigned int irq)
+static void tc6393xb_irq_unmask(struct irq_data *data)
{
- struct tc6393xb *tc6393xb = get_irq_chip_data(irq);
+ struct tc6393xb *tc6393xb = irq_data_get_irq_chip_data(data);
unsigned long flags;
u8 imr;
spin_lock_irqsave(&tc6393xb->lock, flags);
imr = tmio_ioread8(tc6393xb->scr + SCR_IMR);
- imr &= ~(1 << (irq - tc6393xb->irq_base));
+ imr &= ~(1 << (data->irq - tc6393xb->irq_base));
tmio_iowrite8(imr, tc6393xb->scr + SCR_IMR);
spin_unlock_irqrestore(&tc6393xb->lock, flags);
}
static struct irq_chip tc6393xb_chip = {
- .name = "tc6393xb",
- .ack = tc6393xb_irq_ack,
- .mask = tc6393xb_irq_mask,
- .unmask = tc6393xb_irq_unmask,
+ .name = "tc6393xb",
+ .irq_ack = tc6393xb_irq_ack,
+ .irq_mask = tc6393xb_irq_mask,
+ .irq_unmask = tc6393xb_irq_unmask,
};
static void tc6393xb_attach_irq(struct platform_device *dev)
diff --git a/drivers/mfd/tps65010.c b/drivers/mfd/tps65010.c
index 90187fe..93d5fdf 100644
--- a/drivers/mfd/tps65010.c
+++ b/drivers/mfd/tps65010.c
@@ -34,7 +34,7 @@
#include <linux/i2c/tps65010.h>
-#include <asm/gpio.h>
+#include <linux/gpio.h>
/*-------------------------------------------------------------------------*/
diff --git a/drivers/mfd/tps6586x.c b/drivers/mfd/tps6586x.c
index b4931ab..627cf57 100644
--- a/drivers/mfd/tps6586x.c
+++ b/drivers/mfd/tps6586x.c
@@ -46,8 +46,6 @@
/* device id */
#define TPS6586X_VERSIONCRC 0xcd
-#define TPS658621A_VERSIONCRC 0x15
-#define TPS658621C_VERSIONCRC 0x2c
struct tps6586x_irq_data {
u8 mask_reg;
@@ -325,37 +323,37 @@ static int tps6586x_remove_subdevs(struct tps6586x *tps6586x)
return device_for_each_child(tps6586x->dev, NULL, __remove_subdev);
}
-static void tps6586x_irq_lock(unsigned int irq)
+static void tps6586x_irq_lock(struct irq_data *data)
{
- struct tps6586x *tps6586x = get_irq_chip_data(irq);
+ struct tps6586x *tps6586x = irq_data_get_irq_chip_data(data);
mutex_lock(&tps6586x->irq_lock);
}
-static void tps6586x_irq_enable(unsigned int irq)
+static void tps6586x_irq_enable(struct irq_data *irq_data)
{
- struct tps6586x *tps6586x = get_irq_chip_data(irq);
- unsigned int __irq = irq - tps6586x->irq_base;
+ struct tps6586x *tps6586x = irq_data_get_irq_chip_data(irq_data);
+ unsigned int __irq = irq_data->irq - tps6586x->irq_base;
const struct tps6586x_irq_data *data = &tps6586x_irqs[__irq];
tps6586x->mask_reg[data->mask_reg] &= ~data->mask_mask;
tps6586x->irq_en |= (1 << __irq);
}
-static void tps6586x_irq_disable(unsigned int irq)
+static void tps6586x_irq_disable(struct irq_data *irq_data)
{
- struct tps6586x *tps6586x = get_irq_chip_data(irq);
+ struct tps6586x *tps6586x = irq_data_get_irq_chip_data(irq_data);
- unsigned int __irq = irq - tps6586x->irq_base;
+ unsigned int __irq = irq_data->irq - tps6586x->irq_base;
const struct tps6586x_irq_data *data = &tps6586x_irqs[__irq];
tps6586x->mask_reg[data->mask_reg] |= data->mask_mask;
tps6586x->irq_en &= ~(1 << __irq);
}
-static void tps6586x_irq_sync_unlock(unsigned int irq)
+static void tps6586x_irq_sync_unlock(struct irq_data *data)
{
- struct tps6586x *tps6586x = get_irq_chip_data(irq);
+ struct tps6586x *tps6586x = irq_data_get_irq_chip_data(data);
int i;
for (i = 0; i < ARRAY_SIZE(tps6586x->mask_reg); i++) {
@@ -421,10 +419,10 @@ static int __devinit tps6586x_irq_init(struct tps6586x *tps6586x, int irq,
tps6586x->irq_base = irq_base;
tps6586x->irq_chip.name = "tps6586x";
- tps6586x->irq_chip.enable = tps6586x_irq_enable;
- tps6586x->irq_chip.disable = tps6586x_irq_disable;
- tps6586x->irq_chip.bus_lock = tps6586x_irq_lock;
- tps6586x->irq_chip.bus_sync_unlock = tps6586x_irq_sync_unlock;
+ tps6586x->irq_chip.irq_enable = tps6586x_irq_enable;
+ tps6586x->irq_chip.irq_disable = tps6586x_irq_disable;
+ tps6586x->irq_chip.irq_bus_lock = tps6586x_irq_lock;
+ tps6586x->irq_chip.irq_bus_sync_unlock = tps6586x_irq_sync_unlock;
for (i = 0; i < ARRAY_SIZE(tps6586x_irqs); i++) {
int __irq = i + tps6586x->irq_base;
@@ -498,11 +496,7 @@ static int __devinit tps6586x_i2c_probe(struct i2c_client *client,
return -EIO;
}
- if ((ret != TPS658621A_VERSIONCRC) &&
- (ret != TPS658621C_VERSIONCRC)) {
- dev_err(&client->dev, "Unsupported chip ID: %x\n", ret);
- return -ENODEV;
- }
+ dev_info(&client->dev, "VERSIONCRC is %02x\n", ret);
tps6586x = kzalloc(sizeof(struct tps6586x), GFP_KERNEL);
if (tps6586x == NULL)
diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c
index 12abd5b..a35fa7d 100644
--- a/drivers/mfd/twl-core.c
+++ b/drivers/mfd/twl-core.c
@@ -1003,7 +1003,7 @@ static int twl_remove(struct i2c_client *client)
}
/* NOTE: this driver only handles a single twl4030/tps659x0 chip */
-static int __init
+static int __devinit
twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
int status;
diff --git a/drivers/mfd/twl4030-irq.c b/drivers/mfd/twl4030-irq.c
index 5d3a147..63a30e8 100644
--- a/drivers/mfd/twl4030-irq.c
+++ b/drivers/mfd/twl4030-irq.c
@@ -599,38 +599,38 @@ static void twl4030_sih_do_edge(struct work_struct *work)
* completion, potentially including some re-ordering, of these requests.
*/
-static void twl4030_sih_mask(unsigned irq)
+static void twl4030_sih_mask(struct irq_data *data)
{
- struct sih_agent *sih = get_irq_chip_data(irq);
+ struct sih_agent *sih = irq_data_get_irq_chip_data(data);
unsigned long flags;
spin_lock_irqsave(&sih_agent_lock, flags);
- sih->imr |= BIT(irq - sih->irq_base);
+ sih->imr |= BIT(data->irq - sih->irq_base);
sih->imr_change_pending = true;
queue_work(wq, &sih->mask_work);
spin_unlock_irqrestore(&sih_agent_lock, flags);
}
-static void twl4030_sih_unmask(unsigned irq)
+static void twl4030_sih_unmask(struct irq_data *data)
{
- struct sih_agent *sih = get_irq_chip_data(irq);
+ struct sih_agent *sih = irq_data_get_irq_chip_data(data);
unsigned long flags;
spin_lock_irqsave(&sih_agent_lock, flags);
- sih->imr &= ~BIT(irq - sih->irq_base);
+ sih->imr &= ~BIT(data->irq - sih->irq_base);
sih->imr_change_pending = true;
queue_work(wq, &sih->mask_work);
spin_unlock_irqrestore(&sih_agent_lock, flags);
}
-static int twl4030_sih_set_type(unsigned irq, unsigned trigger)
+static int twl4030_sih_set_type(struct irq_data *data, unsigned trigger)
{
- struct sih_agent *sih = get_irq_chip_data(irq);
- struct irq_desc *desc = irq_to_desc(irq);
+ struct sih_agent *sih = irq_data_get_irq_chip_data(data);
+ struct irq_desc *desc = irq_to_desc(data->irq);
unsigned long flags;
if (!desc) {
- pr_err("twl4030: Invalid IRQ: %d\n", irq);
+ pr_err("twl4030: Invalid IRQ: %d\n", data->irq);
return -EINVAL;
}
@@ -641,7 +641,7 @@ static int twl4030_sih_set_type(unsigned irq, unsigned trigger)
if ((desc->status & IRQ_TYPE_SENSE_MASK) != trigger) {
desc->status &= ~IRQ_TYPE_SENSE_MASK;
desc->status |= trigger;
- sih->edge_change |= BIT(irq - sih->irq_base);
+ sih->edge_change |= BIT(data->irq - sih->irq_base);
queue_work(wq, &sih->edge_work);
}
spin_unlock_irqrestore(&sih_agent_lock, flags);
@@ -650,9 +650,9 @@ static int twl4030_sih_set_type(unsigned irq, unsigned trigger)
static struct irq_chip twl4030_sih_irq_chip = {
.name = "twl4030",
- .mask = twl4030_sih_mask,
- .unmask = twl4030_sih_unmask,
- .set_type = twl4030_sih_set_type,
+ .irq_mask = twl4030_sih_mask,
+ .irq_unmask = twl4030_sih_unmask,
+ .irq_set_type = twl4030_sih_set_type,
};
/*----------------------------------------------------------------------*/
diff --git a/drivers/mfd/twl6030-irq.c b/drivers/mfd/twl6030-irq.c
index 06c8955..4082ed7 100644
--- a/drivers/mfd/twl6030-irq.c
+++ b/drivers/mfd/twl6030-irq.c
@@ -332,7 +332,7 @@ int twl6030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end)
*/
twl6030_irq_chip = dummy_irq_chip;
twl6030_irq_chip.name = "twl6030";
- twl6030_irq_chip.set_type = NULL;
+ twl6030_irq_chip.irq_set_type = NULL;
for (i = irq_base; i < irq_end; i++) {
set_irq_chip_and_handler(i, &twl6030_irq_chip,
diff --git a/drivers/mfd/vx855.c b/drivers/mfd/vx855.c
index ebb0597..348052a 100644
--- a/drivers/mfd/vx855.c
+++ b/drivers/mfd/vx855.c
@@ -112,7 +112,7 @@ out:
return ret;
}
-static void vx855_remove(struct pci_dev *pdev)
+static void __devexit vx855_remove(struct pci_dev *pdev)
{
mfd_remove_devices(&pdev->dev);
pci_disable_device(pdev);
diff --git a/drivers/mfd/wm831x-core.c b/drivers/mfd/wm831x-core.c
index 76cadcf..3fe9a58 100644
--- a/drivers/mfd/wm831x-core.c
+++ b/drivers/mfd/wm831x-core.c
@@ -1541,6 +1541,12 @@ int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq)
dev_info(wm831x->dev, "WM8325 revision %c\n", 'A' + rev);
break;
+ case WM8326:
+ parent = WM8326;
+ wm831x->num_gpio = 12;
+ dev_info(wm831x->dev, "WM8326 revision %c\n", 'A' + rev);
+ break;
+
default:
dev_err(wm831x->dev, "Unknown WM831x device %04x\n", ret);
ret = -EINVAL;
@@ -1610,18 +1616,9 @@ int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq)
break;
case WM8320:
- ret = mfd_add_devices(wm831x->dev, -1,
- wm8320_devs, ARRAY_SIZE(wm8320_devs),
- NULL, 0);
- break;
-
case WM8321:
- ret = mfd_add_devices(wm831x->dev, -1,
- wm8320_devs, ARRAY_SIZE(wm8320_devs),
- NULL, 0);
- break;
-
case WM8325:
+ case WM8326:
ret = mfd_add_devices(wm831x->dev, -1,
wm8320_devs, ARRAY_SIZE(wm8320_devs),
NULL, wm831x->irq_base);
diff --git a/drivers/mfd/wm831x-i2c.c b/drivers/mfd/wm831x-i2c.c
index 156b198..3853fa8 100644
--- a/drivers/mfd/wm831x-i2c.c
+++ b/drivers/mfd/wm831x-i2c.c
@@ -94,9 +94,9 @@ static int wm831x_i2c_remove(struct i2c_client *i2c)
return 0;
}
-static int wm831x_i2c_suspend(struct i2c_client *i2c, pm_message_t mesg)
+static int wm831x_i2c_suspend(struct device *dev)
{
- struct wm831x *wm831x = i2c_get_clientdata(i2c);
+ struct wm831x *wm831x = dev_get_drvdata(dev);
return wm831x_device_suspend(wm831x);
}
@@ -108,19 +108,23 @@ static const struct i2c_device_id wm831x_i2c_id[] = {
{ "wm8320", WM8320 },
{ "wm8321", WM8321 },
{ "wm8325", WM8325 },
+ { "wm8326", WM8326 },
{ }
};
MODULE_DEVICE_TABLE(i2c, wm831x_i2c_id);
+static const struct dev_pm_ops wm831x_pm_ops = {
+ .suspend = wm831x_i2c_suspend,
+};
static struct i2c_driver wm831x_i2c_driver = {
.driver = {
- .name = "wm831x",
- .owner = THIS_MODULE,
+ .name = "wm831x",
+ .owner = THIS_MODULE,
+ .pm = &wm831x_pm_ops,
},
.probe = wm831x_i2c_probe,
.remove = wm831x_i2c_remove,
- .suspend = wm831x_i2c_suspend,
.id_table = wm831x_i2c_id,
};
diff --git a/drivers/mfd/wm831x-irq.c b/drivers/mfd/wm831x-irq.c
index 294183b..f7192d4 100644
--- a/drivers/mfd/wm831x-irq.c
+++ b/drivers/mfd/wm831x-irq.c
@@ -345,16 +345,16 @@ static inline struct wm831x_irq_data *irq_to_wm831x_irq(struct wm831x *wm831x,
return &wm831x_irqs[irq - wm831x->irq_base];
}
-static void wm831x_irq_lock(unsigned int irq)
+static void wm831x_irq_lock(struct irq_data *data)
{
- struct wm831x *wm831x = get_irq_chip_data(irq);
+ struct wm831x *wm831x = irq_data_get_irq_chip_data(data);
mutex_lock(&wm831x->irq_lock);
}
-static void wm831x_irq_sync_unlock(unsigned int irq)
+static void wm831x_irq_sync_unlock(struct irq_data *data)
{
- struct wm831x *wm831x = get_irq_chip_data(irq);
+ struct wm831x *wm831x = irq_data_get_irq_chip_data(data);
int i;
for (i = 0; i < ARRAY_SIZE(wm831x->irq_masks_cur); i++) {
@@ -371,28 +371,30 @@ static void wm831x_irq_sync_unlock(unsigned int irq)
mutex_unlock(&wm831x->irq_lock);
}
-static void wm831x_irq_unmask(unsigned int irq)
+static void wm831x_irq_unmask(struct irq_data *data)
{
- struct wm831x *wm831x = get_irq_chip_data(irq);
- struct wm831x_irq_data *irq_data = irq_to_wm831x_irq(wm831x, irq);
+ struct wm831x *wm831x = irq_data_get_irq_chip_data(data);
+ struct wm831x_irq_data *irq_data = irq_to_wm831x_irq(wm831x,
+ data->irq);
wm831x->irq_masks_cur[irq_data->reg - 1] &= ~irq_data->mask;
}
-static void wm831x_irq_mask(unsigned int irq)
+static void wm831x_irq_mask(struct irq_data *data)
{
- struct wm831x *wm831x = get_irq_chip_data(irq);
- struct wm831x_irq_data *irq_data = irq_to_wm831x_irq(wm831x, irq);
+ struct wm831x *wm831x = irq_data_get_irq_chip_data(data);
+ struct wm831x_irq_data *irq_data = irq_to_wm831x_irq(wm831x,
+ data->irq);
wm831x->irq_masks_cur[irq_data->reg - 1] |= irq_data->mask;
}
-static int wm831x_irq_set_type(unsigned int irq, unsigned int type)
+static int wm831x_irq_set_type(struct irq_data *data, unsigned int type)
{
- struct wm831x *wm831x = get_irq_chip_data(irq);
- int val;
+ struct wm831x *wm831x = irq_data_get_irq_chip_data(data);
+ int val, irq;
- irq = irq - wm831x->irq_base;
+ irq = data->irq - wm831x->irq_base;
if (irq < WM831X_IRQ_GPIO_1 || irq > WM831X_IRQ_GPIO_11) {
/* Ignore internal-only IRQs */
@@ -421,12 +423,12 @@ static int wm831x_irq_set_type(unsigned int irq, unsigned int type)
}
static struct irq_chip wm831x_irq_chip = {
- .name = "wm831x",
- .bus_lock = wm831x_irq_lock,
- .bus_sync_unlock = wm831x_irq_sync_unlock,
- .mask = wm831x_irq_mask,
- .unmask = wm831x_irq_unmask,
- .set_type = wm831x_irq_set_type,
+ .name = "wm831x",
+ .irq_bus_lock = wm831x_irq_lock,
+ .irq_bus_sync_unlock = wm831x_irq_sync_unlock,
+ .irq_mask = wm831x_irq_mask,
+ .irq_unmask = wm831x_irq_unmask,
+ .irq_set_type = wm831x_irq_set_type,
};
/* The processing of the primary interrupt occurs in a thread so that
@@ -515,6 +517,17 @@ int wm831x_irq_init(struct wm831x *wm831x, int irq)
return 0;
}
+ /* Try to flag /IRQ as a wake source; there are a number of
+ * unconditional wake sources in the PMIC so this isn't
+ * conditional but we don't actually care *too* much if it
+ * fails.
+ */
+ ret = enable_irq_wake(irq);
+ if (ret != 0) {
+ dev_warn(wm831x->dev, "Can't enable IRQ as wake source: %d\n",
+ ret);
+ }
+
wm831x->irq = irq;
wm831x->irq_base = pdata->irq_base;
diff --git a/drivers/mfd/wm831x-spi.c b/drivers/mfd/wm831x-spi.c
index 2789b15..0a8f772 100644
--- a/drivers/mfd/wm831x-spi.c
+++ b/drivers/mfd/wm831x-spi.c
@@ -81,6 +81,8 @@ static int __devinit wm831x_spi_probe(struct spi_device *spi)
type = WM8321;
else if (strcmp(spi->modalias, "wm8325") == 0)
type = WM8325;
+ else if (strcmp(spi->modalias, "wm8326") == 0)
+ type = WM8326;
else {
dev_err(&spi->dev, "Unknown device type\n");
return -EINVAL;
@@ -184,6 +186,17 @@ static struct spi_driver wm8325_spi_driver = {
.suspend = wm831x_spi_suspend,
};
+static struct spi_driver wm8326_spi_driver = {
+ .driver = {
+ .name = "wm8326",
+ .bus = &spi_bus_type,
+ .owner = THIS_MODULE,
+ },
+ .probe = wm831x_spi_probe,
+ .remove = __devexit_p(wm831x_spi_remove),
+ .suspend = wm831x_spi_suspend,
+};
+
static int __init wm831x_spi_init(void)
{
int ret;
@@ -212,12 +225,17 @@ static int __init wm831x_spi_init(void)
if (ret != 0)
pr_err("Failed to register WM8325 SPI driver: %d\n", ret);
+ ret = spi_register_driver(&wm8326_spi_driver);
+ if (ret != 0)
+ pr_err("Failed to register WM8326 SPI driver: %d\n", ret);
+
return 0;
}
subsys_initcall(wm831x_spi_init);
static void __exit wm831x_spi_exit(void)
{
+ spi_unregister_driver(&wm8326_spi_driver);
spi_unregister_driver(&wm8325_spi_driver);
spi_unregister_driver(&wm8321_spi_driver);
spi_unregister_driver(&wm8320_spi_driver);
diff --git a/drivers/mfd/wm8350-irq.c b/drivers/mfd/wm8350-irq.c
index f56c9ad..5839966 100644
--- a/drivers/mfd/wm8350-irq.c
+++ b/drivers/mfd/wm8350-irq.c
@@ -417,16 +417,16 @@ static irqreturn_t wm8350_irq(int irq, void *irq_data)
return IRQ_HANDLED;
}
-static void wm8350_irq_lock(unsigned int irq)
+static void wm8350_irq_lock(struct irq_data *data)
{
- struct wm8350 *wm8350 = get_irq_chip_data(irq);
+ struct wm8350 *wm8350 = irq_data_get_irq_chip_data(data);
mutex_lock(&wm8350->irq_lock);
}
-static void wm8350_irq_sync_unlock(unsigned int irq)
+static void wm8350_irq_sync_unlock(struct irq_data *data)
{
- struct wm8350 *wm8350 = get_irq_chip_data(irq);
+ struct wm8350 *wm8350 = irq_data_get_irq_chip_data(data);
int i;
for (i = 0; i < ARRAY_SIZE(wm8350->irq_masks); i++) {
@@ -442,28 +442,30 @@ static void wm8350_irq_sync_unlock(unsigned int irq)
mutex_unlock(&wm8350->irq_lock);
}
-static void wm8350_irq_enable(unsigned int irq)
+static void wm8350_irq_enable(struct irq_data *data)
{
- struct wm8350 *wm8350 = get_irq_chip_data(irq);
- struct wm8350_irq_data *irq_data = irq_to_wm8350_irq(wm8350, irq);
+ struct wm8350 *wm8350 = irq_data_get_irq_chip_data(data);
+ struct wm8350_irq_data *irq_data = irq_to_wm8350_irq(wm8350,
+ data->irq);
wm8350->irq_masks[irq_data->reg] &= ~irq_data->mask;
}
-static void wm8350_irq_disable(unsigned int irq)
+static void wm8350_irq_disable(struct irq_data *data)
{
- struct wm8350 *wm8350 = get_irq_chip_data(irq);
- struct wm8350_irq_data *irq_data = irq_to_wm8350_irq(wm8350, irq);
+ struct wm8350 *wm8350 = irq_data_get_irq_chip_data(data);
+ struct wm8350_irq_data *irq_data = irq_to_wm8350_irq(wm8350,
+ data->irq);
wm8350->irq_masks[irq_data->reg] |= irq_data->mask;
}
static struct irq_chip wm8350_irq_chip = {
- .name = "wm8350",
- .bus_lock = wm8350_irq_lock,
- .bus_sync_unlock = wm8350_irq_sync_unlock,
- .disable = wm8350_irq_disable,
- .enable = wm8350_irq_enable,
+ .name = "wm8350",
+ .irq_bus_lock = wm8350_irq_lock,
+ .irq_bus_sync_unlock = wm8350_irq_sync_unlock,
+ .irq_disable = wm8350_irq_disable,
+ .irq_enable = wm8350_irq_enable,
};
int wm8350_irq_init(struct wm8350 *wm8350, int irq,
diff --git a/drivers/mfd/wm8994-core.c b/drivers/mfd/wm8994-core.c
index 8d221ba..41233c7 100644
--- a/drivers/mfd/wm8994-core.c
+++ b/drivers/mfd/wm8994-core.c
@@ -18,6 +18,7 @@
#include <linux/i2c.h>
#include <linux/delay.h>
#include <linux/mfd/core.h>
+#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
#include <linux/regulator/machine.h>
@@ -169,8 +170,16 @@ out:
EXPORT_SYMBOL_GPL(wm8994_set_bits);
static struct mfd_cell wm8994_regulator_devs[] = {
- { .name = "wm8994-ldo", .id = 1 },
- { .name = "wm8994-ldo", .id = 2 },
+ {
+ .name = "wm8994-ldo",
+ .id = 1,
+ .pm_runtime_no_callbacks = true,
+ },
+ {
+ .name = "wm8994-ldo",
+ .id = 2,
+ .pm_runtime_no_callbacks = true,
+ },
};
static struct resource wm8994_codec_resources[] = {
@@ -200,6 +209,7 @@ static struct mfd_cell wm8994_devs[] = {
.name = "wm8994-gpio",
.num_resources = ARRAY_SIZE(wm8994_gpio_resources),
.resources = wm8994_gpio_resources,
+ .pm_runtime_no_callbacks = true,
},
};
@@ -231,7 +241,7 @@ static const char *wm8958_main_supplies[] = {
};
#ifdef CONFIG_PM
-static int wm8994_device_suspend(struct device *dev)
+static int wm8994_suspend(struct device *dev)
{
struct wm8994 *wm8994 = dev_get_drvdata(dev);
int ret;
@@ -261,7 +271,7 @@ static int wm8994_device_suspend(struct device *dev)
return 0;
}
-static int wm8994_device_resume(struct device *dev)
+static int wm8994_resume(struct device *dev)
{
struct wm8994 *wm8994 = dev_get_drvdata(dev);
int ret;
@@ -471,6 +481,9 @@ static int wm8994_device_init(struct wm8994 *wm8994, int irq)
goto err_irq;
}
+ pm_runtime_enable(wm8994->dev);
+ pm_runtime_resume(wm8994->dev);
+
return 0;
err_irq:
@@ -490,6 +503,7 @@ err:
static void wm8994_device_exit(struct wm8994 *wm8994)
{
+ pm_runtime_disable(wm8994->dev);
mfd_remove_devices(wm8994->dev);
wm8994_irq_exit(wm8994);
regulator_bulk_disable(wm8994->num_supplies,
@@ -573,21 +587,6 @@ static int wm8994_i2c_remove(struct i2c_client *i2c)
return 0;
}
-#ifdef CONFIG_PM
-static int wm8994_i2c_suspend(struct i2c_client *i2c, pm_message_t state)
-{
- return wm8994_device_suspend(&i2c->dev);
-}
-
-static int wm8994_i2c_resume(struct i2c_client *i2c)
-{
- return wm8994_device_resume(&i2c->dev);
-}
-#else
-#define wm8994_i2c_suspend NULL
-#define wm8994_i2c_resume NULL
-#endif
-
static const struct i2c_device_id wm8994_i2c_id[] = {
{ "wm8994", WM8994 },
{ "wm8958", WM8958 },
@@ -595,15 +594,16 @@ static const struct i2c_device_id wm8994_i2c_id[] = {
};
MODULE_DEVICE_TABLE(i2c, wm8994_i2c_id);
+UNIVERSAL_DEV_PM_OPS(wm8994_pm_ops, wm8994_suspend, wm8994_resume, NULL);
+
static struct i2c_driver wm8994_i2c_driver = {
.driver = {
- .name = "wm8994",
- .owner = THIS_MODULE,
+ .name = "wm8994",
+ .owner = THIS_MODULE,
+ .pm = &wm8994_pm_ops,
},
.probe = wm8994_i2c_probe,
.remove = wm8994_i2c_remove,
- .suspend = wm8994_i2c_suspend,
- .resume = wm8994_i2c_resume,
.id_table = wm8994_i2c_id,
};
diff --git a/drivers/mfd/wm8994-irq.c b/drivers/mfd/wm8994-irq.c
index 8400eb1..29e8faf 100644
--- a/drivers/mfd/wm8994-irq.c
+++ b/drivers/mfd/wm8994-irq.c
@@ -156,16 +156,16 @@ static inline struct wm8994_irq_data *irq_to_wm8994_irq(struct wm8994 *wm8994,
return &wm8994_irqs[irq - wm8994->irq_base];
}
-static void wm8994_irq_lock(unsigned int irq)
+static void wm8994_irq_lock(struct irq_data *data)
{
- struct wm8994 *wm8994 = get_irq_chip_data(irq);
+ struct wm8994 *wm8994 = irq_data_get_irq_chip_data(data);
mutex_lock(&wm8994->irq_lock);
}
-static void wm8994_irq_sync_unlock(unsigned int irq)
+static void wm8994_irq_sync_unlock(struct irq_data *data)
{
- struct wm8994 *wm8994 = get_irq_chip_data(irq);
+ struct wm8994 *wm8994 = irq_data_get_irq_chip_data(data);
int i;
for (i = 0; i < ARRAY_SIZE(wm8994->irq_masks_cur); i++) {
@@ -182,28 +182,30 @@ static void wm8994_irq_sync_unlock(unsigned int irq)
mutex_unlock(&wm8994->irq_lock);
}
-static void wm8994_irq_unmask(unsigned int irq)
+static void wm8994_irq_unmask(struct irq_data *data)
{
- struct wm8994 *wm8994 = get_irq_chip_data(irq);
- struct wm8994_irq_data *irq_data = irq_to_wm8994_irq(wm8994, irq);
+ struct wm8994 *wm8994 = irq_data_get_irq_chip_data(data);
+ struct wm8994_irq_data *irq_data = irq_to_wm8994_irq(wm8994,
+ data->irq);
wm8994->irq_masks_cur[irq_data->reg - 1] &= ~irq_data->mask;
}
-static void wm8994_irq_mask(unsigned int irq)
+static void wm8994_irq_mask(struct irq_data *data)
{
- struct wm8994 *wm8994 = get_irq_chip_data(irq);
- struct wm8994_irq_data *irq_data = irq_to_wm8994_irq(wm8994, irq);
+ struct wm8994 *wm8994 = irq_data_get_irq_chip_data(data);
+ struct wm8994_irq_data *irq_data = irq_to_wm8994_irq(wm8994,
+ data->irq);
wm8994->irq_masks_cur[irq_data->reg - 1] |= irq_data->mask;
}
static struct irq_chip wm8994_irq_chip = {
- .name = "wm8994",
- .bus_lock = wm8994_irq_lock,
- .bus_sync_unlock = wm8994_irq_sync_unlock,
- .mask = wm8994_irq_mask,
- .unmask = wm8994_irq_unmask,
+ .name = "wm8994",
+ .irq_bus_lock = wm8994_irq_lock,
+ .irq_bus_sync_unlock = wm8994_irq_sync_unlock,
+ .irq_mask = wm8994_irq_mask,
+ .irq_unmask = wm8994_irq_unmask,
};
/* The processing of the primary interrupt occurs in a thread so that
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 1e1a4be..cc8e49d 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -64,7 +64,7 @@ config ATMEL_PWM
config AB8500_PWM
bool "AB8500 PWM support"
- depends on AB8500_CORE
+ depends on AB8500_CORE && ARCH_U8500
select HAVE_PWM
help
This driver exports functions to enable/disble/config/free Pulse
diff --git a/drivers/misc/cs5535-mfgpt.c b/drivers/misc/cs5535-mfgpt.c
index 6f62180..d02d302 100644
--- a/drivers/misc/cs5535-mfgpt.c
+++ b/drivers/misc/cs5535-mfgpt.c
@@ -16,12 +16,11 @@
#include <linux/spinlock.h>
#include <linux/interrupt.h>
#include <linux/module.h>
-#include <linux/pci.h>
+#include <linux/platform_device.h>
#include <linux/cs5535.h>
#include <linux/slab.h>
#define DRV_NAME "cs5535-mfgpt"
-#define MFGPT_BAR 2
static int mfgpt_reset_timers;
module_param_named(mfgptfix, mfgpt_reset_timers, int, 0644);
@@ -37,7 +36,7 @@ static struct cs5535_mfgpt_chip {
DECLARE_BITMAP(avail, MFGPT_MAX_TIMERS);
resource_size_t base;
- struct pci_dev *pdev;
+ struct platform_device *pdev;
spinlock_t lock;
int initialized;
} cs5535_mfgpt_chip;
@@ -290,10 +289,10 @@ static int __init scan_timers(struct cs5535_mfgpt_chip *mfgpt)
return timers;
}
-static int __init cs5535_mfgpt_probe(struct pci_dev *pdev,
- const struct pci_device_id *pci_id)
+static int __devinit cs5535_mfgpt_probe(struct platform_device *pdev)
{
- int err, t;
+ struct resource *res;
+ int err = -EIO, t;
/* There are two ways to get the MFGPT base address; one is by
* fetching it from MSR_LBAR_MFGPT, the other is by reading the
@@ -302,29 +301,27 @@ static int __init cs5535_mfgpt_probe(struct pci_dev *pdev,
* it turns out to be unreliable in the face of crappy BIOSes, we
* can always go back to using MSRs.. */
- err = pci_enable_device_io(pdev);
- if (err) {
- dev_err(&pdev->dev, "can't enable device IO\n");
+ res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "can't fetch device resource info\n");
goto done;
}
- err = pci_request_region(pdev, MFGPT_BAR, DRV_NAME);
- if (err) {
- dev_err(&pdev->dev, "can't alloc PCI BAR #%d\n", MFGPT_BAR);
+ if (!request_region(res->start, resource_size(res), pdev->name)) {
+ dev_err(&pdev->dev, "can't request region\n");
goto done;
}
/* set up the driver-specific struct */
- cs5535_mfgpt_chip.base = pci_resource_start(pdev, MFGPT_BAR);
+ cs5535_mfgpt_chip.base = res->start;
cs5535_mfgpt_chip.pdev = pdev;
spin_lock_init(&cs5535_mfgpt_chip.lock);
- dev_info(&pdev->dev, "allocated PCI BAR #%d: base 0x%llx\n", MFGPT_BAR,
- (unsigned long long) cs5535_mfgpt_chip.base);
+ dev_info(&pdev->dev, "reserved resource region %pR\n", res);
/* detect the available timers */
t = scan_timers(&cs5535_mfgpt_chip);
- dev_info(&pdev->dev, DRV_NAME ": %d MFGPT timers available\n", t);
+ dev_info(&pdev->dev, "%d MFGPT timers available\n", t);
cs5535_mfgpt_chip.initialized = 1;
return 0;
@@ -332,47 +329,18 @@ done:
return err;
}
-static struct pci_device_id cs5535_mfgpt_pci_tbl[] = {
- { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_CS5535_ISA) },
- { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_ISA) },
- { 0, },
+static struct platform_driver cs5535_mfgpt_drv = {
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ },
+ .probe = cs5535_mfgpt_probe,
};
-MODULE_DEVICE_TABLE(pci, cs5535_mfgpt_pci_tbl);
-/*
- * Just like with the cs5535-gpio driver, we can't use the standard PCI driver
- * registration stuff. It only allows only one driver to bind to each PCI
- * device, and we want the GPIO and MFGPT drivers to be able to share a PCI
- * device. Instead, we manually scan for the PCI device, request a single
- * region, and keep track of the devices that we're using.
- */
-
-static int __init cs5535_mfgpt_scan_pci(void)
-{
- struct pci_dev *pdev;
- int err = -ENODEV;
- int i;
-
- for (i = 0; i < ARRAY_SIZE(cs5535_mfgpt_pci_tbl); i++) {
- pdev = pci_get_device(cs5535_mfgpt_pci_tbl[i].vendor,
- cs5535_mfgpt_pci_tbl[i].device, NULL);
- if (pdev) {
- err = cs5535_mfgpt_probe(pdev,
- &cs5535_mfgpt_pci_tbl[i]);
- if (err)
- pci_dev_put(pdev);
-
- /* we only support a single CS5535/6 southbridge */
- break;
- }
- }
-
- return err;
-}
static int __init cs5535_mfgpt_init(void)
{
- return cs5535_mfgpt_scan_pci();
+ return platform_driver_register(&cs5535_mfgpt_drv);
}
module_init(cs5535_mfgpt_init);
@@ -380,3 +348,4 @@ module_init(cs5535_mfgpt_init);
MODULE_AUTHOR("Andres Salomon <dilinger@queued.net>");
MODULE_DESCRIPTION("CS5535/CS5536 MFGPT timer driver");
MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c
index 5decfd0..153ab97 100644
--- a/drivers/mmc/host/msm_sdcc.c
+++ b/drivers/mmc/host/msm_sdcc.c
@@ -383,14 +383,30 @@ static int msmsdcc_config_dma(struct msmsdcc_host *host, struct mmc_data *data)
host->curr.user_pages = 0;
box = &nc->cmd[0];
- for (i = 0; i < host->dma.num_ents; i++) {
- box->cmd = CMD_MODE_BOX;
- /* Initialize sg dma address */
- sg->dma_address = page_to_dma(mmc_dev(host->mmc), sg_page(sg))
- + sg->offset;
+ /* location of command block must be 64 bit aligned */
+ BUG_ON(host->dma.cmd_busaddr & 0x07);
- if (i == (host->dma.num_ents - 1))
+ nc->cmdptr = (host->dma.cmd_busaddr >> 3) | CMD_PTR_LP;
+ host->dma.hdr.cmdptr = DMOV_CMD_PTR_LIST |
+ DMOV_CMD_ADDR(host->dma.cmdptr_busaddr);
+ host->dma.hdr.complete_func = msmsdcc_dma_complete_func;
+
+ n = dma_map_sg(mmc_dev(host->mmc), host->dma.sg,
+ host->dma.num_ents, host->dma.dir);
+ if (n == 0) {
+ printk(KERN_ERR "%s: Unable to map in all sg elements\n",
+ mmc_hostname(host->mmc));
+ host->dma.sg = NULL;
+ host->dma.num_ents = 0;
+ return -ENOMEM;
+ }
+
+ for_each_sg(host->dma.sg, sg, n, i) {
+
+ box->cmd = CMD_MODE_BOX;
+
+ if (i == n - 1)
box->cmd |= CMD_LC;
rows = (sg_dma_len(sg) % MCI_FIFOSIZE) ?
(sg_dma_len(sg) / MCI_FIFOSIZE) + 1 :
@@ -418,27 +434,6 @@ static int msmsdcc_config_dma(struct msmsdcc_host *host, struct mmc_data *data)
box->cmd |= CMD_DST_CRCI(crci);
}
box++;
- sg++;
- }
-
- /* location of command block must be 64 bit aligned */
- BUG_ON(host->dma.cmd_busaddr & 0x07);
-
- nc->cmdptr = (host->dma.cmd_busaddr >> 3) | CMD_PTR_LP;
- host->dma.hdr.cmdptr = DMOV_CMD_PTR_LIST |
- DMOV_CMD_ADDR(host->dma.cmdptr_busaddr);
- host->dma.hdr.complete_func = msmsdcc_dma_complete_func;
-
- n = dma_map_sg(mmc_dev(host->mmc), host->dma.sg,
- host->dma.num_ents, host->dma.dir);
-/* dsb inside dma_map_sg will write nc out to mem as well */
-
- if (n != host->dma.num_ents) {
- printk(KERN_ERR "%s: Unable to map in all sg elements\n",
- mmc_hostname(host->mmc));
- host->dma.sg = NULL;
- host->dma.num_ents = 0;
- return -ENOMEM;
}
return 0;
@@ -1331,9 +1326,6 @@ msmsdcc_probe(struct platform_device *pdev)
if (host->timer.function)
pr_info("%s: Polling status mode enabled\n", mmc_hostname(mmc));
-#if BUSCLK_PWRSAVE
- msmsdcc_disable_clocks(host, 1);
-#endif
return 0;
cmd_irq_free:
free_irq(cmd_irqres->start, host);
diff --git a/drivers/mmc/host/sdhci-of-core.c b/drivers/mmc/host/sdhci-of-core.c
index fa19d84..dd84124f 100644
--- a/drivers/mmc/host/sdhci-of-core.c
+++ b/drivers/mmc/host/sdhci-of-core.c
@@ -13,6 +13,7 @@
* your option) any later version.
*/
+#include <linux/err.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/io.h>
@@ -20,8 +21,12 @@
#include <linux/delay.h>
#include <linux/of.h>
#include <linux/of_platform.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
#include <linux/mmc/host.h>
+#ifdef CONFIG_PPC
#include <asm/machdep.h>
+#endif
#include "sdhci-of.h"
#include "sdhci.h"
@@ -112,7 +117,11 @@ static bool __devinit sdhci_of_wp_inverted(struct device_node *np)
return true;
/* Old device trees don't have the wp-inverted property. */
+#ifdef CONFIG_PPC
return machine_is(mpc837x_rdb) || machine_is(mpc837x_mds);
+#else
+ return false;
+#endif
}
static int __devinit sdhci_of_probe(struct platform_device *ofdev,
diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig
index b1f7689..7741470 100644
--- a/drivers/mtd/Kconfig
+++ b/drivers/mtd/Kconfig
@@ -53,9 +53,10 @@ config MTD_PARTITIONS
devices. Partitioning on NFTL 'devices' is a different - that's the
'normal' form of partitioning used on a block device.
+if MTD_PARTITIONS
+
config MTD_REDBOOT_PARTS
tristate "RedBoot partition table parsing"
- depends on MTD_PARTITIONS
---help---
RedBoot is a ROM monitor and bootloader which deals with multiple
'images' in flash devices by putting a table one of the erase
@@ -72,9 +73,10 @@ config MTD_REDBOOT_PARTS
SA1100 map driver (CONFIG_MTD_SA1100) has an option for this, for
example.
+if MTD_REDBOOT_PARTS
+
config MTD_REDBOOT_DIRECTORY_BLOCK
int "Location of RedBoot partition table"
- depends on MTD_REDBOOT_PARTS
default "-1"
---help---
This option is the Linux counterpart to the
@@ -91,18 +93,18 @@ config MTD_REDBOOT_DIRECTORY_BLOCK
config MTD_REDBOOT_PARTS_UNALLOCATED
bool "Include unallocated flash regions"
- depends on MTD_REDBOOT_PARTS
help
If you need to register each unallocated flash region as a MTD
'partition', enable this option.
config MTD_REDBOOT_PARTS_READONLY
bool "Force read-only for RedBoot system images"
- depends on MTD_REDBOOT_PARTS
help
If you need to force read-only for 'RedBoot', 'RedBoot Config' and
'FIS directory' images, enable this option.
+endif # MTD_REDBOOT_PARTS
+
config MTD_CMDLINE_PARTS
bool "Command line partition table parsing"
depends on MTD_PARTITIONS = "y" && MTD = "y"
@@ -142,7 +144,7 @@ config MTD_CMDLINE_PARTS
config MTD_AFS_PARTS
tristate "ARM Firmware Suite partition parsing"
- depends on ARM && MTD_PARTITIONS
+ depends on ARM
---help---
The ARM Firmware Suite allows the user to divide flash devices into
multiple 'images'. Each such image has a header containing its name
@@ -158,8 +160,8 @@ config MTD_AFS_PARTS
example.
config MTD_OF_PARTS
- tristate "Flash partition map based on OF description"
- depends on OF && MTD_PARTITIONS
+ def_bool y
+ depends on OF
help
This provides a partition parsing function which derives
the partition map from the children of the flash node,
@@ -167,10 +169,11 @@ config MTD_OF_PARTS
config MTD_AR7_PARTS
tristate "TI AR7 partitioning support"
- depends on MTD_PARTITIONS
---help---
TI AR7 partitioning support
+endif # MTD_PARTITIONS
+
comment "User Modules And Translation Layers"
config MTD_CHAR
diff --git a/drivers/mtd/Makefile b/drivers/mtd/Makefile
index 760abc5..d4e7f25 100644
--- a/drivers/mtd/Makefile
+++ b/drivers/mtd/Makefile
@@ -6,13 +6,13 @@
obj-$(CONFIG_MTD) += mtd.o
mtd-y := mtdcore.o mtdsuper.o
mtd-$(CONFIG_MTD_PARTITIONS) += mtdpart.o
+mtd-$(CONFIG_MTD_OF_PARTS) += ofpart.o
obj-$(CONFIG_MTD_CONCAT) += mtdconcat.o
obj-$(CONFIG_MTD_REDBOOT_PARTS) += redboot.o
obj-$(CONFIG_MTD_CMDLINE_PARTS) += cmdlinepart.o
obj-$(CONFIG_MTD_AFS_PARTS) += afs.o
obj-$(CONFIG_MTD_AR7_PARTS) += ar7part.o
-obj-$(CONFIG_MTD_OF_PARTS) += ofpart.o
# 'Users' - code which presents functionality to userspace.
obj-$(CONFIG_MTD_CHAR) += mtdchar.o
diff --git a/drivers/mtd/chips/cfi_cmdset_0001.c b/drivers/mtd/chips/cfi_cmdset_0001.c
index ad9268b..a8c3e1c 100644
--- a/drivers/mtd/chips/cfi_cmdset_0001.c
+++ b/drivers/mtd/chips/cfi_cmdset_0001.c
@@ -162,7 +162,7 @@ static void cfi_tell_features(struct cfi_pri_intelext *extp)
#endif
/* Atmel chips don't use the same PRI format as Intel chips */
-static void fixup_convert_atmel_pri(struct mtd_info *mtd, void *param)
+static void fixup_convert_atmel_pri(struct mtd_info *mtd)
{
struct map_info *map = mtd->priv;
struct cfi_private *cfi = map->fldrv_priv;
@@ -202,7 +202,7 @@ static void fixup_convert_atmel_pri(struct mtd_info *mtd, void *param)
cfi->cfiq->BufWriteTimeoutMax = 0;
}
-static void fixup_at49bv640dx_lock(struct mtd_info *mtd, void *param)
+static void fixup_at49bv640dx_lock(struct mtd_info *mtd)
{
struct map_info *map = mtd->priv;
struct cfi_private *cfi = map->fldrv_priv;
@@ -214,7 +214,7 @@ static void fixup_at49bv640dx_lock(struct mtd_info *mtd, void *param)
#ifdef CMDSET0001_DISABLE_ERASE_SUSPEND_ON_WRITE
/* Some Intel Strata Flash prior to FPO revision C has bugs in this area */
-static void fixup_intel_strataflash(struct mtd_info *mtd, void* param)
+static void fixup_intel_strataflash(struct mtd_info *mtd)
{
struct map_info *map = mtd->priv;
struct cfi_private *cfi = map->fldrv_priv;
@@ -227,7 +227,7 @@ static void fixup_intel_strataflash(struct mtd_info *mtd, void* param)
#endif
#ifdef CMDSET0001_DISABLE_WRITE_SUSPEND
-static void fixup_no_write_suspend(struct mtd_info *mtd, void* param)
+static void fixup_no_write_suspend(struct mtd_info *mtd)
{
struct map_info *map = mtd->priv;
struct cfi_private *cfi = map->fldrv_priv;
@@ -240,7 +240,7 @@ static void fixup_no_write_suspend(struct mtd_info *mtd, void* param)
}
#endif
-static void fixup_st_m28w320ct(struct mtd_info *mtd, void* param)
+static void fixup_st_m28w320ct(struct mtd_info *mtd)
{
struct map_info *map = mtd->priv;
struct cfi_private *cfi = map->fldrv_priv;
@@ -249,7 +249,7 @@ static void fixup_st_m28w320ct(struct mtd_info *mtd, void* param)
cfi->cfiq->BufWriteTimeoutMax = 0; /* Not supported */
}
-static void fixup_st_m28w320cb(struct mtd_info *mtd, void* param)
+static void fixup_st_m28w320cb(struct mtd_info *mtd)
{
struct map_info *map = mtd->priv;
struct cfi_private *cfi = map->fldrv_priv;
@@ -259,7 +259,7 @@ static void fixup_st_m28w320cb(struct mtd_info *mtd, void* param)
(cfi->cfiq->EraseRegionInfo[1] & 0xffff0000) | 0x3e;
};
-static void fixup_use_point(struct mtd_info *mtd, void *param)
+static void fixup_use_point(struct mtd_info *mtd)
{
struct map_info *map = mtd->priv;
if (!mtd->point && map_is_linear(map)) {
@@ -268,7 +268,7 @@ static void fixup_use_point(struct mtd_info *mtd, void *param)
}
}
-static void fixup_use_write_buffers(struct mtd_info *mtd, void *param)
+static void fixup_use_write_buffers(struct mtd_info *mtd)
{
struct map_info *map = mtd->priv;
struct cfi_private *cfi = map->fldrv_priv;
@@ -282,7 +282,7 @@ static void fixup_use_write_buffers(struct mtd_info *mtd, void *param)
/*
* Some chips power-up with all sectors locked by default.
*/
-static void fixup_unlock_powerup_lock(struct mtd_info *mtd, void *param)
+static void fixup_unlock_powerup_lock(struct mtd_info *mtd)
{
struct map_info *map = mtd->priv;
struct cfi_private *cfi = map->fldrv_priv;
@@ -295,31 +295,31 @@ static void fixup_unlock_powerup_lock(struct mtd_info *mtd, void *param)
}
static struct cfi_fixup cfi_fixup_table[] = {
- { CFI_MFR_ATMEL, CFI_ID_ANY, fixup_convert_atmel_pri, NULL },
- { CFI_MFR_ATMEL, AT49BV640D, fixup_at49bv640dx_lock, NULL },
- { CFI_MFR_ATMEL, AT49BV640DT, fixup_at49bv640dx_lock, NULL },
+ { CFI_MFR_ATMEL, CFI_ID_ANY, fixup_convert_atmel_pri },
+ { CFI_MFR_ATMEL, AT49BV640D, fixup_at49bv640dx_lock },
+ { CFI_MFR_ATMEL, AT49BV640DT, fixup_at49bv640dx_lock },
#ifdef CMDSET0001_DISABLE_ERASE_SUSPEND_ON_WRITE
- { CFI_MFR_ANY, CFI_ID_ANY, fixup_intel_strataflash, NULL },
+ { CFI_MFR_ANY, CFI_ID_ANY, fixup_intel_strataflash },
#endif
#ifdef CMDSET0001_DISABLE_WRITE_SUSPEND
- { CFI_MFR_ANY, CFI_ID_ANY, fixup_no_write_suspend, NULL },
+ { CFI_MFR_ANY, CFI_ID_ANY, fixup_no_write_suspend },
#endif
#if !FORCE_WORD_WRITE
- { CFI_MFR_ANY, CFI_ID_ANY, fixup_use_write_buffers, NULL },
+ { CFI_MFR_ANY, CFI_ID_ANY, fixup_use_write_buffers },
#endif
- { CFI_MFR_ST, 0x00ba, /* M28W320CT */ fixup_st_m28w320ct, NULL },
- { CFI_MFR_ST, 0x00bb, /* M28W320CB */ fixup_st_m28w320cb, NULL },
- { CFI_MFR_INTEL, CFI_ID_ANY, fixup_unlock_powerup_lock, NULL, },
- { 0, 0, NULL, NULL }
+ { CFI_MFR_ST, 0x00ba, /* M28W320CT */ fixup_st_m28w320ct },
+ { CFI_MFR_ST, 0x00bb, /* M28W320CB */ fixup_st_m28w320cb },
+ { CFI_MFR_INTEL, CFI_ID_ANY, fixup_unlock_powerup_lock },
+ { 0, 0, NULL }
};
static struct cfi_fixup jedec_fixup_table[] = {
- { CFI_MFR_INTEL, I82802AB, fixup_use_fwh_lock, NULL, },
- { CFI_MFR_INTEL, I82802AC, fixup_use_fwh_lock, NULL, },
- { CFI_MFR_ST, M50LPW080, fixup_use_fwh_lock, NULL, },
- { CFI_MFR_ST, M50FLW080A, fixup_use_fwh_lock, NULL, },
- { CFI_MFR_ST, M50FLW080B, fixup_use_fwh_lock, NULL, },
- { 0, 0, NULL, NULL }
+ { CFI_MFR_INTEL, I82802AB, fixup_use_fwh_lock },
+ { CFI_MFR_INTEL, I82802AC, fixup_use_fwh_lock },
+ { CFI_MFR_ST, M50LPW080, fixup_use_fwh_lock },
+ { CFI_MFR_ST, M50FLW080A, fixup_use_fwh_lock },
+ { CFI_MFR_ST, M50FLW080B, fixup_use_fwh_lock },
+ { 0, 0, NULL }
};
static struct cfi_fixup fixup_table[] = {
/* The CFI vendor ids and the JEDEC vendor IDs appear
@@ -327,8 +327,8 @@ static struct cfi_fixup fixup_table[] = {
* well. This table is to pick all cases where
* we know that is the case.
*/
- { CFI_MFR_ANY, CFI_ID_ANY, fixup_use_point, NULL },
- { 0, 0, NULL, NULL }
+ { CFI_MFR_ANY, CFI_ID_ANY, fixup_use_point },
+ { 0, 0, NULL }
};
static void cfi_fixup_major_minor(struct cfi_private *cfi,
@@ -455,6 +455,7 @@ struct mtd_info *cfi_cmdset_0001(struct map_info *map, int primary)
mtd->flags = MTD_CAP_NORFLASH;
mtd->name = map->name;
mtd->writesize = 1;
+ mtd->writebufsize = 1 << cfi->cfiq->MaxBufWriteSize;
mtd->reboot_notifier.notifier_call = cfi_intelext_reboot;
diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c
index 3b8e32d..f072fcf 100644
--- a/drivers/mtd/chips/cfi_cmdset_0002.c
+++ b/drivers/mtd/chips/cfi_cmdset_0002.c
@@ -134,7 +134,7 @@ static void cfi_tell_features(struct cfi_pri_amdstd *extp)
#ifdef AMD_BOOTLOC_BUG
/* Wheee. Bring me the head of someone at AMD. */
-static void fixup_amd_bootblock(struct mtd_info *mtd, void* param)
+static void fixup_amd_bootblock(struct mtd_info *mtd)
{
struct map_info *map = mtd->priv;
struct cfi_private *cfi = map->fldrv_priv;
@@ -186,7 +186,7 @@ static void fixup_amd_bootblock(struct mtd_info *mtd, void* param)
}
#endif
-static void fixup_use_write_buffers(struct mtd_info *mtd, void *param)
+static void fixup_use_write_buffers(struct mtd_info *mtd)
{
struct map_info *map = mtd->priv;
struct cfi_private *cfi = map->fldrv_priv;
@@ -197,7 +197,7 @@ static void fixup_use_write_buffers(struct mtd_info *mtd, void *param)
}
/* Atmel chips don't use the same PRI format as AMD chips */
-static void fixup_convert_atmel_pri(struct mtd_info *mtd, void *param)
+static void fixup_convert_atmel_pri(struct mtd_info *mtd)
{
struct map_info *map = mtd->priv;
struct cfi_private *cfi = map->fldrv_priv;
@@ -228,14 +228,14 @@ static void fixup_convert_atmel_pri(struct mtd_info *mtd, void *param)
cfi->cfiq->BufWriteTimeoutMax = 0;
}
-static void fixup_use_secsi(struct mtd_info *mtd, void *param)
+static void fixup_use_secsi(struct mtd_info *mtd)
{
/* Setup for chips with a secsi area */
mtd->read_user_prot_reg = cfi_amdstd_secsi_read;
mtd->read_fact_prot_reg = cfi_amdstd_secsi_read;
}
-static void fixup_use_erase_chip(struct mtd_info *mtd, void *param)
+static void fixup_use_erase_chip(struct mtd_info *mtd)
{
struct map_info *map = mtd->priv;
struct cfi_private *cfi = map->fldrv_priv;
@@ -250,7 +250,7 @@ static void fixup_use_erase_chip(struct mtd_info *mtd, void *param)
* Some Atmel chips (e.g. the AT49BV6416) power-up with all sectors
* locked by default.
*/
-static void fixup_use_atmel_lock(struct mtd_info *mtd, void *param)
+static void fixup_use_atmel_lock(struct mtd_info *mtd)
{
mtd->lock = cfi_atmel_lock;
mtd->unlock = cfi_atmel_unlock;
@@ -271,7 +271,7 @@ static void fixup_old_sst_eraseregion(struct mtd_info *mtd)
cfi->cfiq->NumEraseRegions = 1;
}
-static void fixup_sst39vf(struct mtd_info *mtd, void *param)
+static void fixup_sst39vf(struct mtd_info *mtd)
{
struct map_info *map = mtd->priv;
struct cfi_private *cfi = map->fldrv_priv;
@@ -282,7 +282,7 @@ static void fixup_sst39vf(struct mtd_info *mtd, void *param)
cfi->addr_unlock2 = 0x2AAA;
}
-static void fixup_sst39vf_rev_b(struct mtd_info *mtd, void *param)
+static void fixup_sst39vf_rev_b(struct mtd_info *mtd)
{
struct map_info *map = mtd->priv;
struct cfi_private *cfi = map->fldrv_priv;
@@ -295,12 +295,12 @@ static void fixup_sst39vf_rev_b(struct mtd_info *mtd, void *param)
cfi->sector_erase_cmd = CMD(0x50);
}
-static void fixup_sst38vf640x_sectorsize(struct mtd_info *mtd, void *param)
+static void fixup_sst38vf640x_sectorsize(struct mtd_info *mtd)
{
struct map_info *map = mtd->priv;
struct cfi_private *cfi = map->fldrv_priv;
- fixup_sst39vf_rev_b(mtd, param);
+ fixup_sst39vf_rev_b(mtd);
/*
* CFI reports 1024 sectors (0x03ff+1) of 64KBytes (0x0100*256) where
@@ -310,7 +310,7 @@ static void fixup_sst38vf640x_sectorsize(struct mtd_info *mtd, void *param)
pr_warning("%s: Bad 38VF640x CFI data; adjusting sector size from 64 to 8KiB\n", mtd->name);
}
-static void fixup_s29gl064n_sectors(struct mtd_info *mtd, void *param)
+static void fixup_s29gl064n_sectors(struct mtd_info *mtd)
{
struct map_info *map = mtd->priv;
struct cfi_private *cfi = map->fldrv_priv;
@@ -321,7 +321,7 @@ static void fixup_s29gl064n_sectors(struct mtd_info *mtd, void *param)
}
}
-static void fixup_s29gl032n_sectors(struct mtd_info *mtd, void *param)
+static void fixup_s29gl032n_sectors(struct mtd_info *mtd)
{
struct map_info *map = mtd->priv;
struct cfi_private *cfi = map->fldrv_priv;
@@ -334,47 +334,47 @@ static void fixup_s29gl032n_sectors(struct mtd_info *mtd, void *param)
/* Used to fix CFI-Tables of chips without Extended Query Tables */
static struct cfi_fixup cfi_nopri_fixup_table[] = {
- { CFI_MFR_SST, 0x234A, fixup_sst39vf, NULL, }, /* SST39VF1602 */
- { CFI_MFR_SST, 0x234B, fixup_sst39vf, NULL, }, /* SST39VF1601 */
- { CFI_MFR_SST, 0x235A, fixup_sst39vf, NULL, }, /* SST39VF3202 */
- { CFI_MFR_SST, 0x235B, fixup_sst39vf, NULL, }, /* SST39VF3201 */
- { CFI_MFR_SST, 0x235C, fixup_sst39vf_rev_b, NULL, }, /* SST39VF3202B */
- { CFI_MFR_SST, 0x235D, fixup_sst39vf_rev_b, NULL, }, /* SST39VF3201B */
- { CFI_MFR_SST, 0x236C, fixup_sst39vf_rev_b, NULL, }, /* SST39VF6402B */
- { CFI_MFR_SST, 0x236D, fixup_sst39vf_rev_b, NULL, }, /* SST39VF6401B */
- { 0, 0, NULL, NULL }
+ { CFI_MFR_SST, 0x234a, fixup_sst39vf }, /* SST39VF1602 */
+ { CFI_MFR_SST, 0x234b, fixup_sst39vf }, /* SST39VF1601 */
+ { CFI_MFR_SST, 0x235a, fixup_sst39vf }, /* SST39VF3202 */
+ { CFI_MFR_SST, 0x235b, fixup_sst39vf }, /* SST39VF3201 */
+ { CFI_MFR_SST, 0x235c, fixup_sst39vf_rev_b }, /* SST39VF3202B */
+ { CFI_MFR_SST, 0x235d, fixup_sst39vf_rev_b }, /* SST39VF3201B */
+ { CFI_MFR_SST, 0x236c, fixup_sst39vf_rev_b }, /* SST39VF6402B */
+ { CFI_MFR_SST, 0x236d, fixup_sst39vf_rev_b }, /* SST39VF6401B */
+ { 0, 0, NULL }
};
static struct cfi_fixup cfi_fixup_table[] = {
- { CFI_MFR_ATMEL, CFI_ID_ANY, fixup_convert_atmel_pri, NULL },
+ { CFI_MFR_ATMEL, CFI_ID_ANY, fixup_convert_atmel_pri },
#ifdef AMD_BOOTLOC_BUG
- { CFI_MFR_AMD, CFI_ID_ANY, fixup_amd_bootblock, NULL },
- { CFI_MFR_MACRONIX, CFI_ID_ANY, fixup_amd_bootblock, NULL },
+ { CFI_MFR_AMD, CFI_ID_ANY, fixup_amd_bootblock },
+ { CFI_MFR_MACRONIX, CFI_ID_ANY, fixup_amd_bootblock },
#endif
- { CFI_MFR_AMD, 0x0050, fixup_use_secsi, NULL, },
- { CFI_MFR_AMD, 0x0053, fixup_use_secsi, NULL, },
- { CFI_MFR_AMD, 0x0055, fixup_use_secsi, NULL, },
- { CFI_MFR_AMD, 0x0056, fixup_use_secsi, NULL, },
- { CFI_MFR_AMD, 0x005C, fixup_use_secsi, NULL, },
- { CFI_MFR_AMD, 0x005F, fixup_use_secsi, NULL, },
- { CFI_MFR_AMD, 0x0c01, fixup_s29gl064n_sectors, NULL, },
- { CFI_MFR_AMD, 0x1301, fixup_s29gl064n_sectors, NULL, },
- { CFI_MFR_AMD, 0x1a00, fixup_s29gl032n_sectors, NULL, },
- { CFI_MFR_AMD, 0x1a01, fixup_s29gl032n_sectors, NULL, },
- { CFI_MFR_SST, 0x536A, fixup_sst38vf640x_sectorsize, NULL, }, /* SST38VF6402 */
- { CFI_MFR_SST, 0x536B, fixup_sst38vf640x_sectorsize, NULL, }, /* SST38VF6401 */
- { CFI_MFR_SST, 0x536C, fixup_sst38vf640x_sectorsize, NULL, }, /* SST38VF6404 */
- { CFI_MFR_SST, 0x536D, fixup_sst38vf640x_sectorsize, NULL, }, /* SST38VF6403 */
+ { CFI_MFR_AMD, 0x0050, fixup_use_secsi },
+ { CFI_MFR_AMD, 0x0053, fixup_use_secsi },
+ { CFI_MFR_AMD, 0x0055, fixup_use_secsi },
+ { CFI_MFR_AMD, 0x0056, fixup_use_secsi },
+ { CFI_MFR_AMD, 0x005C, fixup_use_secsi },
+ { CFI_MFR_AMD, 0x005F, fixup_use_secsi },
+ { CFI_MFR_AMD, 0x0c01, fixup_s29gl064n_sectors },
+ { CFI_MFR_AMD, 0x1301, fixup_s29gl064n_sectors },
+ { CFI_MFR_AMD, 0x1a00, fixup_s29gl032n_sectors },
+ { CFI_MFR_AMD, 0x1a01, fixup_s29gl032n_sectors },
+ { CFI_MFR_SST, 0x536a, fixup_sst38vf640x_sectorsize }, /* SST38VF6402 */
+ { CFI_MFR_SST, 0x536b, fixup_sst38vf640x_sectorsize }, /* SST38VF6401 */
+ { CFI_MFR_SST, 0x536c, fixup_sst38vf640x_sectorsize }, /* SST38VF6404 */
+ { CFI_MFR_SST, 0x536d, fixup_sst38vf640x_sectorsize }, /* SST38VF6403 */
#if !FORCE_WORD_WRITE
- { CFI_MFR_ANY, CFI_ID_ANY, fixup_use_write_buffers, NULL, },
+ { CFI_MFR_ANY, CFI_ID_ANY, fixup_use_write_buffers },
#endif
- { 0, 0, NULL, NULL }
+ { 0, 0, NULL }
};
static struct cfi_fixup jedec_fixup_table[] = {
- { CFI_MFR_SST, SST49LF004B, fixup_use_fwh_lock, NULL, },
- { CFI_MFR_SST, SST49LF040B, fixup_use_fwh_lock, NULL, },
- { CFI_MFR_SST, SST49LF008A, fixup_use_fwh_lock, NULL, },
- { 0, 0, NULL, NULL }
+ { CFI_MFR_SST, SST49LF004B, fixup_use_fwh_lock },
+ { CFI_MFR_SST, SST49LF040B, fixup_use_fwh_lock },
+ { CFI_MFR_SST, SST49LF008A, fixup_use_fwh_lock },
+ { 0, 0, NULL }
};
static struct cfi_fixup fixup_table[] = {
@@ -383,18 +383,30 @@ static struct cfi_fixup fixup_table[] = {
* well. This table is to pick all cases where
* we know that is the case.
*/
- { CFI_MFR_ANY, CFI_ID_ANY, fixup_use_erase_chip, NULL },
- { CFI_MFR_ATMEL, AT49BV6416, fixup_use_atmel_lock, NULL },
- { 0, 0, NULL, NULL }
+ { CFI_MFR_ANY, CFI_ID_ANY, fixup_use_erase_chip },
+ { CFI_MFR_ATMEL, AT49BV6416, fixup_use_atmel_lock },
+ { 0, 0, NULL }
};
static void cfi_fixup_major_minor(struct cfi_private *cfi,
struct cfi_pri_amdstd *extp)
{
- if (cfi->mfr == CFI_MFR_SAMSUNG && cfi->id == 0x257e &&
- extp->MajorVersion == '0')
- extp->MajorVersion = '1';
+ if (cfi->mfr == CFI_MFR_SAMSUNG) {
+ if ((extp->MajorVersion == '0' && extp->MinorVersion == '0') ||
+ (extp->MajorVersion == '3' && extp->MinorVersion == '3')) {
+ /*
+ * Samsung K8P2815UQB and K8D6x16UxM chips
+ * report major=0 / minor=0.
+ * K8D3x16UxC chips report major=3 / minor=3.
+ */
+ printk(KERN_NOTICE " Fixing Samsung's Amd/Fujitsu"
+ " Extended Query version to 1.%c\n",
+ extp->MinorVersion);
+ extp->MajorVersion = '1';
+ }
+ }
+
/*
* SST 38VF640x chips report major=0xFF / minor=0xFF.
*/
@@ -428,6 +440,10 @@ struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary)
mtd->flags = MTD_CAP_NORFLASH;
mtd->name = map->name;
mtd->writesize = 1;
+ mtd->writebufsize = 1 << cfi->cfiq->MaxBufWriteSize;
+
+ DEBUG(MTD_DEBUG_LEVEL3, "MTD %s(): write buffer size %d\n",
+ __func__, mtd->writebufsize);
mtd->reboot_notifier.notifier_call = cfi_amdstd_reboot;
diff --git a/drivers/mtd/chips/cfi_cmdset_0020.c b/drivers/mtd/chips/cfi_cmdset_0020.c
index 314af1f..c04b765 100644
--- a/drivers/mtd/chips/cfi_cmdset_0020.c
+++ b/drivers/mtd/chips/cfi_cmdset_0020.c
@@ -238,6 +238,7 @@ static struct mtd_info *cfi_staa_setup(struct map_info *map)
mtd->resume = cfi_staa_resume;
mtd->flags = MTD_CAP_NORFLASH & ~MTD_BIT_WRITEABLE;
mtd->writesize = 8; /* FIXME: Should be 0 for STMicro flashes w/out ECC */
+ mtd->writebufsize = 1 << cfi->cfiq->MaxBufWriteSize;
map->fldrv = &cfi_staa_chipdrv;
__module_get(THIS_MODULE);
mtd->name = map->name;
diff --git a/drivers/mtd/chips/cfi_util.c b/drivers/mtd/chips/cfi_util.c
index 360525c..6ae3d11 100644
--- a/drivers/mtd/chips/cfi_util.c
+++ b/drivers/mtd/chips/cfi_util.c
@@ -156,7 +156,7 @@ void cfi_fixup(struct mtd_info *mtd, struct cfi_fixup *fixups)
for (f=fixups; f->fixup; f++) {
if (((f->mfr == CFI_MFR_ANY) || (f->mfr == cfi->mfr)) &&
((f->id == CFI_ID_ANY) || (f->id == cfi->id))) {
- f->fixup(mtd, f->param);
+ f->fixup(mtd);
}
}
}
diff --git a/drivers/mtd/chips/fwh_lock.h b/drivers/mtd/chips/fwh_lock.h
index d180649..5e3cc80 100644
--- a/drivers/mtd/chips/fwh_lock.h
+++ b/drivers/mtd/chips/fwh_lock.h
@@ -98,7 +98,7 @@ static int fwh_unlock_varsize(struct mtd_info *mtd, loff_t ofs, uint64_t len)
return ret;
}
-static void fixup_use_fwh_lock(struct mtd_info *mtd, void *param)
+static void fixup_use_fwh_lock(struct mtd_info *mtd)
{
printk(KERN_NOTICE "using fwh lock/unlock method\n");
/* Setup for the chips with the fwh lock method */
diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c
index bf5a002..e4eba6c 100644
--- a/drivers/mtd/devices/m25p80.c
+++ b/drivers/mtd/devices/m25p80.c
@@ -51,6 +51,10 @@
#define OPCODE_WRDI 0x04 /* Write disable */
#define OPCODE_AAI_WP 0xad /* Auto address increment word program */
+/* Used for Macronix flashes only. */
+#define OPCODE_EN4B 0xb7 /* Enter 4-byte mode */
+#define OPCODE_EX4B 0xe9 /* Exit 4-byte mode */
+
/* Status Register bits. */
#define SR_WIP 1 /* Write in progress */
#define SR_WEL 2 /* Write enable latch */
@@ -62,7 +66,7 @@
/* Define max times to check status register before we give up. */
#define MAX_READY_WAIT_JIFFIES (40 * HZ) /* M25P16 specs 40s max chip erase */
-#define MAX_CMD_SIZE 4
+#define MAX_CMD_SIZE 5
#ifdef CONFIG_M25PXX_USE_FAST_READ
#define OPCODE_READ OPCODE_FAST_READ
@@ -152,6 +156,16 @@ static inline int write_disable(struct m25p *flash)
}
/*
+ * Enable/disable 4-byte addressing mode.
+ */
+static inline int set_4byte(struct m25p *flash, int enable)
+{
+ u8 code = enable ? OPCODE_EN4B : OPCODE_EX4B;
+
+ return spi_write_then_read(flash->spi, &code, 1, NULL, 0);
+}
+
+/*
* Service routine to read status register until ready, or timeout occurs.
* Returns non-zero if error.
*/
@@ -207,6 +221,7 @@ static void m25p_addr2cmd(struct m25p *flash, unsigned int addr, u8 *cmd)
cmd[1] = addr >> (flash->addr_width * 8 - 8);
cmd[2] = addr >> (flash->addr_width * 8 - 16);
cmd[3] = addr >> (flash->addr_width * 8 - 24);
+ cmd[4] = addr >> (flash->addr_width * 8 - 32);
}
static int m25p_cmdsz(struct m25p *flash)
@@ -482,6 +497,10 @@ static int sst_write(struct mtd_info *mtd, loff_t to, size_t len,
size_t actual;
int cmd_sz, ret;
+ DEBUG(MTD_DEBUG_LEVEL2, "%s: %s %s 0x%08x, len %zd\n",
+ dev_name(&flash->spi->dev), __func__, "to",
+ (u32)to, len);
+
*retlen = 0;
/* sanity checks */
@@ -607,7 +626,6 @@ struct flash_info {
.sector_size = (_sector_size), \
.n_sectors = (_n_sectors), \
.page_size = 256, \
- .addr_width = 3, \
.flags = (_flags), \
})
@@ -635,7 +653,7 @@ static const struct spi_device_id m25p_ids[] = {
{ "at26f004", INFO(0x1f0400, 0, 64 * 1024, 8, SECT_4K) },
{ "at26df081a", INFO(0x1f4501, 0, 64 * 1024, 16, SECT_4K) },
{ "at26df161a", INFO(0x1f4601, 0, 64 * 1024, 32, SECT_4K) },
- { "at26df321", INFO(0x1f4701, 0, 64 * 1024, 64, SECT_4K) },
+ { "at26df321", INFO(0x1f4700, 0, 64 * 1024, 64, SECT_4K) },
/* EON -- en25pxx */
{ "en25p32", INFO(0x1c2016, 0, 64 * 1024, 64, 0) },
@@ -653,6 +671,8 @@ static const struct spi_device_id m25p_ids[] = {
{ "mx25l6405d", INFO(0xc22017, 0, 64 * 1024, 128, 0) },
{ "mx25l12805d", INFO(0xc22018, 0, 64 * 1024, 256, 0) },
{ "mx25l12855e", INFO(0xc22618, 0, 64 * 1024, 256, 0) },
+ { "mx25l25635e", INFO(0xc22019, 0, 64 * 1024, 512, 0) },
+ { "mx25l25655e", INFO(0xc22619, 0, 64 * 1024, 512, 0) },
/* Spansion -- single (large) sector size only, at least
* for the chips listed here (without boot sectors).
@@ -764,6 +784,7 @@ static const struct spi_device_id *__devinit jedec_probe(struct spi_device *spi)
return &m25p_ids[tmp];
}
}
+ dev_err(&spi->dev, "unrecognized JEDEC id %06x\n", jedec);
return ERR_PTR(-ENODEV);
}
@@ -883,7 +904,17 @@ static int __devinit m25p_probe(struct spi_device *spi)
flash->mtd.dev.parent = &spi->dev;
flash->page_size = info->page_size;
- flash->addr_width = info->addr_width;
+
+ if (info->addr_width)
+ flash->addr_width = info->addr_width;
+ else {
+ /* enable 4-byte addressing if the device exceeds 16MiB */
+ if (flash->mtd.size > 0x1000000) {
+ flash->addr_width = 4;
+ set_4byte(flash, 1);
+ } else
+ flash->addr_width = 3;
+ }
dev_info(&spi->dev, "%s (%lld Kbytes)\n", id->name,
(long long)flash->mtd.size >> 10);
diff --git a/drivers/mtd/devices/sst25l.c b/drivers/mtd/devices/sst25l.c
index 684247a..c163e61 100644
--- a/drivers/mtd/devices/sst25l.c
+++ b/drivers/mtd/devices/sst25l.c
@@ -335,7 +335,7 @@ out:
return ret;
}
-static struct flash_info *__init sst25l_match_device(struct spi_device *spi)
+static struct flash_info *__devinit sst25l_match_device(struct spi_device *spi)
{
struct flash_info *flash_info = NULL;
struct spi_message m;
@@ -375,7 +375,7 @@ static struct flash_info *__init sst25l_match_device(struct spi_device *spi)
return flash_info;
}
-static int __init sst25l_probe(struct spi_device *spi)
+static int __devinit sst25l_probe(struct spi_device *spi)
{
struct flash_info *flash_info;
struct sst25l_flash *flash;
diff --git a/drivers/mtd/maps/amd76xrom.c b/drivers/mtd/maps/amd76xrom.c
index 19fe92d..77d64ce 100644
--- a/drivers/mtd/maps/amd76xrom.c
+++ b/drivers/mtd/maps/amd76xrom.c
@@ -149,11 +149,8 @@ static int __devinit amd76xrom_init_one (struct pci_dev *pdev,
if (request_resource(&iomem_resource, &window->rsrc)) {
window->rsrc.parent = NULL;
printk(KERN_ERR MOD_NAME
- " %s(): Unable to register resource"
- " 0x%.16llx-0x%.16llx - kernel bug?\n",
- __func__,
- (unsigned long long)window->rsrc.start,
- (unsigned long long)window->rsrc.end);
+ " %s(): Unable to register resource %pR - kernel bug?\n",
+ __func__, &window->rsrc);
}
diff --git a/drivers/mtd/maps/bcm963xx-flash.c b/drivers/mtd/maps/bcm963xx-flash.c
index d175c12..1f30495 100644
--- a/drivers/mtd/maps/bcm963xx-flash.c
+++ b/drivers/mtd/maps/bcm963xx-flash.c
@@ -196,10 +196,15 @@ static int bcm963xx_probe(struct platform_device *pdev)
bcm963xx_mtd_info = do_map_probe("cfi_probe", &bcm963xx_map);
if (!bcm963xx_mtd_info) {
dev_err(&pdev->dev, "failed to probe using CFI\n");
+ bcm963xx_mtd_info = do_map_probe("jedec_probe", &bcm963xx_map);
+ if (bcm963xx_mtd_info)
+ goto probe_ok;
+ dev_err(&pdev->dev, "failed to probe using JEDEC\n");
err = -EIO;
goto err_probe;
}
+probe_ok:
bcm963xx_mtd_info->owner = THIS_MODULE;
/* This is mutually exclusive */
diff --git a/drivers/mtd/maps/ck804xrom.c b/drivers/mtd/maps/ck804xrom.c
index ddb462b..5fdb7b2 100644
--- a/drivers/mtd/maps/ck804xrom.c
+++ b/drivers/mtd/maps/ck804xrom.c
@@ -178,11 +178,8 @@ static int __devinit ck804xrom_init_one (struct pci_dev *pdev,
if (request_resource(&iomem_resource, &window->rsrc)) {
window->rsrc.parent = NULL;
printk(KERN_ERR MOD_NAME
- " %s(): Unable to register resource"
- " 0x%.016llx-0x%.016llx - kernel bug?\n",
- __func__,
- (unsigned long long)window->rsrc.start,
- (unsigned long long)window->rsrc.end);
+ " %s(): Unable to register resource %pR - kernel bug?\n",
+ __func__, &window->rsrc);
}
diff --git a/drivers/mtd/maps/esb2rom.c b/drivers/mtd/maps/esb2rom.c
index d12c93d..4feb750 100644
--- a/drivers/mtd/maps/esb2rom.c
+++ b/drivers/mtd/maps/esb2rom.c
@@ -242,12 +242,9 @@ static int __devinit esb2rom_init_one(struct pci_dev *pdev,
window->rsrc.flags = IORESOURCE_MEM | IORESOURCE_BUSY;
if (request_resource(&iomem_resource, &window->rsrc)) {
window->rsrc.parent = NULL;
- printk(KERN_DEBUG MOD_NAME
- ": %s(): Unable to register resource"
- " 0x%.08llx-0x%.08llx - kernel bug?\n",
- __func__,
- (unsigned long long)window->rsrc.start,
- (unsigned long long)window->rsrc.end);
+ printk(KERN_DEBUG MOD_NAME ": "
+ "%s(): Unable to register resource %pR - kernel bug?\n",
+ __func__, &window->rsrc);
}
/* Map the firmware hub into my address space. */
diff --git a/drivers/mtd/maps/ichxrom.c b/drivers/mtd/maps/ichxrom.c
index f102bf2..1337a41 100644
--- a/drivers/mtd/maps/ichxrom.c
+++ b/drivers/mtd/maps/ichxrom.c
@@ -175,12 +175,9 @@ static int __devinit ichxrom_init_one (struct pci_dev *pdev,
window->rsrc.flags = IORESOURCE_MEM | IORESOURCE_BUSY;
if (request_resource(&iomem_resource, &window->rsrc)) {
window->rsrc.parent = NULL;
- printk(KERN_DEBUG MOD_NAME
- ": %s(): Unable to register resource"
- " 0x%.16llx-0x%.16llx - kernel bug?\n",
- __func__,
- (unsigned long long)window->rsrc.start,
- (unsigned long long)window->rsrc.end);
+ printk(KERN_DEBUG MOD_NAME ": "
+ "%s(): Unable to register resource %pR - kernel bug?\n",
+ __func__, &window->rsrc);
}
/* Map the firmware hub into my address space. */
diff --git a/drivers/mtd/maps/physmap_of.c b/drivers/mtd/maps/physmap_of.c
index 9861814..8506578 100644
--- a/drivers/mtd/maps/physmap_of.c
+++ b/drivers/mtd/maps/physmap_of.c
@@ -274,9 +274,7 @@ static int __devinit of_flash_probe(struct platform_device *dev,
continue;
}
- dev_dbg(&dev->dev, "of_flash device: %.8llx-%.8llx\n",
- (unsigned long long)res.start,
- (unsigned long long)res.end);
+ dev_dbg(&dev->dev, "of_flash device: %pR\n", &res);
err = -EBUSY;
res_size = resource_size(&res);
diff --git a/drivers/mtd/maps/scx200_docflash.c b/drivers/mtd/maps/scx200_docflash.c
index b5391eb..027e628 100644
--- a/drivers/mtd/maps/scx200_docflash.c
+++ b/drivers/mtd/maps/scx200_docflash.c
@@ -166,9 +166,8 @@ static int __init init_scx200_docflash(void)
outl(pmr, scx200_cb_base + SCx200_PMR);
}
- printk(KERN_INFO NAME ": DOCCS mapped at 0x%llx-0x%llx, width %d\n",
- (unsigned long long)docmem.start,
- (unsigned long long)docmem.end, width);
+ printk(KERN_INFO NAME ": DOCCS mapped at %pR, width %d\n",
+ &docmem, width);
scx200_docflash_map.size = size;
if (width == 8)
diff --git a/drivers/mtd/maps/tqm8xxl.c b/drivers/mtd/maps/tqm8xxl.c
index 6014698..c08e140 100644
--- a/drivers/mtd/maps/tqm8xxl.c
+++ b/drivers/mtd/maps/tqm8xxl.c
@@ -139,7 +139,7 @@ static int __init init_tqm_mtd(void)
goto error_mem;
}
- map_banks[idx]->name = (char *)kmalloc(16, GFP_KERNEL);
+ map_banks[idx]->name = kmalloc(16, GFP_KERNEL);
if (!map_banks[idx]->name) {
ret = -ENOMEM;
diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c
index ee4bb33..145b3d0d 100644
--- a/drivers/mtd/mtdchar.c
+++ b/drivers/mtd/mtdchar.c
@@ -522,10 +522,6 @@ static int mtd_blkpg_ioctl(struct mtd_info *mtd,
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
- /* Only master mtd device must be used to control partitions */
- if (!mtd_is_master(mtd))
- return -EINVAL;
-
if (copy_from_user(&a, arg, sizeof(struct blkpg_ioctl_arg)))
return -EFAULT;
@@ -535,6 +531,10 @@ static int mtd_blkpg_ioctl(struct mtd_info *mtd,
switch (a.op) {
case BLKPG_ADD_PARTITION:
+ /* Only master mtd device must be used to add partitions */
+ if (mtd_is_partition(mtd))
+ return -EINVAL;
+
return mtd_add_partition(mtd, p.devname, p.start, p.length);
case BLKPG_DEL_PARTITION:
@@ -601,6 +601,7 @@ static int mtd_ioctl(struct file *file, u_int cmd, u_long arg)
}
case MEMGETINFO:
+ memset(&info, 0, sizeof(info));
info.type = mtd->type;
info.flags = mtd->flags;
info.size = mtd->size;
@@ -609,7 +610,6 @@ static int mtd_ioctl(struct file *file, u_int cmd, u_long arg)
info.oobsize = mtd->oobsize;
/* The below fields are obsolete */
info.ecctype = -1;
- info.eccsize = 0;
if (copy_to_user(argp, &info, sizeof(struct mtd_info_user)))
return -EFAULT;
break;
@@ -1201,7 +1201,7 @@ err_unregister_chdev:
static void __exit cleanup_mtdchar(void)
{
unregister_mtd_user(&mtdchar_notifier);
- mntput_long(mtd_inode_mnt);
+ mntput(mtd_inode_mnt);
unregister_filesystem(&mtd_inodefs_type);
__unregister_chrdev(MTD_CHAR_MAJOR, 0, 1 << MINORBITS, "mtd");
}
diff --git a/drivers/mtd/mtdconcat.c b/drivers/mtd/mtdconcat.c
index bf8de09..5f5777b 100644
--- a/drivers/mtd/mtdconcat.c
+++ b/drivers/mtd/mtdconcat.c
@@ -776,6 +776,7 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c
concat->mtd.size = subdev[0]->size;
concat->mtd.erasesize = subdev[0]->erasesize;
concat->mtd.writesize = subdev[0]->writesize;
+ concat->mtd.writebufsize = subdev[0]->writebufsize;
concat->mtd.subpage_sft = subdev[0]->subpage_sft;
concat->mtd.oobsize = subdev[0]->oobsize;
concat->mtd.oobavail = subdev[0]->oobavail;
diff --git a/drivers/mtd/mtdoops.c b/drivers/mtd/mtdoops.c
index c948150..e3e40f4 100644
--- a/drivers/mtd/mtdoops.c
+++ b/drivers/mtd/mtdoops.c
@@ -401,7 +401,8 @@ static void mtdoops_notify_remove(struct mtd_info *mtd)
printk(KERN_WARNING "mtdoops: could not unregister kmsg_dumper\n");
cxt->mtd = NULL;
- flush_scheduled_work();
+ flush_work_sync(&cxt->work_erase);
+ flush_work_sync(&cxt->work_write);
}
diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c
index 79e3689..0a47601 100644
--- a/drivers/mtd/mtdpart.c
+++ b/drivers/mtd/mtdpart.c
@@ -120,8 +120,25 @@ static int part_read_oob(struct mtd_info *mtd, loff_t from,
return -EINVAL;
if (ops->datbuf && from + ops->len > mtd->size)
return -EINVAL;
- res = part->master->read_oob(part->master, from + part->offset, ops);
+ /*
+ * If OOB is also requested, make sure that we do not read past the end
+ * of this partition.
+ */
+ if (ops->oobbuf) {
+ size_t len, pages;
+
+ if (ops->mode == MTD_OOB_AUTO)
+ len = mtd->oobavail;
+ else
+ len = mtd->oobsize;
+ pages = mtd_div_by_ws(mtd->size, mtd);
+ pages -= mtd_div_by_ws(from, mtd);
+ if (ops->ooboffs + ops->ooblen > pages * len)
+ return -EINVAL;
+ }
+
+ res = part->master->read_oob(part->master, from + part->offset, ops);
if (unlikely(res)) {
if (res == -EUCLEAN)
mtd->ecc_stats.corrected++;
@@ -384,6 +401,7 @@ static struct mtd_part *allocate_partition(struct mtd_info *master,
slave->mtd.flags = master->flags & ~part->mask_flags;
slave->mtd.size = part->size;
slave->mtd.writesize = master->writesize;
+ slave->mtd.writebufsize = master->writebufsize;
slave->mtd.oobsize = master->oobsize;
slave->mtd.oobavail = master->oobavail;
slave->mtd.subpage_sft = master->subpage_sft;
@@ -720,19 +738,19 @@ int parse_mtd_partitions(struct mtd_info *master, const char **types,
}
EXPORT_SYMBOL_GPL(parse_mtd_partitions);
-int mtd_is_master(struct mtd_info *mtd)
+int mtd_is_partition(struct mtd_info *mtd)
{
struct mtd_part *part;
- int nopart = 0;
+ int ispart = 0;
mutex_lock(&mtd_partitions_mutex);
list_for_each_entry(part, &mtd_partitions, list)
if (&part->mtd == mtd) {
- nopart = 1;
+ ispart = 1;
break;
}
mutex_unlock(&mtd_partitions_mutex);
- return nopart;
+ return ispart;
}
-EXPORT_SYMBOL_GPL(mtd_is_master);
+EXPORT_SYMBOL_GPL(mtd_is_partition);
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index 8229802..c895922 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -96,6 +96,7 @@ config MTD_NAND_SPIA
config MTD_NAND_AMS_DELTA
tristate "NAND Flash device on Amstrad E3"
depends on MACH_AMS_DELTA
+ default y
help
Support for NAND flash on Amstrad E3 (Delta).
diff --git a/drivers/mtd/nand/ams-delta.c b/drivers/mtd/nand/ams-delta.c
index 2548e10..a067d09 100644
--- a/drivers/mtd/nand/ams-delta.c
+++ b/drivers/mtd/nand/ams-delta.c
@@ -4,6 +4,8 @@
* Copyright (C) 2006 Jonathan McDowell <noodles@earth.li>
*
* Derived from drivers/mtd/toto.c
+ * Converted to platform driver by Janusz Krzysztofik <jkrzyszt@tis.icnet.pl>
+ * Partially stolen from drivers/mtd/nand/plat_nand.c
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -62,9 +64,10 @@ static struct mtd_partition partition_info[] = {
static void ams_delta_write_byte(struct mtd_info *mtd, u_char byte)
{
struct nand_chip *this = mtd->priv;
+ void __iomem *io_base = this->priv;
- omap_writew(0, (OMAP1_MPUIO_BASE + OMAP_MPUIO_IO_CNTL));
- omap_writew(byte, this->IO_ADDR_W);
+ writew(0, io_base + OMAP_MPUIO_IO_CNTL);
+ writew(byte, this->IO_ADDR_W);
ams_delta_latch2_write(AMS_DELTA_LATCH2_NAND_NWE, 0);
ndelay(40);
ams_delta_latch2_write(AMS_DELTA_LATCH2_NAND_NWE,
@@ -75,11 +78,12 @@ static u_char ams_delta_read_byte(struct mtd_info *mtd)
{
u_char res;
struct nand_chip *this = mtd->priv;
+ void __iomem *io_base = this->priv;
ams_delta_latch2_write(AMS_DELTA_LATCH2_NAND_NRE, 0);
ndelay(40);
- omap_writew(~0, (OMAP1_MPUIO_BASE + OMAP_MPUIO_IO_CNTL));
- res = omap_readw(this->IO_ADDR_R);
+ writew(~0, io_base + OMAP_MPUIO_IO_CNTL);
+ res = readw(this->IO_ADDR_R);
ams_delta_latch2_write(AMS_DELTA_LATCH2_NAND_NRE,
AMS_DELTA_LATCH2_NAND_NRE);
@@ -151,11 +155,16 @@ static int ams_delta_nand_ready(struct mtd_info *mtd)
/*
* Main initialization routine
*/
-static int __init ams_delta_init(void)
+static int __devinit ams_delta_init(struct platform_device *pdev)
{
struct nand_chip *this;
+ struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ void __iomem *io_base;
int err = 0;
+ if (!res)
+ return -ENXIO;
+
/* Allocate memory for MTD device structure and private data */
ams_delta_mtd = kmalloc(sizeof(struct mtd_info) +
sizeof(struct nand_chip), GFP_KERNEL);
@@ -177,9 +186,25 @@ static int __init ams_delta_init(void)
/* Link the private data with the MTD structure */
ams_delta_mtd->priv = this;
+ if (!request_mem_region(res->start, resource_size(res),
+ dev_name(&pdev->dev))) {
+ dev_err(&pdev->dev, "request_mem_region failed\n");
+ err = -EBUSY;
+ goto out_free;
+ }
+
+ io_base = ioremap(res->start, resource_size(res));
+ if (io_base == NULL) {
+ dev_err(&pdev->dev, "ioremap failed\n");
+ err = -EIO;
+ goto out_release_io;
+ }
+
+ this->priv = io_base;
+
/* Set address of NAND IO lines */
- this->IO_ADDR_R = (OMAP1_MPUIO_BASE + OMAP_MPUIO_INPUT_LATCH);
- this->IO_ADDR_W = (OMAP1_MPUIO_BASE + OMAP_MPUIO_OUTPUT);
+ this->IO_ADDR_R = io_base + OMAP_MPUIO_INPUT_LATCH;
+ this->IO_ADDR_W = io_base + OMAP_MPUIO_OUTPUT;
this->read_byte = ams_delta_read_byte;
this->write_buf = ams_delta_write_buf;
this->read_buf = ams_delta_read_buf;
@@ -195,6 +220,8 @@ static int __init ams_delta_init(void)
this->chip_delay = 30;
this->ecc.mode = NAND_ECC_SOFT;
+ platform_set_drvdata(pdev, io_base);
+
/* Set chip enabled, but */
ams_delta_latch2_write(NAND_MASK, AMS_DELTA_LATCH2_NAND_NRE |
AMS_DELTA_LATCH2_NAND_NWE |
@@ -214,25 +241,56 @@ static int __init ams_delta_init(void)
goto out;
out_mtd:
+ platform_set_drvdata(pdev, NULL);
+ iounmap(io_base);
+out_release_io:
+ release_mem_region(res->start, resource_size(res));
+out_free:
kfree(ams_delta_mtd);
out:
return err;
}
-module_init(ams_delta_init);
-
/*
* Clean up routine
*/
-static void __exit ams_delta_cleanup(void)
+static int __devexit ams_delta_cleanup(struct platform_device *pdev)
{
+ void __iomem *io_base = platform_get_drvdata(pdev);
+ struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
/* Release resources, unregister device */
nand_release(ams_delta_mtd);
+ iounmap(io_base);
+ release_mem_region(res->start, resource_size(res));
+
/* Free the MTD device structure */
kfree(ams_delta_mtd);
+
+ return 0;
+}
+
+static struct platform_driver ams_delta_nand_driver = {
+ .probe = ams_delta_init,
+ .remove = __devexit_p(ams_delta_cleanup),
+ .driver = {
+ .name = "ams-delta-nand",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init ams_delta_nand_init(void)
+{
+ return platform_driver_register(&ams_delta_nand_driver);
+}
+module_init(ams_delta_nand_init);
+
+static void __exit ams_delta_nand_exit(void)
+{
+ platform_driver_unregister(&ams_delta_nand_driver);
}
-module_exit(ams_delta_cleanup);
+module_exit(ams_delta_nand_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jonathan McDowell <noodles@earth.li>");
diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/fsl_elbc_nand.c
index c141b07..7a13d42 100644
--- a/drivers/mtd/nand/fsl_elbc_nand.c
+++ b/drivers/mtd/nand/fsl_elbc_nand.c
@@ -388,6 +388,8 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command,
"page_addr: 0x%x, column: 0x%x.\n",
page_addr, column);
+ elbc_fcm_ctrl->column = column;
+ elbc_fcm_ctrl->oob = 0;
elbc_fcm_ctrl->use_mdr = 1;
fcr = (NAND_CMD_STATUS << FCR_CMD1_SHIFT) |
diff --git a/drivers/mtd/nand/fsmc_nand.c b/drivers/mtd/nand/fsmc_nand.c
index 02edfba..205b10b 100644
--- a/drivers/mtd/nand/fsmc_nand.c
+++ b/drivers/mtd/nand/fsmc_nand.c
@@ -31,6 +31,7 @@
#include <linux/io.h>
#include <linux/slab.h>
#include <linux/mtd/fsmc.h>
+#include <linux/amba/bus.h>
#include <mtd/mtd-abi.h>
static struct nand_ecclayout fsmc_ecc1_layout = {
@@ -119,21 +120,36 @@ static struct fsmc_eccplace fsmc_ecc4_sp_place = {
}
};
-/*
- * Default partition tables to be used if the partition information not
- * provided through platform data
- */
-#define PARTITION(n, off, sz) {.name = n, .offset = off, .size = sz}
+#ifdef CONFIG_MTD_PARTITIONS
/*
+ * Default partition tables to be used if the partition information not
+ * provided through platform data.
+ *
* Default partition layout for small page(= 512 bytes) devices
* Size for "Root file system" is updated in driver based on actual device size
*/
static struct mtd_partition partition_info_16KB_blk[] = {
- PARTITION("X-loader", 0, 4 * 0x4000),
- PARTITION("U-Boot", 0x10000, 20 * 0x4000),
- PARTITION("Kernel", 0x60000, 256 * 0x4000),
- PARTITION("Root File System", 0x460000, 0),
+ {
+ .name = "X-loader",
+ .offset = 0,
+ .size = 4*0x4000,
+ },
+ {
+ .name = "U-Boot",
+ .offset = 0x10000,
+ .size = 20*0x4000,
+ },
+ {
+ .name = "Kernel",
+ .offset = 0x60000,
+ .size = 256*0x4000,
+ },
+ {
+ .name = "Root File System",
+ .offset = 0x460000,
+ .size = 0,
+ },
};
/*
@@ -141,19 +157,37 @@ static struct mtd_partition partition_info_16KB_blk[] = {
* Size for "Root file system" is updated in driver based on actual device size
*/
static struct mtd_partition partition_info_128KB_blk[] = {
- PARTITION("X-loader", 0, 4 * 0x20000),
- PARTITION("U-Boot", 0x80000, 12 * 0x20000),
- PARTITION("Kernel", 0x200000, 48 * 0x20000),
- PARTITION("Root File System", 0x800000, 0),
+ {
+ .name = "X-loader",
+ .offset = 0,
+ .size = 4*0x20000,
+ },
+ {
+ .name = "U-Boot",
+ .offset = 0x80000,
+ .size = 12*0x20000,
+ },
+ {
+ .name = "Kernel",
+ .offset = 0x200000,
+ .size = 48*0x20000,
+ },
+ {
+ .name = "Root File System",
+ .offset = 0x800000,
+ .size = 0,
+ },
};
#ifdef CONFIG_MTD_CMDLINE_PARTS
const char *part_probes[] = { "cmdlinepart", NULL };
#endif
+#endif
/**
- * struct fsmc_nand_data - atructure for FSMC NAND device state
+ * struct fsmc_nand_data - structure for FSMC NAND device state
*
+ * @pid: Part ID on the AMBA PrimeCell format
* @mtd: MTD info for a NAND flash.
* @nand: Chip related info for a NAND flash.
* @partitions: Partition info for a NAND Flash.
@@ -169,6 +203,7 @@ const char *part_probes[] = { "cmdlinepart", NULL };
* @regs_va: FSMC regs base address.
*/
struct fsmc_nand_data {
+ u32 pid;
struct mtd_info mtd;
struct nand_chip nand;
struct mtd_partition *partitions;
@@ -508,7 +543,9 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
struct nand_chip *nand;
struct fsmc_regs *regs;
struct resource *res;
- int nr_parts, ret = 0;
+ int ret = 0;
+ u32 pid;
+ int i;
if (!pdata) {
dev_err(&pdev->dev, "platform data is NULL\n");
@@ -598,6 +635,18 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
if (ret)
goto err_probe1;
+ /*
+ * This device ID is actually a common AMBA ID as used on the
+ * AMBA PrimeCell bus. However it is not a PrimeCell.
+ */
+ for (pid = 0, i = 0; i < 4; i++)
+ pid |= (readl(host->regs_va + resource_size(res) - 0x20 + 4 * i) & 255) << (i * 8);
+ host->pid = pid;
+ dev_info(&pdev->dev, "FSMC device partno %03x, manufacturer %02x, "
+ "revision %02x, config %02x\n",
+ AMBA_PART_BITS(pid), AMBA_MANF_BITS(pid),
+ AMBA_REV_BITS(pid), AMBA_CONFIG_BITS(pid));
+
host->bank = pdata->bank;
host->select_chip = pdata->select_bank;
regs = host->regs_va;
@@ -625,7 +674,7 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
fsmc_nand_setup(regs, host->bank, nand->options & NAND_BUSWIDTH_16);
- if (get_fsmc_version(host->regs_va) == FSMC_VER8) {
+ if (AMBA_REV_BITS(host->pid) >= 8) {
nand->ecc.read_page = fsmc_read_page_hwecc;
nand->ecc.calculate = fsmc_read_hwecc_ecc4;
nand->ecc.correct = fsmc_correct_data;
@@ -645,7 +694,7 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
goto err_probe;
}
- if (get_fsmc_version(host->regs_va) == FSMC_VER8) {
+ if (AMBA_REV_BITS(host->pid) >= 8) {
if (host->mtd.writesize == 512) {
nand->ecc.layout = &fsmc_ecc4_sp_layout;
host->ecc_place = &fsmc_ecc4_sp_place;
@@ -676,11 +725,9 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
* Check if partition info passed via command line
*/
host->mtd.name = "nand";
- nr_parts = parse_mtd_partitions(&host->mtd, part_probes,
+ host->nr_partitions = parse_mtd_partitions(&host->mtd, part_probes,
&host->partitions, 0);
- if (nr_parts > 0) {
- host->nr_partitions = nr_parts;
- } else {
+ if (host->nr_partitions <= 0) {
#endif
/*
* Check if partition info passed via command line
diff --git a/drivers/mtd/nand/jz4740_nand.c b/drivers/mtd/nand/jz4740_nand.c
index 67343fc..cea38a5 100644
--- a/drivers/mtd/nand/jz4740_nand.c
+++ b/drivers/mtd/nand/jz4740_nand.c
@@ -251,58 +251,6 @@ static int jz_nand_correct_ecc_rs(struct mtd_info *mtd, uint8_t *dat,
return 0;
}
-
-/* Copy paste of nand_read_page_hwecc_oob_first except for different eccpos
- * handling. The ecc area is for 4k chips 72 bytes long and thus does not fit
- * into the eccpos array. */
-static int jz_nand_read_page_hwecc_oob_first(struct mtd_info *mtd,
- struct nand_chip *chip, uint8_t *buf, int page)
-{
- int i, eccsize = chip->ecc.size;
- int eccbytes = chip->ecc.bytes;
- int eccsteps = chip->ecc.steps;
- uint8_t *p = buf;
- unsigned int ecc_offset = chip->page_shift;
-
- /* Read the OOB area first */
- chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page);
- chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
- chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page);
-
- for (i = ecc_offset; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
- int stat;
-
- chip->ecc.hwctl(mtd, NAND_ECC_READ);
- chip->read_buf(mtd, p, eccsize);
-
- stat = chip->ecc.correct(mtd, p, &chip->oob_poi[i], NULL);
- if (stat < 0)
- mtd->ecc_stats.failed++;
- else
- mtd->ecc_stats.corrected += stat;
- }
- return 0;
-}
-
-/* Copy-and-paste of nand_write_page_hwecc with different eccpos handling. */
-static void jz_nand_write_page_hwecc(struct mtd_info *mtd,
- struct nand_chip *chip, const uint8_t *buf)
-{
- int i, eccsize = chip->ecc.size;
- int eccbytes = chip->ecc.bytes;
- int eccsteps = chip->ecc.steps;
- const uint8_t *p = buf;
- unsigned int ecc_offset = chip->page_shift;
-
- for (i = ecc_offset; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
- chip->ecc.hwctl(mtd, NAND_ECC_WRITE);
- chip->write_buf(mtd, p, eccsize);
- chip->ecc.calculate(mtd, p, &chip->oob_poi[i]);
- }
-
- chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
-}
-
#ifdef CONFIG_MTD_CMDLINE_PARTS
static const char *part_probes[] = {"cmdline", NULL};
#endif
@@ -393,9 +341,6 @@ static int __devinit jz_nand_probe(struct platform_device *pdev)
chip->ecc.size = 512;
chip->ecc.bytes = 9;
- chip->ecc.read_page = jz_nand_read_page_hwecc_oob_first;
- chip->ecc.write_page = jz_nand_write_page_hwecc;
-
if (pdata)
chip->ecc.layout = pdata->ecc_layout;
@@ -489,7 +434,7 @@ static int __devexit jz_nand_remove(struct platform_device *pdev)
return 0;
}
-struct platform_driver jz_nand_driver = {
+static struct platform_driver jz_nand_driver = {
.probe = jz_nand_probe,
.remove = __devexit_p(jz_nand_remove),
.driver = {
diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c
index 214b03a..ef932ba 100644
--- a/drivers/mtd/nand/mxc_nand.c
+++ b/drivers/mtd/nand/mxc_nand.c
@@ -1009,7 +1009,7 @@ static int __init mxcnd_probe(struct platform_device *pdev)
struct mxc_nand_platform_data *pdata = pdev->dev.platform_data;
struct mxc_nand_host *host;
struct resource *res;
- int err = 0, nr_parts = 0;
+ int err = 0, __maybe_unused nr_parts = 0;
struct nand_ecclayout *oob_smallpage, *oob_largepage;
/* Allocate memory for MTD device structure and private data */
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index 31bf376..a9c6ce7 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -2865,20 +2865,24 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip,
/* check version */
val = le16_to_cpu(p->revision);
- if (val == 1 || val > (1 << 4)) {
- printk(KERN_INFO "%s: unsupported ONFI version: %d\n",
- __func__, val);
- return 0;
- }
-
- if (val & (1 << 4))
+ if (val & (1 << 5))
+ chip->onfi_version = 23;
+ else if (val & (1 << 4))
chip->onfi_version = 22;
else if (val & (1 << 3))
chip->onfi_version = 21;
else if (val & (1 << 2))
chip->onfi_version = 20;
- else
+ else if (val & (1 << 1))
chip->onfi_version = 10;
+ else
+ chip->onfi_version = 0;
+
+ if (!chip->onfi_version) {
+ printk(KERN_INFO "%s: unsupported ONFI version: %d\n",
+ __func__, val);
+ return 0;
+ }
sanitize_string(p->manufacturer, sizeof(p->manufacturer));
sanitize_string(p->model, sizeof(p->model));
@@ -2887,7 +2891,7 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip,
mtd->writesize = le32_to_cpu(p->byte_per_page);
mtd->erasesize = le32_to_cpu(p->pages_per_block) * mtd->writesize;
mtd->oobsize = le16_to_cpu(p->spare_bytes_per_page);
- chip->chipsize = le32_to_cpu(p->blocks_per_lun) * mtd->erasesize;
+ chip->chipsize = (uint64_t)le32_to_cpu(p->blocks_per_lun) * mtd->erasesize;
busw = 0;
if (le16_to_cpu(p->features) & 1)
busw = NAND_BUSWIDTH_16;
@@ -3157,7 +3161,7 @@ ident_done:
printk(KERN_INFO "NAND device: Manufacturer ID:"
" 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id, *dev_id,
nand_manuf_ids[maf_idx].name,
- chip->onfi_version ? type->name : chip->onfi_params.model);
+ chip->onfi_version ? chip->onfi_params.model : type->name);
return type;
}
@@ -3435,6 +3439,7 @@ int nand_scan_tail(struct mtd_info *mtd)
mtd->resume = nand_resume;
mtd->block_isbad = nand_block_isbad;
mtd->block_markbad = nand_block_markbad;
+ mtd->writebufsize = mtd->writesize;
/* propagate ecc.layout to mtd_info */
mtd->ecclayout = chip->ecc.layout;
diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c
index 586b981..6ebd869 100644
--- a/drivers/mtd/nand/nand_bbt.c
+++ b/drivers/mtd/nand/nand_bbt.c
@@ -1092,7 +1092,8 @@ static void mark_bbt_region(struct mtd_info *mtd, struct nand_bbt_descr *td)
/**
* verify_bbt_descr - verify the bad block description
- * @bd: the table to verify
+ * @mtd: MTD device structure
+ * @bd: the table to verify
*
* This functions performs a few sanity checks on the bad block description
* table.
diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c
index a6a73aa..a5aa99f 100644
--- a/drivers/mtd/nand/nandsim.c
+++ b/drivers/mtd/nand/nandsim.c
@@ -210,12 +210,12 @@ MODULE_PARM_DESC(bbt, "0 OOB, 1 BBT with marker in OOB, 2 BBT with marker in d
#define STATE_CMD_READ0 0x00000001 /* read data from the beginning of page */
#define STATE_CMD_READ1 0x00000002 /* read data from the second half of page */
#define STATE_CMD_READSTART 0x00000003 /* read data second command (large page devices) */
-#define STATE_CMD_PAGEPROG 0x00000004 /* start page programm */
+#define STATE_CMD_PAGEPROG 0x00000004 /* start page program */
#define STATE_CMD_READOOB 0x00000005 /* read OOB area */
#define STATE_CMD_ERASE1 0x00000006 /* sector erase first command */
#define STATE_CMD_STATUS 0x00000007 /* read status */
#define STATE_CMD_STATUS_M 0x00000008 /* read multi-plane status (isn't implemented) */
-#define STATE_CMD_SEQIN 0x00000009 /* sequential data imput */
+#define STATE_CMD_SEQIN 0x00000009 /* sequential data input */
#define STATE_CMD_READID 0x0000000A /* read ID */
#define STATE_CMD_ERASE2 0x0000000B /* sector erase second command */
#define STATE_CMD_RESET 0x0000000C /* reset */
@@ -230,7 +230,7 @@ MODULE_PARM_DESC(bbt, "0 OOB, 1 BBT with marker in OOB, 2 BBT with marker in d
#define STATE_ADDR_ZERO 0x00000040 /* one byte zero address was accepted */
#define STATE_ADDR_MASK 0x00000070 /* address states mask */
-/* Durind data input/output the simulator is in these states */
+/* During data input/output the simulator is in these states */
#define STATE_DATAIN 0x00000100 /* waiting for data input */
#define STATE_DATAIN_MASK 0x00000100 /* data input states mask */
@@ -248,7 +248,7 @@ MODULE_PARM_DESC(bbt, "0 OOB, 1 BBT with marker in OOB, 2 BBT with marker in d
/* Simulator's actions bit masks */
#define ACTION_CPY 0x00100000 /* copy page/OOB to the internal buffer */
-#define ACTION_PRGPAGE 0x00200000 /* programm the internal buffer to flash */
+#define ACTION_PRGPAGE 0x00200000 /* program the internal buffer to flash */
#define ACTION_SECERASE 0x00300000 /* erase sector */
#define ACTION_ZEROOFF 0x00400000 /* don't add any offset to address */
#define ACTION_HALFOFF 0x00500000 /* add to address half of page */
@@ -263,18 +263,18 @@ MODULE_PARM_DESC(bbt, "0 OOB, 1 BBT with marker in OOB, 2 BBT with marker in d
#define OPT_PAGE512 0x00000002 /* 512-byte page chips */
#define OPT_PAGE2048 0x00000008 /* 2048-byte page chips */
#define OPT_SMARTMEDIA 0x00000010 /* SmartMedia technology chips */
-#define OPT_AUTOINCR 0x00000020 /* page number auto inctimentation is possible */
+#define OPT_AUTOINCR 0x00000020 /* page number auto incrementation is possible */
#define OPT_PAGE512_8BIT 0x00000040 /* 512-byte page chips with 8-bit bus width */
#define OPT_PAGE4096 0x00000080 /* 4096-byte page chips */
#define OPT_LARGEPAGE (OPT_PAGE2048 | OPT_PAGE4096) /* 2048 & 4096-byte page chips */
#define OPT_SMALLPAGE (OPT_PAGE256 | OPT_PAGE512) /* 256 and 512-byte page chips */
-/* Remove action bits ftom state */
+/* Remove action bits from state */
#define NS_STATE(x) ((x) & ~ACTION_MASK)
/*
* Maximum previous states which need to be saved. Currently saving is
- * only needed for page programm operation with preceeded read command
+ * only needed for page program operation with preceded read command
* (which is only valid for 512-byte pages).
*/
#define NS_MAX_PREVSTATES 1
@@ -380,16 +380,16 @@ static struct nandsim_operations {
/* Read OOB */
{OPT_SMALLPAGE, {STATE_CMD_READOOB | ACTION_OOBOFF, STATE_ADDR_PAGE | ACTION_CPY,
STATE_DATAOUT, STATE_READY}},
- /* Programm page starting from the beginning */
+ /* Program page starting from the beginning */
{OPT_ANY, {STATE_CMD_SEQIN, STATE_ADDR_PAGE, STATE_DATAIN,
STATE_CMD_PAGEPROG | ACTION_PRGPAGE, STATE_READY}},
- /* Programm page starting from the beginning */
+ /* Program page starting from the beginning */
{OPT_SMALLPAGE, {STATE_CMD_READ0, STATE_CMD_SEQIN | ACTION_ZEROOFF, STATE_ADDR_PAGE,
STATE_DATAIN, STATE_CMD_PAGEPROG | ACTION_PRGPAGE, STATE_READY}},
- /* Programm page starting from the second half */
+ /* Program page starting from the second half */
{OPT_PAGE512, {STATE_CMD_READ1, STATE_CMD_SEQIN | ACTION_HALFOFF, STATE_ADDR_PAGE,
STATE_DATAIN, STATE_CMD_PAGEPROG | ACTION_PRGPAGE, STATE_READY}},
- /* Programm OOB */
+ /* Program OOB */
{OPT_SMALLPAGE, {STATE_CMD_READOOB, STATE_CMD_SEQIN | ACTION_OOBOFF, STATE_ADDR_PAGE,
STATE_DATAIN, STATE_CMD_PAGEPROG | ACTION_PRGPAGE, STATE_READY}},
/* Erase sector */
@@ -470,7 +470,7 @@ static int alloc_device(struct nandsim *ns)
err = -EINVAL;
goto err_close;
}
- ns->pages_written = vmalloc(ns->geom.pgnum);
+ ns->pages_written = vzalloc(ns->geom.pgnum);
if (!ns->pages_written) {
NS_ERR("alloc_device: unable to allocate pages written array\n");
err = -ENOMEM;
@@ -483,7 +483,6 @@ static int alloc_device(struct nandsim *ns)
goto err_free;
}
ns->cfile = cfile;
- memset(ns->pages_written, 0, ns->geom.pgnum);
return 0;
}
@@ -1171,9 +1170,9 @@ static inline void switch_to_ready_state(struct nandsim *ns, u_char status)
* of supported operations.
*
* Operation can be unknown because of the following.
- * 1. New command was accepted and this is the firs call to find the
+ * 1. New command was accepted and this is the first call to find the
* correspondent states chain. In this case ns->npstates = 0;
- * 2. There is several operations which begin with the same command(s)
+ * 2. There are several operations which begin with the same command(s)
* (for example program from the second half and read from the
* second half operations both begin with the READ1 command). In this
* case the ns->pstates[] array contains previous states.
@@ -1186,7 +1185,7 @@ static inline void switch_to_ready_state(struct nandsim *ns, u_char status)
* ns->ops, ns->state, ns->nxstate are initialized, ns->npstate is
* zeroed).
*
- * If there are several maches, the current state is pushed to the
+ * If there are several matches, the current state is pushed to the
* ns->pstates.
*
* The operation can be unknown only while commands are input to the chip.
@@ -1195,10 +1194,10 @@ static inline void switch_to_ready_state(struct nandsim *ns, u_char status)
* operation is searched using the following pattern:
* ns->pstates[0], ... ns->pstates[ns->npstates], <address input>
*
- * It is supposed that this pattern must either match one operation on
+ * It is supposed that this pattern must either match one operation or
* none. There can't be ambiguity in that case.
*
- * If no matches found, the functions does the following:
+ * If no matches found, the function does the following:
* 1. if there are saved states present, try to ignore them and search
* again only using the last command. If nothing was found, switch
* to the STATE_READY state.
@@ -1668,7 +1667,7 @@ static int do_state_action(struct nandsim *ns, uint32_t action)
case ACTION_PRGPAGE:
/*
- * Programm page - move internal buffer data to the page.
+ * Program page - move internal buffer data to the page.
*/
if (ns->lines.wp) {
@@ -1933,7 +1932,7 @@ static u_char ns_nand_read_byte(struct mtd_info *mtd)
NS_DBG("read_byte: all bytes were read\n");
/*
- * The OPT_AUTOINCR allows to read next conseqitive pages without
+ * The OPT_AUTOINCR allows to read next consecutive pages without
* new read operation cycle.
*/
if ((ns->options & OPT_AUTOINCR) && NS_STATE(ns->state) == STATE_DATAOUT) {
diff --git a/drivers/mtd/nand/pasemi_nand.c b/drivers/mtd/nand/pasemi_nand.c
index 6ddb246..bb277a5 100644
--- a/drivers/mtd/nand/pasemi_nand.c
+++ b/drivers/mtd/nand/pasemi_nand.c
@@ -107,7 +107,7 @@ static int __devinit pasemi_nand_probe(struct platform_device *ofdev,
if (pasemi_nand_mtd)
return -ENODEV;
- pr_debug("pasemi_nand at %llx-%llx\n", res.start, res.end);
+ pr_debug("pasemi_nand at %pR\n", &res);
/* Allocate memory for MTD device structure and private data */
pasemi_nand_mtd = kzalloc(sizeof(struct mtd_info) +
diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c
index 17f8518..ea2c288 100644
--- a/drivers/mtd/nand/pxa3xx_nand.c
+++ b/drivers/mtd/nand/pxa3xx_nand.c
@@ -885,6 +885,7 @@ static int pxa3xx_nand_detect_config(struct pxa3xx_nand_info *info)
/* set info fields needed to __readid */
info->read_id_bytes = (info->page_size == 2048) ? 4 : 2;
info->reg_ndcr = ndcr;
+ info->cmdset = &default_cmdset;
if (__readid(info, &id))
return -ENODEV;
@@ -915,7 +916,6 @@ static int pxa3xx_nand_detect_config(struct pxa3xx_nand_info *info)
info->ndtr0cs0 = nand_readl(info, NDTR0CS0);
info->ndtr1cs0 = nand_readl(info, NDTR1CS0);
- info->cmdset = &default_cmdset;
return 0;
}
diff --git a/drivers/mtd/nand/txx9ndfmc.c b/drivers/mtd/nand/txx9ndfmc.c
index 054a41c..ca270a4 100644
--- a/drivers/mtd/nand/txx9ndfmc.c
+++ b/drivers/mtd/nand/txx9ndfmc.c
@@ -277,8 +277,9 @@ static int txx9ndfmc_nand_scan(struct mtd_info *mtd)
ret = nand_scan_ident(mtd, 1, NULL);
if (!ret) {
if (mtd->writesize >= 512) {
- chip->ecc.size = mtd->writesize;
- chip->ecc.bytes = 3 * (mtd->writesize / 256);
+ /* Hardware ECC 6 byte ECC per 512 Byte data */
+ chip->ecc.size = 512;
+ chip->ecc.bytes = 6;
}
ret = nand_scan_tail(mtd);
}
diff --git a/drivers/mtd/onenand/omap2.c b/drivers/mtd/onenand/omap2.c
index d0894ca7..ac31f46 100644
--- a/drivers/mtd/onenand/omap2.c
+++ b/drivers/mtd/onenand/omap2.c
@@ -35,6 +35,7 @@
#include <linux/dma-mapping.h>
#include <linux/io.h>
#include <linux/slab.h>
+#include <linux/regulator/consumer.h>
#include <asm/mach/flash.h>
#include <plat/gpmc.h>
@@ -63,8 +64,13 @@ struct omap2_onenand {
int dma_channel;
int freq;
int (*setup)(void __iomem *base, int freq);
+ struct regulator *regulator;
};
+#ifdef CONFIG_MTD_PARTITIONS
+static const char *part_probes[] = { "cmdlinepart", NULL, };
+#endif
+
static void omap2_onenand_dma_cb(int lch, u16 ch_status, void *data)
{
struct omap2_onenand *c = data;
@@ -108,8 +114,9 @@ static void wait_warn(char *msg, int state, unsigned int ctrl,
static int omap2_onenand_wait(struct mtd_info *mtd, int state)
{
struct omap2_onenand *c = container_of(mtd, struct omap2_onenand, mtd);
+ struct onenand_chip *this = mtd->priv;
unsigned int intr = 0;
- unsigned int ctrl;
+ unsigned int ctrl, ctrl_mask;
unsigned long timeout;
u32 syscfg;
@@ -180,7 +187,8 @@ retry:
if (result == 0) {
/* Timeout after 20ms */
ctrl = read_reg(c, ONENAND_REG_CTRL_STATUS);
- if (ctrl & ONENAND_CTRL_ONGO) {
+ if (ctrl & ONENAND_CTRL_ONGO &&
+ !this->ongoing) {
/*
* The operation seems to be still going
* so give it some more time.
@@ -269,7 +277,11 @@ retry:
return -EIO;
}
- if (ctrl & 0xFE9F)
+ ctrl_mask = 0xFE9F;
+ if (this->ongoing)
+ ctrl_mask &= ~0x8000;
+
+ if (ctrl & ctrl_mask)
wait_warn("unexpected controller status", state, ctrl, intr);
return 0;
@@ -591,6 +603,30 @@ static void omap2_onenand_shutdown(struct platform_device *pdev)
memset((__force void *)c->onenand.base, 0, ONENAND_BUFRAM_SIZE);
}
+static int omap2_onenand_enable(struct mtd_info *mtd)
+{
+ int ret;
+ struct omap2_onenand *c = container_of(mtd, struct omap2_onenand, mtd);
+
+ ret = regulator_enable(c->regulator);
+ if (ret != 0)
+ dev_err(&c->pdev->dev, "cant enable regulator\n");
+
+ return ret;
+}
+
+static int omap2_onenand_disable(struct mtd_info *mtd)
+{
+ int ret;
+ struct omap2_onenand *c = container_of(mtd, struct omap2_onenand, mtd);
+
+ ret = regulator_disable(c->regulator);
+ if (ret != 0)
+ dev_err(&c->pdev->dev, "cant disable regulator\n");
+
+ return ret;
+}
+
static int __devinit omap2_onenand_probe(struct platform_device *pdev)
{
struct omap_onenand_platform_data *pdata;
@@ -705,8 +741,18 @@ static int __devinit omap2_onenand_probe(struct platform_device *pdev)
}
}
+ if (pdata->regulator_can_sleep) {
+ c->regulator = regulator_get(&pdev->dev, "vonenand");
+ if (IS_ERR(c->regulator)) {
+ dev_err(&pdev->dev, "Failed to get regulator\n");
+ goto err_release_dma;
+ }
+ c->onenand.enable = omap2_onenand_enable;
+ c->onenand.disable = omap2_onenand_disable;
+ }
+
if ((r = onenand_scan(&c->mtd, 1)) < 0)
- goto err_release_dma;
+ goto err_release_regulator;
switch ((c->onenand.version_id >> 4) & 0xf) {
case 0:
@@ -727,13 +773,15 @@ static int __devinit omap2_onenand_probe(struct platform_device *pdev)
}
#ifdef CONFIG_MTD_PARTITIONS
- if (pdata->parts != NULL)
- r = add_mtd_partitions(&c->mtd, pdata->parts,
- pdata->nr_parts);
+ r = parse_mtd_partitions(&c->mtd, part_probes, &c->parts, 0);
+ if (r > 0)
+ r = add_mtd_partitions(&c->mtd, c->parts, r);
+ else if (pdata->parts != NULL)
+ r = add_mtd_partitions(&c->mtd, pdata->parts, pdata->nr_parts);
else
#endif
r = add_mtd_device(&c->mtd);
- if (r < 0)
+ if (r)
goto err_release_onenand;
platform_set_drvdata(pdev, c);
@@ -742,6 +790,8 @@ static int __devinit omap2_onenand_probe(struct platform_device *pdev)
err_release_onenand:
onenand_release(&c->mtd);
+err_release_regulator:
+ regulator_put(c->regulator);
err_release_dma:
if (c->dma_channel != -1)
omap_free_dma(c->dma_channel);
@@ -757,6 +807,7 @@ err_release_mem_region:
err_free_cs:
gpmc_cs_free(c->gpmc_cs);
err_kfree:
+ kfree(c->parts);
kfree(c);
return r;
@@ -766,18 +817,8 @@ static int __devexit omap2_onenand_remove(struct platform_device *pdev)
{
struct omap2_onenand *c = dev_get_drvdata(&pdev->dev);
- BUG_ON(c == NULL);
-
-#ifdef CONFIG_MTD_PARTITIONS
- if (c->parts)
- del_mtd_partitions(&c->mtd);
- else
- del_mtd_device(&c->mtd);
-#else
- del_mtd_device(&c->mtd);
-#endif
-
onenand_release(&c->mtd);
+ regulator_put(c->regulator);
if (c->dma_channel != -1)
omap_free_dma(c->dma_channel);
omap2_onenand_shutdown(pdev);
@@ -789,6 +830,7 @@ static int __devexit omap2_onenand_remove(struct platform_device *pdev)
iounmap(c->onenand.base);
release_mem_region(c->phys_base, ONENAND_IO_SIZE);
gpmc_cs_free(c->gpmc_cs);
+ kfree(c->parts);
kfree(c);
return 0;
diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c
index 6b3a875..bac41ca 100644
--- a/drivers/mtd/onenand/onenand_base.c
+++ b/drivers/mtd/onenand/onenand_base.c
@@ -400,8 +400,7 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, size_t le
value = onenand_bufferram_address(this, block);
this->write_word(value, this->base + ONENAND_REG_START_ADDRESS2);
- if (ONENAND_IS_MLC(this) || ONENAND_IS_2PLANE(this) ||
- ONENAND_IS_4KB_PAGE(this))
+ if (ONENAND_IS_2PLANE(this) || ONENAND_IS_4KB_PAGE(this))
/* It is always BufferRAM0 */
ONENAND_SET_BUFFERRAM0(this);
else
@@ -430,7 +429,7 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, size_t le
case FLEXONENAND_CMD_RECOVER_LSB:
case ONENAND_CMD_READ:
case ONENAND_CMD_READOOB:
- if (ONENAND_IS_MLC(this) || ONENAND_IS_4KB_PAGE(this))
+ if (ONENAND_IS_4KB_PAGE(this))
/* It is always BufferRAM0 */
dataram = ONENAND_SET_BUFFERRAM0(this);
else
@@ -949,6 +948,8 @@ static int onenand_get_device(struct mtd_info *mtd, int new_state)
if (this->state == FL_READY) {
this->state = new_state;
spin_unlock(&this->chip_lock);
+ if (new_state != FL_PM_SUSPENDED && this->enable)
+ this->enable(mtd);
break;
}
if (new_state == FL_PM_SUSPENDED) {
@@ -975,6 +976,8 @@ static void onenand_release_device(struct mtd_info *mtd)
{
struct onenand_chip *this = mtd->priv;
+ if (this->state != FL_PM_SUSPENDED && this->disable)
+ this->disable(mtd);
/* Release the chip */
spin_lock(&this->chip_lock);
this->state = FL_READY;
@@ -1353,7 +1356,7 @@ static int onenand_read_oob_nolock(struct mtd_info *mtd, loff_t from,
stats = mtd->ecc_stats;
- readcmd = ONENAND_IS_MLC(this) ? ONENAND_CMD_READ : ONENAND_CMD_READOOB;
+ readcmd = ONENAND_IS_4KB_PAGE(this) ? ONENAND_CMD_READ : ONENAND_CMD_READOOB;
while (read < len) {
cond_resched();
@@ -1429,7 +1432,7 @@ static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len,
int ret;
onenand_get_device(mtd, FL_READING);
- ret = ONENAND_IS_MLC(this) || ONENAND_IS_4KB_PAGE(this) ?
+ ret = ONENAND_IS_4KB_PAGE(this) ?
onenand_mlc_read_ops_nolock(mtd, from, &ops) :
onenand_read_ops_nolock(mtd, from, &ops);
onenand_release_device(mtd);
@@ -1464,7 +1467,7 @@ static int onenand_read_oob(struct mtd_info *mtd, loff_t from,
onenand_get_device(mtd, FL_READING);
if (ops->datbuf)
- ret = ONENAND_IS_MLC(this) || ONENAND_IS_4KB_PAGE(this) ?
+ ret = ONENAND_IS_4KB_PAGE(this) ?
onenand_mlc_read_ops_nolock(mtd, from, ops) :
onenand_read_ops_nolock(mtd, from, ops);
else
@@ -1485,8 +1488,7 @@ static int onenand_bbt_wait(struct mtd_info *mtd, int state)
{
struct onenand_chip *this = mtd->priv;
unsigned long timeout;
- unsigned int interrupt;
- unsigned int ctrl;
+ unsigned int interrupt, ctrl, ecc, addr1, addr8;
/* The 20 msec is enough */
timeout = jiffies + msecs_to_jiffies(20);
@@ -1498,25 +1500,28 @@ static int onenand_bbt_wait(struct mtd_info *mtd, int state)
/* To get correct interrupt status in timeout case */
interrupt = this->read_word(this->base + ONENAND_REG_INTERRUPT);
ctrl = this->read_word(this->base + ONENAND_REG_CTRL_STATUS);
+ addr1 = this->read_word(this->base + ONENAND_REG_START_ADDRESS1);
+ addr8 = this->read_word(this->base + ONENAND_REG_START_ADDRESS8);
if (interrupt & ONENAND_INT_READ) {
- int ecc = onenand_read_ecc(this);
+ ecc = onenand_read_ecc(this);
if (ecc & ONENAND_ECC_2BIT_ALL) {
- printk(KERN_WARNING "%s: ecc error = 0x%04x, "
- "controller error 0x%04x\n",
- __func__, ecc, ctrl);
+ printk(KERN_DEBUG "%s: ecc 0x%04x ctrl 0x%04x "
+ "intr 0x%04x addr1 %#x addr8 %#x\n",
+ __func__, ecc, ctrl, interrupt, addr1, addr8);
return ONENAND_BBT_READ_ECC_ERROR;
}
} else {
- printk(KERN_ERR "%s: read timeout! ctrl=0x%04x intr=0x%04x\n",
- __func__, ctrl, interrupt);
+ printk(KERN_ERR "%s: read timeout! ctrl 0x%04x "
+ "intr 0x%04x addr1 %#x addr8 %#x\n",
+ __func__, ctrl, interrupt, addr1, addr8);
return ONENAND_BBT_READ_FATAL_ERROR;
}
/* Initial bad block case: 0x2400 or 0x0400 */
if (ctrl & ONENAND_CTRL_ERROR) {
- printk(KERN_DEBUG "%s: controller error = 0x%04x\n",
- __func__, ctrl);
+ printk(KERN_DEBUG "%s: ctrl 0x%04x intr 0x%04x addr1 %#x "
+ "addr8 %#x\n", __func__, ctrl, interrupt, addr1, addr8);
return ONENAND_BBT_READ_ERROR;
}
@@ -1558,7 +1563,7 @@ int onenand_bbt_read_oob(struct mtd_info *mtd, loff_t from,
column = from & (mtd->oobsize - 1);
- readcmd = ONENAND_IS_MLC(this) ? ONENAND_CMD_READ : ONENAND_CMD_READOOB;
+ readcmd = ONENAND_IS_4KB_PAGE(this) ? ONENAND_CMD_READ : ONENAND_CMD_READOOB;
while (read < len) {
cond_resched();
@@ -1612,7 +1617,7 @@ static int onenand_verify_oob(struct mtd_info *mtd, const u_char *buf, loff_t to
u_char *oob_buf = this->oob_buf;
int status, i, readcmd;
- readcmd = ONENAND_IS_MLC(this) ? ONENAND_CMD_READ : ONENAND_CMD_READOOB;
+ readcmd = ONENAND_IS_4KB_PAGE(this) ? ONENAND_CMD_READ : ONENAND_CMD_READOOB;
this->command(mtd, readcmd, to, mtd->oobsize);
onenand_update_bufferram(mtd, to, 0);
@@ -1845,7 +1850,7 @@ static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to,
const u_char *buf = ops->datbuf;
const u_char *oob = ops->oobbuf;
u_char *oobbuf;
- int ret = 0;
+ int ret = 0, cmd;
DEBUG(MTD_DEBUG_LEVEL3, "%s: to = 0x%08x, len = %i\n",
__func__, (unsigned int) to, (int) len);
@@ -1954,7 +1959,19 @@ static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to,
ONENAND_SET_NEXT_BUFFERRAM(this);
}
- this->command(mtd, ONENAND_CMD_PROG, to, mtd->writesize);
+ this->ongoing = 0;
+ cmd = ONENAND_CMD_PROG;
+
+ /* Exclude 1st OTP and OTP blocks for cache program feature */
+ if (ONENAND_IS_CACHE_PROGRAM(this) &&
+ likely(onenand_block(this, to) != 0) &&
+ ONENAND_IS_4KB_PAGE(this) &&
+ ((written + thislen) < len)) {
+ cmd = ONENAND_CMD_2X_CACHE_PROG;
+ this->ongoing = 1;
+ }
+
+ this->command(mtd, cmd, to, mtd->writesize);
/*
* 2 PLANE, MLC, and Flex-OneNAND wait here
@@ -2067,7 +2084,7 @@ static int onenand_write_oob_nolock(struct mtd_info *mtd, loff_t to,
oobbuf = this->oob_buf;
- oobcmd = ONENAND_IS_MLC(this) ? ONENAND_CMD_PROG : ONENAND_CMD_PROGOOB;
+ oobcmd = ONENAND_IS_4KB_PAGE(this) ? ONENAND_CMD_PROG : ONENAND_CMD_PROGOOB;
/* Loop until all data write */
while (written < len) {
@@ -2086,7 +2103,7 @@ static int onenand_write_oob_nolock(struct mtd_info *mtd, loff_t to,
memcpy(oobbuf + column, buf, thislen);
this->write_bufferram(mtd, ONENAND_SPARERAM, oobbuf, 0, mtd->oobsize);
- if (ONENAND_IS_MLC(this) || ONENAND_IS_4KB_PAGE(this)) {
+ if (ONENAND_IS_4KB_PAGE(this)) {
/* Set main area of DataRAM to 0xff*/
memset(this->page_buf, 0xff, mtd->writesize);
this->write_bufferram(mtd, ONENAND_DATARAM,
@@ -2481,7 +2498,8 @@ static int onenand_erase(struct mtd_info *mtd, struct erase_info *instr)
/* Grab the lock and see if the device is available */
onenand_get_device(mtd, FL_ERASING);
- if (region || instr->len < MB_ERASE_MIN_BLK_COUNT * block_size) {
+ if (ONENAND_IS_4KB_PAGE(this) || region ||
+ instr->len < MB_ERASE_MIN_BLK_COUNT * block_size) {
/* region is set for Flex-OneNAND (no mb erase) */
ret = onenand_block_by_block_erase(mtd, instr,
region, block_size);
@@ -3029,7 +3047,7 @@ static int do_otp_read(struct mtd_info *mtd, loff_t from, size_t len,
this->command(mtd, ONENAND_CMD_OTP_ACCESS, 0, 0);
this->wait(mtd, FL_OTPING);
- ret = ONENAND_IS_MLC(this) || ONENAND_IS_4KB_PAGE(this) ?
+ ret = ONENAND_IS_4KB_PAGE(this) ?
onenand_mlc_read_ops_nolock(mtd, from, &ops) :
onenand_read_ops_nolock(mtd, from, &ops);
@@ -3377,8 +3395,10 @@ static void onenand_check_features(struct mtd_info *mtd)
case ONENAND_DEVICE_DENSITY_4Gb:
if (ONENAND_IS_DDP(this))
this->options |= ONENAND_HAS_2PLANE;
- else if (numbufs == 1)
+ else if (numbufs == 1) {
this->options |= ONENAND_HAS_4KB_PAGE;
+ this->options |= ONENAND_HAS_CACHE_PROGRAM;
+ }
case ONENAND_DEVICE_DENSITY_2Gb:
/* 2Gb DDP does not have 2 plane */
@@ -3399,7 +3419,11 @@ static void onenand_check_features(struct mtd_info *mtd)
break;
}
- if (ONENAND_IS_MLC(this) || ONENAND_IS_4KB_PAGE(this))
+ /* The MLC has 4KiB pagesize. */
+ if (ONENAND_IS_MLC(this))
+ this->options |= ONENAND_HAS_4KB_PAGE;
+
+ if (ONENAND_IS_4KB_PAGE(this))
this->options &= ~ONENAND_HAS_2PLANE;
if (FLEXONENAND(this)) {
@@ -3415,6 +3439,8 @@ static void onenand_check_features(struct mtd_info *mtd)
printk(KERN_DEBUG "Chip has 2 plane\n");
if (this->options & ONENAND_HAS_4KB_PAGE)
printk(KERN_DEBUG "Chip has 4KiB pagesize\n");
+ if (this->options & ONENAND_HAS_CACHE_PROGRAM)
+ printk(KERN_DEBUG "Chip has cache program feature\n");
}
/**
@@ -3831,7 +3857,7 @@ static int onenand_probe(struct mtd_info *mtd)
/* The data buffer size is equal to page size */
mtd->writesize = this->read_word(this->base + ONENAND_REG_DATA_BUFFER_SIZE);
/* We use the full BufferRAM */
- if (ONENAND_IS_MLC(this) || ONENAND_IS_4KB_PAGE(this))
+ if (ONENAND_IS_4KB_PAGE(this))
mtd->writesize <<= 1;
mtd->oobsize = mtd->writesize >> 5;
@@ -4054,6 +4080,7 @@ int onenand_scan(struct mtd_info *mtd, int maxchips)
mtd->block_isbad = onenand_block_isbad;
mtd->block_markbad = onenand_block_markbad;
mtd->owner = THIS_MODULE;
+ mtd->writebufsize = mtd->writesize;
/* Unlock whole block */
this->unlock_all(mtd);
diff --git a/drivers/mtd/onenand/onenand_bbt.c b/drivers/mtd/onenand/onenand_bbt.c
index 01ab5b3..fc2c16a 100644
--- a/drivers/mtd/onenand/onenand_bbt.c
+++ b/drivers/mtd/onenand/onenand_bbt.c
@@ -91,16 +91,18 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr
for (j = 0; j < len; j++) {
/* No need to read pages fully,
* just read required OOB bytes */
- ret = onenand_bbt_read_oob(mtd, from + j * mtd->writesize + bd->offs, &ops);
+ ret = onenand_bbt_read_oob(mtd,
+ from + j * this->writesize + bd->offs, &ops);
/* If it is a initial bad block, just ignore it */
if (ret == ONENAND_BBT_READ_FATAL_ERROR)
return -EIO;
- if (ret || check_short_pattern(&buf[j * scanlen], scanlen, mtd->writesize, bd)) {
+ if (ret || check_short_pattern(&buf[j * scanlen],
+ scanlen, this->writesize, bd)) {
bbm->bbt[i >> 3] |= 0x03 << (i & 0x6);
- printk(KERN_WARNING "Bad eraseblock %d at 0x%08x\n",
- i >> 1, (unsigned int) from);
+ printk(KERN_INFO "OneNAND eraseblock %d is an "
+ "initial bad block\n", i >> 1);
mtd->ecc_stats.badblocks++;
break;
}
diff --git a/drivers/mtd/onenand/samsung.c b/drivers/mtd/onenand/samsung.c
index 0de7a05..a4c74a9 100644
--- a/drivers/mtd/onenand/samsung.c
+++ b/drivers/mtd/onenand/samsung.c
@@ -651,7 +651,7 @@ static int s5pc110_read_bufferram(struct mtd_info *mtd, int area,
void __iomem *p;
void *buf = (void *) buffer;
dma_addr_t dma_src, dma_dst;
- int err, page_dma = 0;
+ int err, ofs, page_dma = 0;
struct device *dev = &onenand->pdev->dev;
p = this->base + area;
@@ -677,10 +677,13 @@ static int s5pc110_read_bufferram(struct mtd_info *mtd, int area,
if (!page)
goto normal;
+ /* Page offset */
+ ofs = ((size_t) buf & ~PAGE_MASK);
page_dma = 1;
+
/* DMA routine */
dma_src = onenand->phys_base + (p - this->base);
- dma_dst = dma_map_page(dev, page, 0, count, DMA_FROM_DEVICE);
+ dma_dst = dma_map_page(dev, page, ofs, count, DMA_FROM_DEVICE);
} else {
/* DMA routine */
dma_src = onenand->phys_base + (p - this->base);
diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c
index 5ebe280..f49e49d 100644
--- a/drivers/mtd/ubi/build.c
+++ b/drivers/mtd/ubi/build.c
@@ -672,7 +672,33 @@ static int io_init(struct ubi_device *ubi)
ubi->nor_flash = 1;
}
- ubi->min_io_size = ubi->mtd->writesize;
+ /*
+ * Set UBI min. I/O size (@ubi->min_io_size). We use @mtd->writebufsize
+ * for these purposes, not @mtd->writesize. At the moment this does not
+ * matter for NAND, because currently @mtd->writebufsize is equivalent to
+ * @mtd->writesize for all NANDs. However, some CFI NOR flashes may
+ * have @mtd->writebufsize which is multiple of @mtd->writesize.
+ *
+ * The reason we use @mtd->writebufsize for @ubi->min_io_size is that
+ * UBI and UBIFS recovery algorithms rely on the fact that if there was
+ * an unclean power cut, then we can find offset of the last corrupted
+ * node, align the offset to @ubi->min_io_size, read the rest of the
+ * eraseblock starting from this offset, and check whether there are
+ * only 0xFF bytes. If yes, then we are probably dealing with a
+ * corruption caused by a power cut, if not, then this is probably some
+ * severe corruption.
+ *
+ * Thus, we have to use the maximum write unit size of the flash, which
+ * is @mtd->writebufsize, because @mtd->writesize is the minimum write
+ * size, not the maximum.
+ */
+ if (ubi->mtd->type == MTD_NANDFLASH)
+ ubi_assert(ubi->mtd->writebufsize == ubi->mtd->writesize);
+ else if (ubi->mtd->type == MTD_NORFLASH)
+ ubi_assert(ubi->mtd->writebufsize % ubi->mtd->writesize == 0);
+
+ ubi->min_io_size = ubi->mtd->writebufsize;
+
ubi->hdrs_min_io_size = ubi->mtd->writesize >> ubi->mtd->subpage_sft;
/*
diff --git a/drivers/mtd/ubi/vtbl.c b/drivers/mtd/ubi/vtbl.c
index fcdb7f6..0b8141f 100644
--- a/drivers/mtd/ubi/vtbl.c
+++ b/drivers/mtd/ubi/vtbl.c
@@ -425,12 +425,11 @@ static struct ubi_vtbl_record *process_lvol(struct ubi_device *ubi,
/* Read both LEB 0 and LEB 1 into memory */
ubi_rb_for_each_entry(rb, seb, &sv->root, u.rb) {
- leb[seb->lnum] = vmalloc(ubi->vtbl_size);
+ leb[seb->lnum] = vzalloc(ubi->vtbl_size);
if (!leb[seb->lnum]) {
err = -ENOMEM;
goto out_free;
}
- memset(leb[seb->lnum], 0, ubi->vtbl_size);
err = ubi_io_read_data(ubi, leb[seb->lnum], seb->pnum, 0,
ubi->vtbl_size);
@@ -516,10 +515,9 @@ static struct ubi_vtbl_record *create_empty_lvol(struct ubi_device *ubi,
int i;
struct ubi_vtbl_record *vtbl;
- vtbl = vmalloc(ubi->vtbl_size);
+ vtbl = vzalloc(ubi->vtbl_size);
if (!vtbl)
return ERR_PTR(-ENOMEM);
- memset(vtbl, 0, ubi->vtbl_size);
for (i = 0; i < ubi->vtbl_slots; i++)
memcpy(&vtbl[i], &empty_vtbl_record, UBI_VTBL_RECORD_SIZE);
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 4c8bfc9..0382332 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -2864,7 +2864,7 @@ config MLX4_CORE
default n
config MLX4_DEBUG
- bool "Verbose debugging output" if (MLX4_CORE && EMBEDDED)
+ bool "Verbose debugging output" if (MLX4_CORE && EXPERT)
depends on MLX4_CORE
default y
---help---
@@ -3389,8 +3389,7 @@ config NETCONSOLE
config NETCONSOLE_DYNAMIC
bool "Dynamic reconfiguration of logging targets"
- depends on NETCONSOLE && SYSFS
- select CONFIGFS_FS
+ depends on NETCONSOLE && SYSFS && CONFIGFS_FS
help
This option enables the ability to dynamically reconfigure target
parameters (interface, IP addresses, port numbers, MAC addresses)
diff --git a/drivers/net/arm/ks8695net.c b/drivers/net/arm/ks8695net.c
index 54c6d84..aa07657 100644
--- a/drivers/net/arm/ks8695net.c
+++ b/drivers/net/arm/ks8695net.c
@@ -854,12 +854,12 @@ ks8695_set_msglevel(struct net_device *ndev, u32 value)
}
/**
- * ks8695_get_settings - Get device-specific settings.
+ * ks8695_wan_get_settings - Get device-specific settings.
* @ndev: The network device to read settings from
* @cmd: The ethtool structure to read into
*/
static int
-ks8695_get_settings(struct net_device *ndev, struct ethtool_cmd *cmd)
+ks8695_wan_get_settings(struct net_device *ndev, struct ethtool_cmd *cmd)
{
struct ks8695_priv *ksp = netdev_priv(ndev);
u32 ctrl;
@@ -870,69 +870,50 @@ ks8695_get_settings(struct net_device *ndev, struct ethtool_cmd *cmd)
SUPPORTED_TP | SUPPORTED_MII);
cmd->transceiver = XCVR_INTERNAL;
- /* Port specific extras */
- switch (ksp->dtype) {
- case KS8695_DTYPE_HPNA:
- cmd->phy_address = 0;
- /* not supported for HPNA */
- cmd->autoneg = AUTONEG_DISABLE;
+ cmd->advertising = ADVERTISED_TP | ADVERTISED_MII;
+ cmd->port = PORT_MII;
+ cmd->supported |= (SUPPORTED_Autoneg | SUPPORTED_Pause);
+ cmd->phy_address = 0;
- /* BUG: Erm, dtype hpna implies no phy regs */
- /*
- ctrl = readl(KS8695_MISC_VA + KS8695_HMC);
- cmd->speed = (ctrl & HMC_HSS) ? SPEED_100 : SPEED_10;
- cmd->duplex = (ctrl & HMC_HDS) ? DUPLEX_FULL : DUPLEX_HALF;
- */
- return -EOPNOTSUPP;
- case KS8695_DTYPE_WAN:
- cmd->advertising = ADVERTISED_TP | ADVERTISED_MII;
- cmd->port = PORT_MII;
- cmd->supported |= (SUPPORTED_Autoneg | SUPPORTED_Pause);
- cmd->phy_address = 0;
+ ctrl = readl(ksp->phyiface_regs + KS8695_WMC);
+ if ((ctrl & WMC_WAND) == 0) {
+ /* auto-negotiation is enabled */
+ cmd->advertising |= ADVERTISED_Autoneg;
+ if (ctrl & WMC_WANA100F)
+ cmd->advertising |= ADVERTISED_100baseT_Full;
+ if (ctrl & WMC_WANA100H)
+ cmd->advertising |= ADVERTISED_100baseT_Half;
+ if (ctrl & WMC_WANA10F)
+ cmd->advertising |= ADVERTISED_10baseT_Full;
+ if (ctrl & WMC_WANA10H)
+ cmd->advertising |= ADVERTISED_10baseT_Half;
+ if (ctrl & WMC_WANAP)
+ cmd->advertising |= ADVERTISED_Pause;
+ cmd->autoneg = AUTONEG_ENABLE;
+
+ cmd->speed = (ctrl & WMC_WSS) ? SPEED_100 : SPEED_10;
+ cmd->duplex = (ctrl & WMC_WDS) ?
+ DUPLEX_FULL : DUPLEX_HALF;
+ } else {
+ /* auto-negotiation is disabled */
+ cmd->autoneg = AUTONEG_DISABLE;
- ctrl = readl(ksp->phyiface_regs + KS8695_WMC);
- if ((ctrl & WMC_WAND) == 0) {
- /* auto-negotiation is enabled */
- cmd->advertising |= ADVERTISED_Autoneg;
- if (ctrl & WMC_WANA100F)
- cmd->advertising |= ADVERTISED_100baseT_Full;
- if (ctrl & WMC_WANA100H)
- cmd->advertising |= ADVERTISED_100baseT_Half;
- if (ctrl & WMC_WANA10F)
- cmd->advertising |= ADVERTISED_10baseT_Full;
- if (ctrl & WMC_WANA10H)
- cmd->advertising |= ADVERTISED_10baseT_Half;
- if (ctrl & WMC_WANAP)
- cmd->advertising |= ADVERTISED_Pause;
- cmd->autoneg = AUTONEG_ENABLE;
-
- cmd->speed = (ctrl & WMC_WSS) ? SPEED_100 : SPEED_10;
- cmd->duplex = (ctrl & WMC_WDS) ?
- DUPLEX_FULL : DUPLEX_HALF;
- } else {
- /* auto-negotiation is disabled */
- cmd->autoneg = AUTONEG_DISABLE;
-
- cmd->speed = (ctrl & WMC_WANF100) ?
- SPEED_100 : SPEED_10;
- cmd->duplex = (ctrl & WMC_WANFF) ?
- DUPLEX_FULL : DUPLEX_HALF;
- }
- break;
- case KS8695_DTYPE_LAN:
- return -EOPNOTSUPP;
+ cmd->speed = (ctrl & WMC_WANF100) ?
+ SPEED_100 : SPEED_10;
+ cmd->duplex = (ctrl & WMC_WANFF) ?
+ DUPLEX_FULL : DUPLEX_HALF;
}
return 0;
}
/**
- * ks8695_set_settings - Set device-specific settings.
+ * ks8695_wan_set_settings - Set device-specific settings.
* @ndev: The network device to configure
* @cmd: The settings to configure
*/
static int
-ks8695_set_settings(struct net_device *ndev, struct ethtool_cmd *cmd)
+ks8695_wan_set_settings(struct net_device *ndev, struct ethtool_cmd *cmd)
{
struct ks8695_priv *ksp = netdev_priv(ndev);
u32 ctrl;
@@ -956,171 +937,85 @@ ks8695_set_settings(struct net_device *ndev, struct ethtool_cmd *cmd)
ADVERTISED_100baseT_Full)) == 0)
return -EINVAL;
- switch (ksp->dtype) {
- case KS8695_DTYPE_HPNA:
- /* HPNA does not support auto-negotiation. */
- return -EINVAL;
- case KS8695_DTYPE_WAN:
- ctrl = readl(ksp->phyiface_regs + KS8695_WMC);
-
- ctrl &= ~(WMC_WAND | WMC_WANA100F | WMC_WANA100H |
- WMC_WANA10F | WMC_WANA10H);
- if (cmd->advertising & ADVERTISED_100baseT_Full)
- ctrl |= WMC_WANA100F;
- if (cmd->advertising & ADVERTISED_100baseT_Half)
- ctrl |= WMC_WANA100H;
- if (cmd->advertising & ADVERTISED_10baseT_Full)
- ctrl |= WMC_WANA10F;
- if (cmd->advertising & ADVERTISED_10baseT_Half)
- ctrl |= WMC_WANA10H;
-
- /* force a re-negotiation */
- ctrl |= WMC_WANR;
- writel(ctrl, ksp->phyiface_regs + KS8695_WMC);
- break;
- case KS8695_DTYPE_LAN:
- return -EOPNOTSUPP;
- }
+ ctrl = readl(ksp->phyiface_regs + KS8695_WMC);
+ ctrl &= ~(WMC_WAND | WMC_WANA100F | WMC_WANA100H |
+ WMC_WANA10F | WMC_WANA10H);
+ if (cmd->advertising & ADVERTISED_100baseT_Full)
+ ctrl |= WMC_WANA100F;
+ if (cmd->advertising & ADVERTISED_100baseT_Half)
+ ctrl |= WMC_WANA100H;
+ if (cmd->advertising & ADVERTISED_10baseT_Full)
+ ctrl |= WMC_WANA10F;
+ if (cmd->advertising & ADVERTISED_10baseT_Half)
+ ctrl |= WMC_WANA10H;
+
+ /* force a re-negotiation */
+ ctrl |= WMC_WANR;
+ writel(ctrl, ksp->phyiface_regs + KS8695_WMC);
} else {
- switch (ksp->dtype) {
- case KS8695_DTYPE_HPNA:
- /* BUG: dtype_hpna implies no phy registers */
- /*
- ctrl = __raw_readl(KS8695_MISC_VA + KS8695_HMC);
-
- ctrl &= ~(HMC_HSS | HMC_HDS);
- if (cmd->speed == SPEED_100)
- ctrl |= HMC_HSS;
- if (cmd->duplex == DUPLEX_FULL)
- ctrl |= HMC_HDS;
-
- __raw_writel(ctrl, KS8695_MISC_VA + KS8695_HMC);
- */
- return -EOPNOTSUPP;
- case KS8695_DTYPE_WAN:
- ctrl = readl(ksp->phyiface_regs + KS8695_WMC);
-
- /* disable auto-negotiation */
- ctrl |= WMC_WAND;
- ctrl &= ~(WMC_WANF100 | WMC_WANFF);
-
- if (cmd->speed == SPEED_100)
- ctrl |= WMC_WANF100;
- if (cmd->duplex == DUPLEX_FULL)
- ctrl |= WMC_WANFF;
-
- writel(ctrl, ksp->phyiface_regs + KS8695_WMC);
- break;
- case KS8695_DTYPE_LAN:
- return -EOPNOTSUPP;
- }
+ ctrl = readl(ksp->phyiface_regs + KS8695_WMC);
+
+ /* disable auto-negotiation */
+ ctrl |= WMC_WAND;
+ ctrl &= ~(WMC_WANF100 | WMC_WANFF);
+
+ if (cmd->speed == SPEED_100)
+ ctrl |= WMC_WANF100;
+ if (cmd->duplex == DUPLEX_FULL)
+ ctrl |= WMC_WANFF;
+
+ writel(ctrl, ksp->phyiface_regs + KS8695_WMC);
}
return 0;
}
/**
- * ks8695_nwayreset - Restart the autonegotiation on the port.
+ * ks8695_wan_nwayreset - Restart the autonegotiation on the port.
* @ndev: The network device to restart autoneotiation on
*/
static int
-ks8695_nwayreset(struct net_device *ndev)
+ks8695_wan_nwayreset(struct net_device *ndev)
{
struct ks8695_priv *ksp = netdev_priv(ndev);
u32 ctrl;
- switch (ksp->dtype) {
- case KS8695_DTYPE_HPNA:
- /* No phy means no autonegotiation on hpna */
- return -EINVAL;
- case KS8695_DTYPE_WAN:
- ctrl = readl(ksp->phyiface_regs + KS8695_WMC);
-
- if ((ctrl & WMC_WAND) == 0)
- writel(ctrl | WMC_WANR,
- ksp->phyiface_regs + KS8695_WMC);
- else
- /* auto-negotiation not enabled */
- return -EINVAL;
- break;
- case KS8695_DTYPE_LAN:
- return -EOPNOTSUPP;
- }
-
- return 0;
-}
+ ctrl = readl(ksp->phyiface_regs + KS8695_WMC);
-/**
- * ks8695_get_link - Retrieve link status of network interface
- * @ndev: The network interface to retrive the link status of.
- */
-static u32
-ks8695_get_link(struct net_device *ndev)
-{
- struct ks8695_priv *ksp = netdev_priv(ndev);
- u32 ctrl;
+ if ((ctrl & WMC_WAND) == 0)
+ writel(ctrl | WMC_WANR,
+ ksp->phyiface_regs + KS8695_WMC);
+ else
+ /* auto-negotiation not enabled */
+ return -EINVAL;
- switch (ksp->dtype) {
- case KS8695_DTYPE_HPNA:
- /* HPNA always has link */
- return 1;
- case KS8695_DTYPE_WAN:
- /* WAN we can read the PHY for */
- ctrl = readl(ksp->phyiface_regs + KS8695_WMC);
- return ctrl & WMC_WLS;
- case KS8695_DTYPE_LAN:
- return -EOPNOTSUPP;
- }
return 0;
}
/**
- * ks8695_get_pause - Retrieve network pause/flow-control advertising
+ * ks8695_wan_get_pause - Retrieve network pause/flow-control advertising
* @ndev: The device to retrieve settings from
* @param: The structure to fill out with the information
*/
static void
-ks8695_get_pause(struct net_device *ndev, struct ethtool_pauseparam *param)
+ks8695_wan_get_pause(struct net_device *ndev, struct ethtool_pauseparam *param)
{
struct ks8695_priv *ksp = netdev_priv(ndev);
u32 ctrl;
- switch (ksp->dtype) {
- case KS8695_DTYPE_HPNA:
- /* No phy link on hpna to configure */
- return;
- case KS8695_DTYPE_WAN:
- ctrl = readl(ksp->phyiface_regs + KS8695_WMC);
-
- /* advertise Pause */
- param->autoneg = (ctrl & WMC_WANAP);
+ ctrl = readl(ksp->phyiface_regs + KS8695_WMC);
- /* current Rx Flow-control */
- ctrl = ks8695_readreg(ksp, KS8695_DRXC);
- param->rx_pause = (ctrl & DRXC_RFCE);
+ /* advertise Pause */
+ param->autoneg = (ctrl & WMC_WANAP);
- /* current Tx Flow-control */
- ctrl = ks8695_readreg(ksp, KS8695_DTXC);
- param->tx_pause = (ctrl & DTXC_TFCE);
- break;
- case KS8695_DTYPE_LAN:
- /* The LAN's "phy" is a direct-attached switch */
- return;
- }
-}
+ /* current Rx Flow-control */
+ ctrl = ks8695_readreg(ksp, KS8695_DRXC);
+ param->rx_pause = (ctrl & DRXC_RFCE);
-/**
- * ks8695_set_pause - Configure pause/flow-control
- * @ndev: The device to configure
- * @param: The pause parameters to set
- *
- * TODO: Implement this
- */
-static int
-ks8695_set_pause(struct net_device *ndev, struct ethtool_pauseparam *param)
-{
- return -EOPNOTSUPP;
+ /* current Tx Flow-control */
+ ctrl = ks8695_readreg(ksp, KS8695_DTXC);
+ param->tx_pause = (ctrl & DTXC_TFCE);
}
/**
@@ -1140,12 +1035,17 @@ ks8695_get_drvinfo(struct net_device *ndev, struct ethtool_drvinfo *info)
static const struct ethtool_ops ks8695_ethtool_ops = {
.get_msglevel = ks8695_get_msglevel,
.set_msglevel = ks8695_set_msglevel,
- .get_settings = ks8695_get_settings,
- .set_settings = ks8695_set_settings,
- .nway_reset = ks8695_nwayreset,
- .get_link = ks8695_get_link,
- .get_pauseparam = ks8695_get_pause,
- .set_pauseparam = ks8695_set_pause,
+ .get_drvinfo = ks8695_get_drvinfo,
+};
+
+static const struct ethtool_ops ks8695_wan_ethtool_ops = {
+ .get_msglevel = ks8695_get_msglevel,
+ .set_msglevel = ks8695_set_msglevel,
+ .get_settings = ks8695_wan_get_settings,
+ .set_settings = ks8695_wan_set_settings,
+ .nway_reset = ks8695_wan_nwayreset,
+ .get_link = ethtool_op_get_link,
+ .get_pauseparam = ks8695_wan_get_pause,
.get_drvinfo = ks8695_get_drvinfo,
};
@@ -1541,7 +1441,6 @@ ks8695_probe(struct platform_device *pdev)
/* driver system setup */
ndev->netdev_ops = &ks8695_netdev_ops;
- SET_ETHTOOL_OPS(ndev, &ks8695_ethtool_ops);
ndev->watchdog_timeo = msecs_to_jiffies(watchdog);
netif_napi_add(ndev, &ksp->napi, ks8695_poll, NAPI_WEIGHT);
@@ -1608,12 +1507,15 @@ ks8695_probe(struct platform_device *pdev)
if (ksp->phyiface_regs && ksp->link_irq == -1) {
ks8695_init_switch(ksp);
ksp->dtype = KS8695_DTYPE_LAN;
+ SET_ETHTOOL_OPS(ndev, &ks8695_ethtool_ops);
} else if (ksp->phyiface_regs && ksp->link_irq != -1) {
ks8695_init_wan_phy(ksp);
ksp->dtype = KS8695_DTYPE_WAN;
+ SET_ETHTOOL_OPS(ndev, &ks8695_wan_ethtool_ops);
} else {
/* No initialisation since HPNA does not have a PHY */
ksp->dtype = KS8695_DTYPE_HPNA;
+ SET_ETHTOOL_OPS(ndev, &ks8695_ethtool_ops);
}
/* And bring up the net_device with the net core */
@@ -1742,7 +1644,7 @@ ks8695_cleanup(void)
module_init(ks8695_init);
module_exit(ks8695_cleanup);
-MODULE_AUTHOR("Simtec Electronics")
+MODULE_AUTHOR("Simtec Electronics");
MODULE_DESCRIPTION("Micrel KS8695 (Centaur) Ethernet driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:" MODULENAME);
diff --git a/drivers/net/bfin_mac.c b/drivers/net/bfin_mac.c
index 0b9fc51..22abfb3 100644
--- a/drivers/net/bfin_mac.c
+++ b/drivers/net/bfin_mac.c
@@ -1284,19 +1284,12 @@ static void bfin_mac_multicast_hash(struct net_device *dev)
{
u32 emac_hashhi, emac_hashlo;
struct netdev_hw_addr *ha;
- char *addrs;
u32 crc;
emac_hashhi = emac_hashlo = 0;
netdev_for_each_mc_addr(ha, dev) {
- addrs = ha->addr;
-
- /* skip non-multicast addresses */
- if (!(*addrs & 1))
- continue;
-
- crc = ether_crc(ETH_ALEN, addrs);
+ crc = ether_crc(ETH_ALEN, ha->addr);
crc >>= 26;
if (crc & 0x20)
diff --git a/drivers/net/bna/bnad_ethtool.c b/drivers/net/bna/bnad_ethtool.c
index 99be5ae..142d604 100644
--- a/drivers/net/bna/bnad_ethtool.c
+++ b/drivers/net/bna/bnad_ethtool.c
@@ -275,7 +275,6 @@ bnad_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *drvinfo)
ioc_attr = kzalloc(sizeof(*ioc_attr), GFP_KERNEL);
if (ioc_attr) {
- memset(ioc_attr, 0, sizeof(*ioc_attr));
spin_lock_irqsave(&bnad->bna_lock, flags);
bfa_nw_ioc_get_attr(&bnad->bna.device.ioc, ioc_attr);
spin_unlock_irqrestore(&bnad->bna_lock, flags);
diff --git a/drivers/net/bnx2x/bnx2x.h b/drivers/net/bnx2x/bnx2x.h
index a6cd335..8e41837 100644
--- a/drivers/net/bnx2x/bnx2x.h
+++ b/drivers/net/bnx2x/bnx2x.h
@@ -22,8 +22,8 @@
* (you will need to reboot afterwards) */
/* #define BNX2X_STOP_ON_ERROR */
-#define DRV_MODULE_VERSION "1.62.00-3"
-#define DRV_MODULE_RELDATE "2010/12/21"
+#define DRV_MODULE_VERSION "1.62.00-4"
+#define DRV_MODULE_RELDATE "2011/01/18"
#define BNX2X_BC_VER 0x040200
#define BNX2X_MULTI_QUEUE
diff --git a/drivers/net/bnx2x/bnx2x_hsi.h b/drivers/net/bnx2x/bnx2x_hsi.h
index 6238d4f..548f563 100644
--- a/drivers/net/bnx2x/bnx2x_hsi.h
+++ b/drivers/net/bnx2x/bnx2x_hsi.h
@@ -352,6 +352,10 @@ struct port_hw_cfg { /* port 0: 0x12c port 1: 0x2bc */
#define PORT_HW_CFG_LANE_SWAP_CFG_31203120 0x0000d8d8
/* forced only */
#define PORT_HW_CFG_LANE_SWAP_CFG_32103210 0x0000e4e4
+ /* Indicate whether to swap the external phy polarity */
+#define PORT_HW_CFG_SWAP_PHY_POLARITY_MASK 0x00010000
+#define PORT_HW_CFG_SWAP_PHY_POLARITY_DISABLED 0x00000000
+#define PORT_HW_CFG_SWAP_PHY_POLARITY_ENABLED 0x00010000
u32 external_phy_config;
#define PORT_HW_CFG_SERDES_EXT_PHY_TYPE_MASK 0xff000000
diff --git a/drivers/net/bnx2x/bnx2x_link.c b/drivers/net/bnx2x/bnx2x_link.c
index 43b0de2..7160ec5 100644
--- a/drivers/net/bnx2x/bnx2x_link.c
+++ b/drivers/net/bnx2x/bnx2x_link.c
@@ -1573,7 +1573,7 @@ static void bnx2x_set_aer_mmd_xgxs(struct link_params *params,
offset = phy->addr + ser_lane;
if (CHIP_IS_E2(bp))
- aer_val = 0x2800 + offset - 1;
+ aer_val = 0x3800 + offset - 1;
else
aer_val = 0x3800 + offset;
CL45_WR_OVER_CL22(bp, phy,
@@ -3166,7 +3166,23 @@ u8 bnx2x_set_led(struct link_params *params,
if (!vars->link_up)
break;
case LED_MODE_ON:
- if (SINGLE_MEDIA_DIRECT(params)) {
+ if (params->phy[EXT_PHY1].type ==
+ PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727 &&
+ CHIP_IS_E2(bp) && params->num_phys == 2) {
+ /**
+ * This is a work-around for E2+8727 Configurations
+ */
+ if (mode == LED_MODE_ON ||
+ speed == SPEED_10000){
+ REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4, 0);
+ REG_WR(bp, NIG_REG_LED_10G_P0 + port*4, 1);
+
+ tmp = EMAC_RD(bp, EMAC_REG_EMAC_LED);
+ EMAC_WR(bp, EMAC_REG_EMAC_LED,
+ (tmp | EMAC_LED_OVERRIDE));
+ return rc;
+ }
+ } else if (SINGLE_MEDIA_DIRECT(params)) {
/**
* This is a work-around for HW issue found when link
* is up in CL73
@@ -3854,11 +3870,14 @@ static void bnx2x_8073_resolve_fc(struct bnx2x_phy *phy,
pause_result);
}
}
-
-static void bnx2x_8073_8727_external_rom_boot(struct bnx2x *bp,
+static u8 bnx2x_8073_8727_external_rom_boot(struct bnx2x *bp,
struct bnx2x_phy *phy,
u8 port)
{
+ u32 count = 0;
+ u16 fw_ver1, fw_msgout;
+ u8 rc = 0;
+
/* Boot port from external ROM */
/* EDC grst */
bnx2x_cl45_write(bp, phy,
@@ -3888,14 +3907,45 @@ static void bnx2x_8073_8727_external_rom_boot(struct bnx2x *bp,
MDIO_PMA_REG_GEN_CTRL,
MDIO_PMA_REG_GEN_CTRL_ROM_RESET_INTERNAL_MP);
- /* wait for 120ms for code download via SPI port */
- msleep(120);
+ /* Delay 100ms per the PHY specifications */
+ msleep(100);
+
+ /* 8073 sometimes taking longer to download */
+ do {
+ count++;
+ if (count > 300) {
+ DP(NETIF_MSG_LINK,
+ "bnx2x_8073_8727_external_rom_boot port %x:"
+ "Download failed. fw version = 0x%x\n",
+ port, fw_ver1);
+ rc = -EINVAL;
+ break;
+ }
+
+ bnx2x_cl45_read(bp, phy,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_ROM_VER1, &fw_ver1);
+ bnx2x_cl45_read(bp, phy,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_M8051_MSGOUT_REG, &fw_msgout);
+
+ msleep(1);
+ } while (fw_ver1 == 0 || fw_ver1 == 0x4321 ||
+ ((fw_msgout & 0xff) != 0x03 && (phy->type ==
+ PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073)));
/* Clear ser_boot_ctl bit */
bnx2x_cl45_write(bp, phy,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_MISC_CTRL1, 0x0000);
bnx2x_save_bcm_spirom_ver(bp, phy, port);
+
+ DP(NETIF_MSG_LINK,
+ "bnx2x_8073_8727_external_rom_boot port %x:"
+ "Download complete. fw version = 0x%x\n",
+ port, fw_ver1);
+
+ return rc;
}
static void bnx2x_8073_set_xaui_low_power_mode(struct bnx2x *bp,
@@ -4108,6 +4158,25 @@ static u8 bnx2x_8073_config_init(struct bnx2x_phy *phy,
DP(NETIF_MSG_LINK, "Before rom RX_ALARM(port1): 0x%x\n", tmp1);
+ /**
+ * If this is forced speed, set to KR or KX (all other are not
+ * supported)
+ */
+ /* Swap polarity if required - Must be done only in non-1G mode */
+ if (params->lane_config & PORT_HW_CFG_SWAP_PHY_POLARITY_ENABLED) {
+ /* Configure the 8073 to swap _P and _N of the KR lines */
+ DP(NETIF_MSG_LINK, "Swapping polarity for the 8073\n");
+ /* 10G Rx/Tx and 1G Tx signal polarity swap */
+ bnx2x_cl45_read(bp, phy,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_8073_OPT_DIGITAL_CTRL, &val);
+ bnx2x_cl45_write(bp, phy,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_8073_OPT_DIGITAL_CTRL,
+ (val | (3<<9)));
+ }
+
+
/* Enable CL37 BAM */
if (REG_RD(bp, params->shmem_base +
offsetof(struct shmem_region, dev_info.
@@ -4314,8 +4383,32 @@ static u8 bnx2x_8073_read_status(struct bnx2x_phy *phy,
}
if (link_up) {
+ /* Swap polarity if required */
+ if (params->lane_config &
+ PORT_HW_CFG_SWAP_PHY_POLARITY_ENABLED) {
+ /* Configure the 8073 to swap P and N of the KR lines */
+ bnx2x_cl45_read(bp, phy,
+ MDIO_XS_DEVAD,
+ MDIO_XS_REG_8073_RX_CTRL_PCIE, &val1);
+ /**
+ * Set bit 3 to invert Rx in 1G mode and clear this bit
+ * when it`s in 10G mode.
+ */
+ if (vars->line_speed == SPEED_1000) {
+ DP(NETIF_MSG_LINK, "Swapping 1G polarity for"
+ "the 8073\n");
+ val1 |= (1<<3);
+ } else
+ val1 &= ~(1<<3);
+
+ bnx2x_cl45_write(bp, phy,
+ MDIO_XS_DEVAD,
+ MDIO_XS_REG_8073_RX_CTRL_PCIE,
+ val1);
+ }
bnx2x_ext_phy_10G_an_resolve(bp, phy, vars);
bnx2x_8073_resolve_fc(phy, params, vars);
+ vars->duplex = DUPLEX_FULL;
}
return link_up;
}
@@ -5062,6 +5155,7 @@ static u8 bnx2x_8706_8726_read_status(struct bnx2x_phy *phy,
else
vars->line_speed = SPEED_10000;
bnx2x_ext_phy_resolve_fc(phy, params, vars);
+ vars->duplex = DUPLEX_FULL;
}
return link_up;
}
@@ -5758,8 +5852,11 @@ static u8 bnx2x_8727_read_status(struct bnx2x_phy *phy,
DP(NETIF_MSG_LINK, "port %x: External link is down\n",
params->port);
}
- if (link_up)
+ if (link_up) {
bnx2x_ext_phy_resolve_fc(phy, params, vars);
+ vars->duplex = DUPLEX_FULL;
+ DP(NETIF_MSG_LINK, "duplex = 0x%x\n", vars->duplex);
+ }
if ((DUAL_MEDIA(params)) &&
(phy->req_line_speed == SPEED_1000)) {
@@ -5875,10 +5972,26 @@ static void bnx2x_848xx_set_led(struct bnx2x *bp,
MDIO_PMA_REG_8481_LED2_MASK,
0x18);
+ /* Select activity source by Tx and Rx, as suggested by PHY AE */
bnx2x_cl45_write(bp, phy,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_8481_LED3_MASK,
- 0x0040);
+ 0x0006);
+
+ /* Select the closest activity blink rate to that in 10/100/1000 */
+ bnx2x_cl45_write(bp, phy,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_8481_LED3_BLINK,
+ 0);
+
+ bnx2x_cl45_read(bp, phy,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_84823_CTL_LED_CTL_1, &val);
+ val |= MDIO_PMA_REG_84823_LED3_STRETCH_EN; /* stretch_en for LED3*/
+
+ bnx2x_cl45_write(bp, phy,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_84823_CTL_LED_CTL_1, val);
/* 'Interrupt Mask' */
bnx2x_cl45_write(bp, phy,
@@ -6126,6 +6239,7 @@ static u8 bnx2x_848xx_read_status(struct bnx2x_phy *phy,
/* Check link 10G */
if (val2 & (1<<11)) {
vars->line_speed = SPEED_10000;
+ vars->duplex = DUPLEX_FULL;
link_up = 1;
bnx2x_ext_phy_10G_an_resolve(bp, phy, vars);
} else { /* Check Legacy speed link */
@@ -6489,6 +6603,7 @@ static u8 bnx2x_7101_read_status(struct bnx2x_phy *phy,
MDIO_AN_DEVAD, MDIO_AN_REG_MASTER_STATUS,
&val2);
vars->line_speed = SPEED_10000;
+ vars->duplex = DUPLEX_FULL;
DP(NETIF_MSG_LINK, "SFX7101 AN status 0x%x->Master=%x\n",
val2, (val2 & (1<<14)));
bnx2x_ext_phy_10G_an_resolve(bp, phy, vars);
@@ -7663,7 +7778,6 @@ static u8 bnx2x_8073_common_init_phy(struct bnx2x *bp,
/* PART2 - Download firmware to both phys */
for (port = PORT_MAX - 1; port >= PORT_0; port--) {
- u16 fw_ver1;
if (CHIP_IS_E2(bp))
port_of_path = 0;
else
@@ -7671,19 +7785,9 @@ static u8 bnx2x_8073_common_init_phy(struct bnx2x *bp,
DP(NETIF_MSG_LINK, "Loading spirom for phy address 0x%x\n",
phy_blk[port]->addr);
- bnx2x_8073_8727_external_rom_boot(bp, phy_blk[port],
- port_of_path);
-
- bnx2x_cl45_read(bp, phy_blk[port],
- MDIO_PMA_DEVAD,
- MDIO_PMA_REG_ROM_VER1, &fw_ver1);
- if (fw_ver1 == 0 || fw_ver1 == 0x4321) {
- DP(NETIF_MSG_LINK,
- "bnx2x_8073_common_init_phy port %x:"
- "Download failed. fw version = 0x%x\n",
- port, fw_ver1);
+ if (bnx2x_8073_8727_external_rom_boot(bp, phy_blk[port],
+ port_of_path))
return -EINVAL;
- }
/* Only set bit 10 = 1 (Tx power down) */
bnx2x_cl45_read(bp, phy_blk[port],
@@ -7848,27 +7952,17 @@ static u8 bnx2x_8727_common_init_phy(struct bnx2x *bp,
}
/* PART2 - Download firmware to both phys */
for (port = PORT_MAX - 1; port >= PORT_0; port--) {
- u16 fw_ver1;
if (CHIP_IS_E2(bp))
port_of_path = 0;
else
port_of_path = port;
DP(NETIF_MSG_LINK, "Loading spirom for phy address 0x%x\n",
phy_blk[port]->addr);
- bnx2x_8073_8727_external_rom_boot(bp, phy_blk[port],
- port_of_path);
- bnx2x_cl45_read(bp, phy_blk[port],
- MDIO_PMA_DEVAD,
- MDIO_PMA_REG_ROM_VER1, &fw_ver1);
- if (fw_ver1 == 0 || fw_ver1 == 0x4321) {
- DP(NETIF_MSG_LINK,
- "bnx2x_8727_common_init_phy port %x:"
- "Download failed. fw version = 0x%x\n",
- port, fw_ver1);
+ if (bnx2x_8073_8727_external_rom_boot(bp, phy_blk[port],
+ port_of_path))
return -EINVAL;
- }
- }
+ }
return 0;
}
@@ -7916,6 +8010,7 @@ u8 bnx2x_common_init_phy(struct bnx2x *bp, u32 shmem_base_path[],
u32 shmem2_base_path[], u32 chip_id)
{
u8 rc = 0;
+ u32 phy_ver;
u8 phy_index;
u32 ext_phy_type, ext_phy_config;
DP(NETIF_MSG_LINK, "Begin common phy init\n");
@@ -7923,6 +8018,16 @@ u8 bnx2x_common_init_phy(struct bnx2x *bp, u32 shmem_base_path[],
if (CHIP_REV_IS_EMUL(bp))
return 0;
+ /* Check if common init was already done */
+ phy_ver = REG_RD(bp, shmem_base_path[0] +
+ offsetof(struct shmem_region,
+ port_mb[PORT_0].ext_phy_fw_version));
+ if (phy_ver) {
+ DP(NETIF_MSG_LINK, "Not doing common init; phy ver is 0x%x\n",
+ phy_ver);
+ return 0;
+ }
+
/* Read the ext_phy_type for arbitrary port(0) */
for (phy_index = EXT_PHY1; phy_index < MAX_PHYS;
phy_index++) {
diff --git a/drivers/net/bnx2x/bnx2x_reg.h b/drivers/net/bnx2x/bnx2x_reg.h
index c939683..e01330b 100644
--- a/drivers/net/bnx2x/bnx2x_reg.h
+++ b/drivers/net/bnx2x/bnx2x_reg.h
@@ -6194,7 +6194,11 @@ Theotherbitsarereservedandshouldbezero*/
#define MDIO_CTL_REG_84823_MEDIA_PRIORITY_COPPER 0x0000
#define MDIO_CTL_REG_84823_MEDIA_PRIORITY_FIBER 0x0100
#define MDIO_CTL_REG_84823_MEDIA_FIBER_1G 0x1000
+#define MDIO_CTL_REG_84823_USER_CTRL_REG 0x4005
+#define MDIO_CTL_REG_84823_USER_CTRL_CMS 0x0080
+#define MDIO_PMA_REG_84823_CTL_LED_CTL_1 0xa8e3
+#define MDIO_PMA_REG_84823_LED3_STRETCH_EN 0x0080
#define IGU_FUNC_BASE 0x0400
diff --git a/drivers/net/cassini.c b/drivers/net/cassini.c
index 7206ab2..3437613 100644
--- a/drivers/net/cassini.c
+++ b/drivers/net/cassini.c
@@ -3203,7 +3203,7 @@ static int cas_get_vpd_info(struct cas *cp, unsigned char *dev_addr,
int phy_type = CAS_PHY_MII_MDIO0; /* default phy type */
int mac_off = 0;
-#if defined(CONFIG_OF)
+#if defined(CONFIG_SPARC)
const unsigned char *addr;
#endif
@@ -3354,7 +3354,7 @@ use_random_mac_addr:
if (found & VPD_FOUND_MAC)
goto done;
-#if defined(CONFIG_OF)
+#if defined(CONFIG_SPARC)
addr = of_get_property(cp->of_node, "local-mac-address", NULL);
if (addr != NULL) {
memcpy(dev_addr, addr, 6);
@@ -5031,7 +5031,7 @@ static int __devinit cas_init_one(struct pci_dev *pdev,
cp->msg_enable = (cassini_debug < 0) ? CAS_DEF_MSG_ENABLE :
cassini_debug;
-#if defined(CONFIG_OF)
+#if defined(CONFIG_SPARC)
cp->of_node = pci_device_to_OF_node(pdev);
#endif
diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c
index de69c54..bfab140 100644
--- a/drivers/net/e1000/e1000_main.c
+++ b/drivers/net/e1000/e1000_main.c
@@ -3478,9 +3478,17 @@ static irqreturn_t e1000_intr(int irq, void *data)
struct e1000_hw *hw = &adapter->hw;
u32 icr = er32(ICR);
- if (unlikely((!icr) || test_bit(__E1000_DOWN, &adapter->flags)))
+ if (unlikely((!icr)))
return IRQ_NONE; /* Not our interrupt */
+ /*
+ * we might have caused the interrupt, but the above
+ * read cleared it, and just in case the driver is
+ * down there is nothing to do so return handled
+ */
+ if (unlikely(test_bit(__E1000_DOWN, &adapter->flags)))
+ return IRQ_HANDLED;
+
if (unlikely(icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC))) {
hw->get_link_status = 1;
/* guard against interrupt when we're going down */
diff --git a/drivers/net/e1000e/82571.c b/drivers/net/e1000e/82571.c
index 1397da1..89a6903 100644
--- a/drivers/net/e1000e/82571.c
+++ b/drivers/net/e1000e/82571.c
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel PRO/1000 Linux driver
- Copyright(c) 1999 - 2010 Intel Corporation.
+ Copyright(c) 1999 - 2011 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,
@@ -1310,7 +1310,7 @@ static void e1000_initialize_hw_bits_82571(struct e1000_hw *hw)
* apply workaround for hardware errata documented in errata
* docs Fixes issue where some error prone or unreliable PCIe
* completions are occurring, particularly with ASPM enabled.
- * Without fix, issue can cause tx timeouts.
+ * Without fix, issue can cause Tx timeouts.
*/
reg = er32(GCR2);
reg |= 1;
diff --git a/drivers/net/e1000e/Makefile b/drivers/net/e1000e/Makefile
index 360c913..28519ac 100644
--- a/drivers/net/e1000e/Makefile
+++ b/drivers/net/e1000e/Makefile
@@ -1,7 +1,7 @@
################################################################################
#
# Intel PRO/1000 Linux driver
-# Copyright(c) 1999 - 2008 Intel Corporation.
+# Copyright(c) 1999 - 2011 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,
diff --git a/drivers/net/e1000e/defines.h b/drivers/net/e1000e/defines.h
index 7245dc2..1314998 100644
--- a/drivers/net/e1000e/defines.h
+++ b/drivers/net/e1000e/defines.h
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel PRO/1000 Linux driver
- Copyright(c) 1999 - 2010 Intel Corporation.
+ Copyright(c) 1999 - 2011 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,
diff --git a/drivers/net/e1000e/e1000.h b/drivers/net/e1000e/e1000.h
index 5255be7..e610e136 100644
--- a/drivers/net/e1000e/e1000.h
+++ b/drivers/net/e1000e/e1000.h
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel PRO/1000 Linux driver
- Copyright(c) 1999 - 2010 Intel Corporation.
+ Copyright(c) 1999 - 2011 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,
diff --git a/drivers/net/e1000e/es2lan.c b/drivers/net/e1000e/es2lan.c
index e45a61c..2fefa82 100644
--- a/drivers/net/e1000e/es2lan.c
+++ b/drivers/net/e1000e/es2lan.c
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel PRO/1000 Linux driver
- Copyright(c) 1999 - 2010 Intel Corporation.
+ Copyright(c) 1999 - 2011 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,
diff --git a/drivers/net/e1000e/ethtool.c b/drivers/net/e1000e/ethtool.c
index f8ed03d..fa08b63 100644
--- a/drivers/net/e1000e/ethtool.c
+++ b/drivers/net/e1000e/ethtool.c
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel PRO/1000 Linux driver
- Copyright(c) 1999 - 2010 Intel Corporation.
+ Copyright(c) 1999 - 2011 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,
diff --git a/drivers/net/e1000e/hw.h b/drivers/net/e1000e/hw.h
index e774380..bc0860a 100644
--- a/drivers/net/e1000e/hw.h
+++ b/drivers/net/e1000e/hw.h
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel PRO/1000 Linux driver
- Copyright(c) 1999 - 2010 Intel Corporation.
+ Copyright(c) 1999 - 2011 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,
@@ -102,7 +102,7 @@ enum e1e_registers {
E1000_RDTR = 0x02820, /* Rx Delay Timer - RW */
E1000_RXDCTL_BASE = 0x02828, /* Rx Descriptor Control - RW */
#define E1000_RXDCTL(_n) (E1000_RXDCTL_BASE + (_n << 8))
- E1000_RADV = 0x0282C, /* RX Interrupt Absolute Delay Timer - RW */
+ E1000_RADV = 0x0282C, /* Rx Interrupt Absolute Delay Timer - RW */
/* Convenience macros
*
diff --git a/drivers/net/e1000e/ich8lan.c b/drivers/net/e1000e/ich8lan.c
index 5bb65b7..fb46974 100644
--- a/drivers/net/e1000e/ich8lan.c
+++ b/drivers/net/e1000e/ich8lan.c
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel PRO/1000 Linux driver
- Copyright(c) 1999 - 2010 Intel Corporation.
+ Copyright(c) 1999 - 2011 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,
diff --git a/drivers/net/e1000e/lib.c b/drivers/net/e1000e/lib.c
index ff28721..68aa174 100644
--- a/drivers/net/e1000e/lib.c
+++ b/drivers/net/e1000e/lib.c
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel PRO/1000 Linux driver
- Copyright(c) 1999 - 2010 Intel Corporation.
+ Copyright(c) 1999 - 2011 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,
@@ -533,7 +533,7 @@ s32 e1000e_check_for_fiber_link(struct e1000_hw *hw)
mac->autoneg_failed = 1;
return 0;
}
- e_dbg("NOT RXing /C/, disable AutoNeg and force link.\n");
+ e_dbg("NOT Rx'ing /C/, disable AutoNeg and force link.\n");
/* Disable auto-negotiation in the TXCW register */
ew32(TXCW, (mac->txcw & ~E1000_TXCW_ANE));
@@ -556,7 +556,7 @@ s32 e1000e_check_for_fiber_link(struct e1000_hw *hw)
* and disable forced link in the Device Control register
* in an attempt to auto-negotiate with our link partner.
*/
- e_dbg("RXing /C/, enable AutoNeg and stop forcing link.\n");
+ e_dbg("Rx'ing /C/, enable AutoNeg and stop forcing link.\n");
ew32(TXCW, mac->txcw);
ew32(CTRL, (ctrl & ~E1000_CTRL_SLU));
@@ -598,7 +598,7 @@ s32 e1000e_check_for_serdes_link(struct e1000_hw *hw)
mac->autoneg_failed = 1;
return 0;
}
- e_dbg("NOT RXing /C/, disable AutoNeg and force link.\n");
+ e_dbg("NOT Rx'ing /C/, disable AutoNeg and force link.\n");
/* Disable auto-negotiation in the TXCW register */
ew32(TXCW, (mac->txcw & ~E1000_TXCW_ANE));
@@ -621,7 +621,7 @@ s32 e1000e_check_for_serdes_link(struct e1000_hw *hw)
* and disable forced link in the Device Control register
* in an attempt to auto-negotiate with our link partner.
*/
- e_dbg("RXing /C/, enable AutoNeg and stop forcing link.\n");
+ e_dbg("Rx'ing /C/, enable AutoNeg and stop forcing link.\n");
ew32(TXCW, mac->txcw);
ew32(CTRL, (ctrl & ~E1000_CTRL_SLU));
@@ -800,9 +800,9 @@ static s32 e1000_commit_fc_settings_generic(struct e1000_hw *hw)
* The possible values of the "fc" parameter are:
* 0: Flow control is completely disabled
* 1: Rx flow control is enabled (we can receive pause frames,
- * but not send pause frames).
+ * but not send pause frames).
* 2: Tx flow control is enabled (we can send pause frames but we
- * do not support receiving pause frames).
+ * do not support receiving pause frames).
* 3: Both Rx and Tx flow control (symmetric) are enabled.
*/
switch (hw->fc.current_mode) {
@@ -1031,9 +1031,9 @@ s32 e1000e_force_mac_fc(struct e1000_hw *hw)
* The possible values of the "fc" parameter are:
* 0: Flow control is completely disabled
* 1: Rx flow control is enabled (we can receive pause
- * frames but not send pause frames).
+ * frames but not send pause frames).
* 2: Tx flow control is enabled (we can send pause frames
- * frames but we do not receive pause frames).
+ * frames but we do not receive pause frames).
* 3: Both Rx and Tx flow control (symmetric) is enabled.
* other: No other values should be possible at this point.
*/
@@ -1189,7 +1189,7 @@ s32 e1000e_config_fc_after_link_up(struct e1000_hw *hw)
} else {
hw->fc.current_mode = e1000_fc_rx_pause;
e_dbg("Flow Control = "
- "RX PAUSE frames only.\r\n");
+ "Rx PAUSE frames only.\r\n");
}
}
/*
diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c
index fa5b604..1c18f26 100644
--- a/drivers/net/e1000e/netdev.c
+++ b/drivers/net/e1000e/netdev.c
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel PRO/1000 Linux driver
- Copyright(c) 1999 - 2010 Intel Corporation.
+ Copyright(c) 1999 - 2011 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,
@@ -77,17 +77,17 @@ struct e1000_reg_info {
char *name;
};
-#define E1000_RDFH 0x02410 /* Rx Data FIFO Head - RW */
-#define E1000_RDFT 0x02418 /* Rx Data FIFO Tail - RW */
-#define E1000_RDFHS 0x02420 /* Rx Data FIFO Head Saved - RW */
-#define E1000_RDFTS 0x02428 /* Rx Data FIFO Tail Saved - RW */
-#define E1000_RDFPC 0x02430 /* Rx Data FIFO Packet Count - RW */
+#define E1000_RDFH 0x02410 /* Rx Data FIFO Head - RW */
+#define E1000_RDFT 0x02418 /* Rx Data FIFO Tail - RW */
+#define E1000_RDFHS 0x02420 /* Rx Data FIFO Head Saved - RW */
+#define E1000_RDFTS 0x02428 /* Rx Data FIFO Tail Saved - RW */
+#define E1000_RDFPC 0x02430 /* Rx Data FIFO Packet Count - RW */
-#define E1000_TDFH 0x03410 /* Tx Data FIFO Head - RW */
-#define E1000_TDFT 0x03418 /* Tx Data FIFO Tail - RW */
-#define E1000_TDFHS 0x03420 /* Tx Data FIFO Head Saved - RW */
-#define E1000_TDFTS 0x03428 /* Tx Data FIFO Tail Saved - RW */
-#define E1000_TDFPC 0x03430 /* Tx Data FIFO Packet Count - RW */
+#define E1000_TDFH 0x03410 /* Tx Data FIFO Head - RW */
+#define E1000_TDFT 0x03418 /* Tx Data FIFO Tail - RW */
+#define E1000_TDFHS 0x03420 /* Tx Data FIFO Head Saved - RW */
+#define E1000_TDFTS 0x03428 /* Tx Data FIFO Tail Saved - RW */
+#define E1000_TDFPC 0x03430 /* Tx Data FIFO Packet Count - RW */
static const struct e1000_reg_info e1000_reg_info_tbl[] = {
@@ -99,7 +99,7 @@ static const struct e1000_reg_info e1000_reg_info_tbl[] = {
/* Interrupt Registers */
{E1000_ICR, "ICR"},
- /* RX Registers */
+ /* Rx Registers */
{E1000_RCTL, "RCTL"},
{E1000_RDLEN, "RDLEN"},
{E1000_RDH, "RDH"},
@@ -115,7 +115,7 @@ static const struct e1000_reg_info e1000_reg_info_tbl[] = {
{E1000_RDFTS, "RDFTS"},
{E1000_RDFPC, "RDFPC"},
- /* TX Registers */
+ /* Tx Registers */
{E1000_TCTL, "TCTL"},
{E1000_TDBAL, "TDBAL"},
{E1000_TDBAH, "TDBAH"},
@@ -160,7 +160,7 @@ static void e1000_regdump(struct e1000_hw *hw, struct e1000_reg_info *reginfo)
break;
default:
printk(KERN_INFO "%-15s %08x\n",
- reginfo->name, __er32(hw, reginfo->ofs));
+ reginfo->name, __er32(hw, reginfo->ofs));
return;
}
@@ -171,9 +171,8 @@ static void e1000_regdump(struct e1000_hw *hw, struct e1000_reg_info *reginfo)
printk(KERN_CONT "\n");
}
-
/*
- * e1000e_dump - Print registers, tx-ring and rx-ring
+ * e1000e_dump - Print registers, Tx-ring and Rx-ring
*/
static void e1000e_dump(struct e1000_adapter *adapter)
{
@@ -182,12 +181,20 @@ static void e1000e_dump(struct e1000_adapter *adapter)
struct e1000_reg_info *reginfo;
struct e1000_ring *tx_ring = adapter->tx_ring;
struct e1000_tx_desc *tx_desc;
- struct my_u0 { u64 a; u64 b; } *u0;
+ struct my_u0 {
+ u64 a;
+ u64 b;
+ } *u0;
struct e1000_buffer *buffer_info;
struct e1000_ring *rx_ring = adapter->rx_ring;
union e1000_rx_desc_packet_split *rx_desc_ps;
struct e1000_rx_desc *rx_desc;
- struct my_u1 { u64 a; u64 b; u64 c; u64 d; } *u1;
+ struct my_u1 {
+ u64 a;
+ u64 b;
+ u64 c;
+ u64 d;
+ } *u1;
u32 staterr;
int i = 0;
@@ -198,12 +205,10 @@ static void e1000e_dump(struct e1000_adapter *adapter)
if (netdev) {
dev_info(&adapter->pdev->dev, "Net device Info\n");
printk(KERN_INFO "Device Name state "
- "trans_start last_rx\n");
+ "trans_start last_rx\n");
printk(KERN_INFO "%-15s %016lX %016lX %016lX\n",
- netdev->name,
- netdev->state,
- netdev->trans_start,
- netdev->last_rx);
+ netdev->name, netdev->state, netdev->trans_start,
+ netdev->last_rx);
}
/* Print Registers */
@@ -214,26 +219,26 @@ static void e1000e_dump(struct e1000_adapter *adapter)
e1000_regdump(hw, reginfo);
}
- /* Print TX Ring Summary */
+ /* Print Tx Ring Summary */
if (!netdev || !netif_running(netdev))
goto exit;
- dev_info(&adapter->pdev->dev, "TX Rings Summary\n");
+ dev_info(&adapter->pdev->dev, "Tx Ring Summary\n");
printk(KERN_INFO "Queue [NTU] [NTC] [bi(ntc)->dma ]"
- " leng ntw timestamp\n");
+ " leng ntw timestamp\n");
buffer_info = &tx_ring->buffer_info[tx_ring->next_to_clean];
printk(KERN_INFO " %5d %5X %5X %016llX %04X %3X %016llX\n",
- 0, tx_ring->next_to_use, tx_ring->next_to_clean,
- (unsigned long long)buffer_info->dma,
- buffer_info->length,
- buffer_info->next_to_watch,
- (unsigned long long)buffer_info->time_stamp);
+ 0, tx_ring->next_to_use, tx_ring->next_to_clean,
+ (unsigned long long)buffer_info->dma,
+ buffer_info->length,
+ buffer_info->next_to_watch,
+ (unsigned long long)buffer_info->time_stamp);
- /* Print TX Rings */
+ /* Print Tx Ring */
if (!netif_msg_tx_done(adapter))
goto rx_ring_summary;
- dev_info(&adapter->pdev->dev, "TX Rings Dump\n");
+ dev_info(&adapter->pdev->dev, "Tx Ring Dump\n");
/* Transmit Descriptor Formats - DEXT[29] is 0 (Legacy) or 1 (Extended)
*
@@ -263,22 +268,22 @@ static void e1000e_dump(struct e1000_adapter *adapter)
* 63 48 47 40 39 36 35 32 31 24 23 20 19 0
*/
printk(KERN_INFO "Tl[desc] [address 63:0 ] [SpeCssSCmCsLen]"
- " [bi->dma ] leng ntw timestamp bi->skb "
- "<-- Legacy format\n");
+ " [bi->dma ] leng ntw timestamp bi->skb "
+ "<-- Legacy format\n");
printk(KERN_INFO "Tc[desc] [Ce CoCsIpceCoS] [MssHlRSCm0Plen]"
- " [bi->dma ] leng ntw timestamp bi->skb "
- "<-- Ext Context format\n");
+ " [bi->dma ] leng ntw timestamp bi->skb "
+ "<-- Ext Context format\n");
printk(KERN_INFO "Td[desc] [address 63:0 ] [VlaPoRSCm1Dlen]"
- " [bi->dma ] leng ntw timestamp bi->skb "
- "<-- Ext Data format\n");
+ " [bi->dma ] leng ntw timestamp bi->skb "
+ "<-- Ext Data format\n");
for (i = 0; tx_ring->desc && (i < tx_ring->count); i++) {
tx_desc = E1000_TX_DESC(*tx_ring, i);
buffer_info = &tx_ring->buffer_info[i];
u0 = (struct my_u0 *)tx_desc;
printk(KERN_INFO "T%c[0x%03X] %016llX %016llX %016llX "
- "%04X %3X %016llX %p",
- (!(le64_to_cpu(u0->b) & (1<<29)) ? 'l' :
- ((le64_to_cpu(u0->b) & (1<<20)) ? 'd' : 'c')), i,
+ "%04X %3X %016llX %p",
+ (!(le64_to_cpu(u0->b) & (1 << 29)) ? 'l' :
+ ((le64_to_cpu(u0->b) & (1 << 20)) ? 'd' : 'c')), i,
(unsigned long long)le64_to_cpu(u0->a),
(unsigned long long)le64_to_cpu(u0->b),
(unsigned long long)buffer_info->dma,
@@ -296,22 +301,22 @@ static void e1000e_dump(struct e1000_adapter *adapter)
if (netif_msg_pktdata(adapter) && buffer_info->dma != 0)
print_hex_dump(KERN_INFO, "", DUMP_PREFIX_ADDRESS,
- 16, 1, phys_to_virt(buffer_info->dma),
- buffer_info->length, true);
+ 16, 1, phys_to_virt(buffer_info->dma),
+ buffer_info->length, true);
}
- /* Print RX Rings Summary */
+ /* Print Rx Ring Summary */
rx_ring_summary:
- dev_info(&adapter->pdev->dev, "RX Rings Summary\n");
+ dev_info(&adapter->pdev->dev, "Rx Ring Summary\n");
printk(KERN_INFO "Queue [NTU] [NTC]\n");
printk(KERN_INFO " %5d %5X %5X\n", 0,
- rx_ring->next_to_use, rx_ring->next_to_clean);
+ rx_ring->next_to_use, rx_ring->next_to_clean);
- /* Print RX Rings */
+ /* Print Rx Ring */
if (!netif_msg_rx_status(adapter))
goto exit;
- dev_info(&adapter->pdev->dev, "RX Rings Dump\n");
+ dev_info(&adapter->pdev->dev, "Rx Ring Dump\n");
switch (adapter->rx_ps_pages) {
case 1:
case 2:
@@ -329,7 +334,7 @@ rx_ring_summary:
* +-----------------------------------------------------+
*/
printk(KERN_INFO "R [desc] [buffer 0 63:0 ] "
- "[buffer 1 63:0 ] "
+ "[buffer 1 63:0 ] "
"[buffer 2 63:0 ] [buffer 3 63:0 ] [bi->dma ] "
"[bi->skb] <-- Ext Pkt Split format\n");
/* [Extended] Receive Descriptor (Write-Back) Format
@@ -344,7 +349,7 @@ rx_ring_summary:
* 63 48 47 32 31 20 19 0
*/
printk(KERN_INFO "RWB[desc] [ck ipid mrqhsh] "
- "[vl l0 ee es] "
+ "[vl l0 ee es] "
"[ l3 l2 l1 hs] [reserved ] ---------------- "
"[bi->skb] <-- Ext Rx Write-Back format\n");
for (i = 0; i < rx_ring->count; i++) {
@@ -352,26 +357,26 @@ rx_ring_summary:
rx_desc_ps = E1000_RX_DESC_PS(*rx_ring, i);
u1 = (struct my_u1 *)rx_desc_ps;
staterr =
- le32_to_cpu(rx_desc_ps->wb.middle.status_error);
+ le32_to_cpu(rx_desc_ps->wb.middle.status_error);
if (staterr & E1000_RXD_STAT_DD) {
/* Descriptor Done */
printk(KERN_INFO "RWB[0x%03X] %016llX "
- "%016llX %016llX %016llX "
- "---------------- %p", i,
- (unsigned long long)le64_to_cpu(u1->a),
- (unsigned long long)le64_to_cpu(u1->b),
- (unsigned long long)le64_to_cpu(u1->c),
- (unsigned long long)le64_to_cpu(u1->d),
- buffer_info->skb);
+ "%016llX %016llX %016llX "
+ "---------------- %p", i,
+ (unsigned long long)le64_to_cpu(u1->a),
+ (unsigned long long)le64_to_cpu(u1->b),
+ (unsigned long long)le64_to_cpu(u1->c),
+ (unsigned long long)le64_to_cpu(u1->d),
+ buffer_info->skb);
} else {
printk(KERN_INFO "R [0x%03X] %016llX "
- "%016llX %016llX %016llX %016llX %p", i,
- (unsigned long long)le64_to_cpu(u1->a),
- (unsigned long long)le64_to_cpu(u1->b),
- (unsigned long long)le64_to_cpu(u1->c),
- (unsigned long long)le64_to_cpu(u1->d),
- (unsigned long long)buffer_info->dma,
- buffer_info->skb);
+ "%016llX %016llX %016llX %016llX %p", i,
+ (unsigned long long)le64_to_cpu(u1->a),
+ (unsigned long long)le64_to_cpu(u1->b),
+ (unsigned long long)le64_to_cpu(u1->c),
+ (unsigned long long)le64_to_cpu(u1->d),
+ (unsigned long long)buffer_info->dma,
+ buffer_info->skb);
if (netif_msg_pktdata(adapter))
print_hex_dump(KERN_INFO, "",
@@ -400,18 +405,18 @@ rx_ring_summary:
* 63 48 47 40 39 32 31 16 15 0
*/
printk(KERN_INFO "Rl[desc] [address 63:0 ] "
- "[vl er S cks ln] [bi->dma ] [bi->skb] "
- "<-- Legacy format\n");
+ "[vl er S cks ln] [bi->dma ] [bi->skb] "
+ "<-- Legacy format\n");
for (i = 0; rx_ring->desc && (i < rx_ring->count); i++) {
rx_desc = E1000_RX_DESC(*rx_ring, i);
buffer_info = &rx_ring->buffer_info[i];
u0 = (struct my_u0 *)rx_desc;
printk(KERN_INFO "Rl[0x%03X] %016llX %016llX "
- "%016llX %p", i,
- (unsigned long long)le64_to_cpu(u0->a),
- (unsigned long long)le64_to_cpu(u0->b),
- (unsigned long long)buffer_info->dma,
- buffer_info->skb);
+ "%016llX %p", i,
+ (unsigned long long)le64_to_cpu(u0->a),
+ (unsigned long long)le64_to_cpu(u0->b),
+ (unsigned long long)buffer_info->dma,
+ buffer_info->skb);
if (i == rx_ring->next_to_use)
printk(KERN_CONT " NTU\n");
else if (i == rx_ring->next_to_clean)
@@ -421,9 +426,10 @@ rx_ring_summary:
if (netif_msg_pktdata(adapter))
print_hex_dump(KERN_INFO, "",
- DUMP_PREFIX_ADDRESS,
- 16, 1, phys_to_virt(buffer_info->dma),
- adapter->rx_buffer_len, true);
+ DUMP_PREFIX_ADDRESS,
+ 16, 1,
+ phys_to_virt(buffer_info->dma),
+ adapter->rx_buffer_len, true);
}
}
@@ -450,8 +456,7 @@ static int e1000_desc_unused(struct e1000_ring *ring)
* @skb: pointer to sk_buff to be indicated to stack
**/
static void e1000_receive_skb(struct e1000_adapter *adapter,
- struct net_device *netdev,
- struct sk_buff *skb,
+ struct net_device *netdev, struct sk_buff *skb,
u8 status, __le16 vlan)
{
skb->protocol = eth_type_trans(skb, netdev);
@@ -464,7 +469,7 @@ static void e1000_receive_skb(struct e1000_adapter *adapter,
}
/**
- * e1000_rx_checksum - Receive Checksum Offload for 82543
+ * e1000_rx_checksum - Receive Checksum Offload
* @adapter: board private structure
* @status_err: receive descriptor status and error fields
* @csum: receive descriptor csum field
@@ -548,7 +553,7 @@ map_skb:
adapter->rx_buffer_len,
DMA_FROM_DEVICE);
if (dma_mapping_error(&pdev->dev, buffer_info->dma)) {
- dev_err(&pdev->dev, "RX DMA map failed\n");
+ dev_err(&pdev->dev, "Rx DMA map failed\n");
adapter->rx_dma_failed++;
break;
}
@@ -601,7 +606,8 @@ static void e1000_alloc_rx_buffers_ps(struct e1000_adapter *adapter,
ps_page = &buffer_info->ps_pages[j];
if (j >= adapter->rx_ps_pages) {
/* all unused desc entries get hw null ptr */
- rx_desc->read.buffer_addr[j+1] = ~cpu_to_le64(0);
+ rx_desc->read.buffer_addr[j + 1] =
+ ~cpu_to_le64(0);
continue;
}
if (!ps_page->page) {
@@ -617,7 +623,7 @@ static void e1000_alloc_rx_buffers_ps(struct e1000_adapter *adapter,
if (dma_mapping_error(&pdev->dev,
ps_page->dma)) {
dev_err(&adapter->pdev->dev,
- "RX DMA page map failed\n");
+ "Rx DMA page map failed\n");
adapter->rx_dma_failed++;
goto no_buffers;
}
@@ -627,8 +633,8 @@ static void e1000_alloc_rx_buffers_ps(struct e1000_adapter *adapter,
* didn't change because each write-back
* erases this info.
*/
- rx_desc->read.buffer_addr[j+1] =
- cpu_to_le64(ps_page->dma);
+ rx_desc->read.buffer_addr[j + 1] =
+ cpu_to_le64(ps_page->dma);
}
skb = netdev_alloc_skb_ip_align(netdev,
@@ -644,7 +650,7 @@ static void e1000_alloc_rx_buffers_ps(struct e1000_adapter *adapter,
adapter->rx_ps_bsize0,
DMA_FROM_DEVICE);
if (dma_mapping_error(&pdev->dev, buffer_info->dma)) {
- dev_err(&pdev->dev, "RX DMA map failed\n");
+ dev_err(&pdev->dev, "Rx DMA map failed\n");
adapter->rx_dma_failed++;
/* cleanup skb */
dev_kfree_skb_any(skb);
@@ -662,7 +668,7 @@ static void e1000_alloc_rx_buffers_ps(struct e1000_adapter *adapter,
* such as IA-64).
*/
wmb();
- writel(i<<1, adapter->hw.hw_addr + rx_ring->tail);
+ writel(i << 1, adapter->hw.hw_addr + rx_ring->tail);
}
i++;
@@ -1106,11 +1112,10 @@ static bool e1000_clean_rx_irq_ps(struct e1000_adapter *adapter,
cleaned = 1;
cleaned_count++;
dma_unmap_single(&pdev->dev, buffer_info->dma,
- adapter->rx_ps_bsize0,
- DMA_FROM_DEVICE);
+ adapter->rx_ps_bsize0, DMA_FROM_DEVICE);
buffer_info->dma = 0;
- /* see !EOP comment in other rx routine */
+ /* see !EOP comment in other Rx routine */
if (!(staterr & E1000_RXD_STAT_EOP))
adapter->flags2 |= FLAG2_IS_DISCARDING;
@@ -2610,7 +2615,7 @@ static void e1000_init_manageability_pt(struct e1000_adapter *adapter)
}
/**
- * e1000_configure_tx - Configure 8254x Transmit Unit after Reset
+ * e1000_configure_tx - Configure Transmit Unit after Reset
* @adapter: board private structure
*
* Configure the Tx unit of the MAC after a reset.
@@ -2663,7 +2668,7 @@ static void e1000_configure_tx(struct e1000_adapter *adapter)
* hthresh = 1 ==> prefetch when one or more available
* pthresh = 0x1f ==> prefetch if internal cache 31 or less
* BEWARE: this seems to work but should be considered first if
- * there are tx hangs or other tx related bugs
+ * there are Tx hangs or other Tx related bugs
*/
txdctl |= E1000_TXDCTL_DMA_BURST_ENABLE;
ew32(TXDCTL(0), txdctl);
@@ -2877,7 +2882,7 @@ static void e1000_configure_rx(struct e1000_adapter *adapter)
if (adapter->rx_ps_pages) {
/* this is a 32 byte descriptor */
rdlen = rx_ring->count *
- sizeof(union e1000_rx_desc_packet_split);
+ sizeof(union e1000_rx_desc_packet_split);
adapter->clean_rx = e1000_clean_rx_irq_ps;
adapter->alloc_rx_buf = e1000_alloc_rx_buffers_ps;
} else if (adapter->netdev->mtu > ETH_FRAME_LEN + ETH_FCS_LEN) {
@@ -2900,7 +2905,7 @@ static void e1000_configure_rx(struct e1000_adapter *adapter)
/*
* set the writeback threshold (only takes effect if the RDTR
* is set). set GRAN=1 and write back up to 0x4 worth, and
- * enable prefetching of 0x20 rx descriptors
+ * enable prefetching of 0x20 Rx descriptors
* granularity = 01
* wthresh = 04,
* hthresh = 04,
@@ -2981,12 +2986,10 @@ static void e1000_configure_rx(struct e1000_adapter *adapter)
* excessive C-state transition latencies result in
* dropped transactions.
*/
- pm_qos_update_request(
- &adapter->netdev->pm_qos_req, 55);
+ pm_qos_update_request(&adapter->netdev->pm_qos_req, 55);
} else {
- pm_qos_update_request(
- &adapter->netdev->pm_qos_req,
- PM_QOS_DEFAULT_VALUE);
+ pm_qos_update_request(&adapter->netdev->pm_qos_req,
+ PM_QOS_DEFAULT_VALUE);
}
}
@@ -3152,7 +3155,7 @@ void e1000e_reset(struct e1000_adapter *adapter)
/* lower 16 bits has Rx packet buffer allocation size in KB */
pba &= 0xffff;
/*
- * the Tx fifo also stores 16 bytes of information about the tx
+ * the Tx fifo also stores 16 bytes of information about the Tx
* but don't include ethernet FCS because hardware appends it
*/
min_tx_space = (adapter->max_frame_size +
@@ -3175,7 +3178,7 @@ void e1000e_reset(struct e1000_adapter *adapter)
pba -= min_tx_space - tx_space;
/*
- * if short on Rx space, Rx wins and must trump tx
+ * if short on Rx space, Rx wins and must trump Tx
* adjustment or use Early Receive if available
*/
if ((pba < min_rx_space) &&
@@ -4039,11 +4042,11 @@ static void e1000_print_link_info(struct e1000_adapter *adapter)
adapter->netdev->name,
adapter->link_speed,
(adapter->link_duplex == FULL_DUPLEX) ?
- "Full Duplex" : "Half Duplex",
+ "Full Duplex" : "Half Duplex",
((ctrl & E1000_CTRL_TFCE) && (ctrl & E1000_CTRL_RFCE)) ?
- "RX/TX" :
- ((ctrl & E1000_CTRL_RFCE) ? "RX" :
- ((ctrl & E1000_CTRL_TFCE) ? "TX" : "None" )));
+ "Rx/Tx" :
+ ((ctrl & E1000_CTRL_RFCE) ? "Rx" :
+ ((ctrl & E1000_CTRL_TFCE) ? "Tx" : "None")));
}
static bool e1000e_has_link(struct e1000_adapter *adapter)
@@ -4338,7 +4341,7 @@ link_up:
/* Force detection of hung controller every watchdog period */
adapter->detect_tx_hung = 1;
- /* flush partial descriptors to memory before detecting tx hang */
+ /* flush partial descriptors to memory before detecting Tx hang */
if (adapter->flags2 & FLAG2_DMA_BURST) {
ew32(TIDV, adapter->tx_int_delay | E1000_TIDV_FPD);
ew32(RDTR, adapter->rx_int_delay | E1000_RDTR_FPD);
@@ -4529,7 +4532,7 @@ static int e1000_tx_map(struct e1000_adapter *adapter,
buffer_info->next_to_watch = i;
buffer_info->dma = dma_map_single(&pdev->dev,
skb->data + offset,
- size, DMA_TO_DEVICE);
+ size, DMA_TO_DEVICE);
buffer_info->mapped_as_page = false;
if (dma_mapping_error(&pdev->dev, buffer_info->dma))
goto dma_error;
@@ -4576,7 +4579,7 @@ static int e1000_tx_map(struct e1000_adapter *adapter,
}
}
- segs = skb_shinfo(skb)->gso_segs ?: 1;
+ segs = skb_shinfo(skb)->gso_segs ? : 1;
/* multiply data chunks by size of headers */
bytecount = ((segs - 1) * skb_headlen(skb)) + skb->len;
@@ -4588,13 +4591,13 @@ static int e1000_tx_map(struct e1000_adapter *adapter,
return count;
dma_error:
- dev_err(&pdev->dev, "TX DMA map failed\n");
+ dev_err(&pdev->dev, "Tx DMA map failed\n");
buffer_info->dma = 0;
if (count)
count--;
while (count--) {
- if (i==0)
+ if (i == 0)
i += tx_ring->count;
i--;
buffer_info = &tx_ring->buffer_info[i];
@@ -6193,7 +6196,7 @@ static int __init e1000_init_module(void)
int ret;
pr_info("Intel(R) PRO/1000 Network Driver - %s\n",
e1000e_driver_version);
- pr_info("Copyright (c) 1999 - 2010 Intel Corporation.\n");
+ pr_info("Copyright(c) 1999 - 2011 Intel Corporation.\n");
ret = pci_register_driver(&e1000_driver);
return ret;
diff --git a/drivers/net/e1000e/param.c b/drivers/net/e1000e/param.c
index a9612b0..4dd9b63 100644
--- a/drivers/net/e1000e/param.c
+++ b/drivers/net/e1000e/param.c
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel PRO/1000 Linux driver
- Copyright(c) 1999 - 2010 Intel Corporation.
+ Copyright(c) 1999 - 2011 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,
@@ -62,10 +62,9 @@ MODULE_PARM_DESC(copybreak,
module_param_array_named(X, X, int, &num_##X, 0); \
MODULE_PARM_DESC(X, desc);
-
/*
* Transmit Interrupt Delay in units of 1.024 microseconds
- * Tx interrupt delay needs to typically be set to something non zero
+ * Tx interrupt delay needs to typically be set to something non-zero
*
* Valid Range: 0-65535
*/
@@ -112,6 +111,7 @@ E1000_PARAM(InterruptThrottleRate, "Interrupt Throttling Rate");
#define DEFAULT_ITR 3
#define MAX_ITR 100000
#define MIN_ITR 100
+
/* IntMode (Interrupt Mode)
*
* Valid Range: 0 - 2
diff --git a/drivers/net/e1000e/phy.c b/drivers/net/e1000e/phy.c
index 00f89e8..6bea051 100644
--- a/drivers/net/e1000e/phy.c
+++ b/drivers/net/e1000e/phy.c
@@ -1,7 +1,7 @@
/*******************************************************************************
Intel PRO/1000 Linux driver
- Copyright(c) 1999 - 2010 Intel Corporation.
+ Copyright(c) 1999 - 2011 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,
@@ -640,7 +640,7 @@ s32 e1000_copper_link_setup_82577(struct e1000_hw *hw)
s32 ret_val;
u16 phy_data;
- /* Enable CRS on TX. This must be set for half-duplex operation. */
+ /* Enable CRS on Tx. This must be set for half-duplex operation. */
ret_val = e1e_rphy(hw, I82577_CFG_REG, &phy_data);
if (ret_val)
goto out;
diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c
index 6de4675..5ed8f9f9 100644
--- a/drivers/net/gianfar.c
+++ b/drivers/net/gianfar.c
@@ -434,7 +434,6 @@ static void gfar_init_mac(struct net_device *ndev)
static struct net_device_stats *gfar_get_stats(struct net_device *dev)
{
struct gfar_private *priv = netdev_priv(dev);
- struct netdev_queue *txq;
unsigned long rx_packets = 0, rx_bytes = 0, rx_dropped = 0;
unsigned long tx_packets = 0, tx_bytes = 0;
int i = 0;
@@ -450,9 +449,8 @@ static struct net_device_stats *gfar_get_stats(struct net_device *dev)
dev->stats.rx_dropped = rx_dropped;
for (i = 0; i < priv->num_tx_queues; i++) {
- txq = netdev_get_tx_queue(dev, i);
- tx_bytes += txq->tx_bytes;
- tx_packets += txq->tx_packets;
+ tx_bytes += priv->tx_queue[i]->stats.tx_bytes;
+ tx_packets += priv->tx_queue[i]->stats.tx_packets;
}
dev->stats.tx_bytes = tx_bytes;
@@ -1922,7 +1920,7 @@ int startup_gfar(struct net_device *ndev)
if (err) {
for (j = 0; j < i; j++)
free_grp_irqs(&priv->gfargrp[j]);
- goto irq_fail;
+ goto irq_fail;
}
}
@@ -2109,8 +2107,8 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
}
/* Update transmit stats */
- txq->tx_bytes += skb->len;
- txq->tx_packets ++;
+ tx_queue->stats.tx_bytes += skb->len;
+ tx_queue->stats.tx_packets++;
txbdp = txbdp_start = tx_queue->cur_tx;
lstatus = txbdp->lstatus;
diff --git a/drivers/net/gianfar.h b/drivers/net/gianfar.h
index 68984eb..54de413 100644
--- a/drivers/net/gianfar.h
+++ b/drivers/net/gianfar.h
@@ -907,12 +907,21 @@ enum {
MQ_MG_MODE
};
+/*
+ * Per TX queue stats
+ */
+struct tx_q_stats {
+ unsigned long tx_packets;
+ unsigned long tx_bytes;
+};
+
/**
* struct gfar_priv_tx_q - per tx queue structure
* @txlock: per queue tx spin lock
* @tx_skbuff:skb pointers
* @skb_curtx: to be used skb pointer
* @skb_dirtytx:the last used skb pointer
+ * @stats: bytes/packets stats
* @qindex: index of this queue
* @dev: back pointer to the dev structure
* @grp: back pointer to the group to which this queue belongs
@@ -934,6 +943,7 @@ struct gfar_priv_tx_q {
struct txbd8 *tx_bd_base;
struct txbd8 *cur_tx;
struct txbd8 *dirty_tx;
+ struct tx_q_stats stats;
struct net_device *dev;
struct gfar_priv_grp *grp;
u16 skb_curtx;
diff --git a/drivers/net/greth.c b/drivers/net/greth.c
index 27d6960..fdb0333 100644
--- a/drivers/net/greth.c
+++ b/drivers/net/greth.c
@@ -1,7 +1,7 @@
/*
* Aeroflex Gaisler GRETH 10/100/1G Ethernet MAC.
*
- * 2005-2009 (c) Aeroflex Gaisler AB
+ * 2005-2010 (c) Aeroflex Gaisler AB
*
* This driver supports GRETH 10/100 and GRETH 10/100/1G Ethernet MACs
* available in the GRLIB VHDL IP core library.
@@ -356,6 +356,8 @@ static int greth_open(struct net_device *dev)
dev_dbg(&dev->dev, " starting queue\n");
netif_start_queue(dev);
+ GRETH_REGSAVE(greth->regs->status, 0xFF);
+
napi_enable(&greth->napi);
greth_enable_irqs(greth);
@@ -371,7 +373,9 @@ static int greth_close(struct net_device *dev)
napi_disable(&greth->napi);
+ greth_disable_irqs(greth);
greth_disable_tx(greth);
+ greth_disable_rx(greth);
netif_stop_queue(dev);
@@ -388,12 +392,20 @@ greth_start_xmit(struct sk_buff *skb, struct net_device *dev)
struct greth_private *greth = netdev_priv(dev);
struct greth_bd *bdp;
int err = NETDEV_TX_OK;
- u32 status, dma_addr;
+ u32 status, dma_addr, ctrl;
+ unsigned long flags;
- bdp = greth->tx_bd_base + greth->tx_next;
+ /* Clean TX Ring */
+ greth_clean_tx(greth->netdev);
if (unlikely(greth->tx_free <= 0)) {
+ spin_lock_irqsave(&greth->devlock, flags);/*save from poll/irq*/
+ ctrl = GRETH_REGLOAD(greth->regs->control);
+ /* Enable TX IRQ only if not already in poll() routine */
+ if (ctrl & GRETH_RXI)
+ GRETH_REGSAVE(greth->regs->control, ctrl | GRETH_TXI);
netif_stop_queue(dev);
+ spin_unlock_irqrestore(&greth->devlock, flags);
return NETDEV_TX_BUSY;
}
@@ -406,13 +418,14 @@ greth_start_xmit(struct sk_buff *skb, struct net_device *dev)
goto out;
}
+ bdp = greth->tx_bd_base + greth->tx_next;
dma_addr = greth_read_bd(&bdp->addr);
memcpy((unsigned char *) phys_to_virt(dma_addr), skb->data, skb->len);
dma_sync_single_for_device(greth->dev, dma_addr, skb->len, DMA_TO_DEVICE);
- status = GRETH_BD_EN | (skb->len & GRETH_BD_LEN);
+ status = GRETH_BD_EN | GRETH_BD_IE | (skb->len & GRETH_BD_LEN);
/* Wrap around descriptor ring */
if (greth->tx_next == GRETH_TXBD_NUM_MASK) {
@@ -422,22 +435,11 @@ greth_start_xmit(struct sk_buff *skb, struct net_device *dev)
greth->tx_next = NEXT_TX(greth->tx_next);
greth->tx_free--;
- /* No more descriptors */
- if (unlikely(greth->tx_free == 0)) {
-
- /* Free transmitted descriptors */
- greth_clean_tx(dev);
-
- /* If nothing was cleaned, stop queue & wait for irq */
- if (unlikely(greth->tx_free == 0)) {
- status |= GRETH_BD_IE;
- netif_stop_queue(dev);
- }
- }
-
/* Write descriptor control word and enable transmission */
greth_write_bd(&bdp->stat, status);
+ spin_lock_irqsave(&greth->devlock, flags); /*save from poll/irq*/
greth_enable_tx(greth);
+ spin_unlock_irqrestore(&greth->devlock, flags);
out:
dev_kfree_skb(skb);
@@ -450,13 +452,23 @@ greth_start_xmit_gbit(struct sk_buff *skb, struct net_device *dev)
{
struct greth_private *greth = netdev_priv(dev);
struct greth_bd *bdp;
- u32 status = 0, dma_addr;
+ u32 status = 0, dma_addr, ctrl;
int curr_tx, nr_frags, i, err = NETDEV_TX_OK;
+ unsigned long flags;
nr_frags = skb_shinfo(skb)->nr_frags;
+ /* Clean TX Ring */
+ greth_clean_tx_gbit(dev);
+
if (greth->tx_free < nr_frags + 1) {
+ spin_lock_irqsave(&greth->devlock, flags);/*save from poll/irq*/
+ ctrl = GRETH_REGLOAD(greth->regs->control);
+ /* Enable TX IRQ only if not already in poll() routine */
+ if (ctrl & GRETH_RXI)
+ GRETH_REGSAVE(greth->regs->control, ctrl | GRETH_TXI);
netif_stop_queue(dev);
+ spin_unlock_irqrestore(&greth->devlock, flags);
err = NETDEV_TX_BUSY;
goto out;
}
@@ -499,7 +511,7 @@ greth_start_xmit_gbit(struct sk_buff *skb, struct net_device *dev)
greth->tx_skbuff[curr_tx] = NULL;
bdp = greth->tx_bd_base + curr_tx;
- status = GRETH_TXBD_CSALL;
+ status = GRETH_TXBD_CSALL | GRETH_BD_EN;
status |= frag->size & GRETH_BD_LEN;
/* Wrap around descriptor ring */
@@ -509,14 +521,8 @@ greth_start_xmit_gbit(struct sk_buff *skb, struct net_device *dev)
/* More fragments left */
if (i < nr_frags - 1)
status |= GRETH_TXBD_MORE;
-
- /* ... last fragment, check if out of descriptors */
- else if (greth->tx_free - nr_frags - 1 < (MAX_SKB_FRAGS + 1)) {
-
- /* Enable interrupts and stop queue */
- status |= GRETH_BD_IE;
- netif_stop_queue(dev);
- }
+ else
+ status |= GRETH_BD_IE; /* enable IRQ on last fragment */
greth_write_bd(&bdp->stat, status);
@@ -536,26 +542,29 @@ greth_start_xmit_gbit(struct sk_buff *skb, struct net_device *dev)
wmb();
- /* Enable the descriptors that we configured ... */
- for (i = 0; i < nr_frags + 1; i++) {
- bdp = greth->tx_bd_base + greth->tx_next;
- greth_write_bd(&bdp->stat, greth_read_bd(&bdp->stat) | GRETH_BD_EN);
- greth->tx_next = NEXT_TX(greth->tx_next);
- greth->tx_free--;
- }
+ /* Enable the descriptor chain by enabling the first descriptor */
+ bdp = greth->tx_bd_base + greth->tx_next;
+ greth_write_bd(&bdp->stat, greth_read_bd(&bdp->stat) | GRETH_BD_EN);
+ greth->tx_next = curr_tx;
+ greth->tx_free -= nr_frags + 1;
+ wmb();
+
+ spin_lock_irqsave(&greth->devlock, flags); /*save from poll/irq*/
greth_enable_tx(greth);
+ spin_unlock_irqrestore(&greth->devlock, flags);
return NETDEV_TX_OK;
frag_map_error:
- /* Unmap SKB mappings that succeeded */
+ /* Unmap SKB mappings that succeeded and disable descriptor */
for (i = 0; greth->tx_next + i != curr_tx; i++) {
bdp = greth->tx_bd_base + greth->tx_next + i;
dma_unmap_single(greth->dev,
greth_read_bd(&bdp->addr),
greth_read_bd(&bdp->stat) & GRETH_BD_LEN,
DMA_TO_DEVICE);
+ greth_write_bd(&bdp->stat, 0);
}
map_error:
if (net_ratelimit())
@@ -565,12 +574,11 @@ out:
return err;
}
-
static irqreturn_t greth_interrupt(int irq, void *dev_id)
{
struct net_device *dev = dev_id;
struct greth_private *greth;
- u32 status;
+ u32 status, ctrl;
irqreturn_t retval = IRQ_NONE;
greth = netdev_priv(dev);
@@ -580,13 +588,15 @@ static irqreturn_t greth_interrupt(int irq, void *dev_id)
/* Get the interrupt events that caused us to be here. */
status = GRETH_REGLOAD(greth->regs->status);
- /* Handle rx and tx interrupts through poll */
- if (status & (GRETH_INT_RX | GRETH_INT_TX)) {
-
- /* Clear interrupt status */
- GRETH_REGORIN(greth->regs->status,
- status & (GRETH_INT_RX | GRETH_INT_TX));
+ /* Must see if interrupts are enabled also, INT_TX|INT_RX flags may be
+ * set regardless of whether IRQ is enabled or not. Especially
+ * important when shared IRQ.
+ */
+ ctrl = GRETH_REGLOAD(greth->regs->control);
+ /* Handle rx and tx interrupts through poll */
+ if (((status & (GRETH_INT_RE | GRETH_INT_RX)) && (ctrl & GRETH_RXI)) ||
+ ((status & (GRETH_INT_TE | GRETH_INT_TX)) && (ctrl & GRETH_TXI))) {
retval = IRQ_HANDLED;
/* Disable interrupts and schedule poll() */
@@ -610,6 +620,8 @@ static void greth_clean_tx(struct net_device *dev)
while (1) {
bdp = greth->tx_bd_base + greth->tx_last;
+ GRETH_REGSAVE(greth->regs->status, GRETH_INT_TE | GRETH_INT_TX);
+ mb();
stat = greth_read_bd(&bdp->stat);
if (unlikely(stat & GRETH_BD_EN))
@@ -670,7 +682,10 @@ static void greth_clean_tx_gbit(struct net_device *dev)
/* We only clean fully completed SKBs */
bdp_last_frag = greth->tx_bd_base + SKIP_TX(greth->tx_last, nr_frags);
- stat = bdp_last_frag->stat;
+
+ GRETH_REGSAVE(greth->regs->status, GRETH_INT_TE | GRETH_INT_TX);
+ mb();
+ stat = greth_read_bd(&bdp_last_frag->stat);
if (stat & GRETH_BD_EN)
break;
@@ -702,21 +717,9 @@ static void greth_clean_tx_gbit(struct net_device *dev)
greth->tx_free += nr_frags+1;
dev_kfree_skb(skb);
}
- if (greth->tx_free > (MAX_SKB_FRAGS + 1)) {
- netif_wake_queue(dev);
- }
-}
-static int greth_pending_packets(struct greth_private *greth)
-{
- struct greth_bd *bdp;
- u32 status;
- bdp = greth->rx_bd_base + greth->rx_cur;
- status = greth_read_bd(&bdp->stat);
- if (status & GRETH_BD_EN)
- return 0;
- else
- return 1;
+ if (netif_queue_stopped(dev) && (greth->tx_free > (MAX_SKB_FRAGS+1)))
+ netif_wake_queue(dev);
}
static int greth_rx(struct net_device *dev, int limit)
@@ -727,20 +730,24 @@ static int greth_rx(struct net_device *dev, int limit)
int pkt_len;
int bad, count;
u32 status, dma_addr;
+ unsigned long flags;
greth = netdev_priv(dev);
for (count = 0; count < limit; ++count) {
bdp = greth->rx_bd_base + greth->rx_cur;
+ GRETH_REGSAVE(greth->regs->status, GRETH_INT_RE | GRETH_INT_RX);
+ mb();
status = greth_read_bd(&bdp->stat);
- dma_addr = greth_read_bd(&bdp->addr);
- bad = 0;
if (unlikely(status & GRETH_BD_EN)) {
break;
}
+ dma_addr = greth_read_bd(&bdp->addr);
+ bad = 0;
+
/* Check status for errors. */
if (unlikely(status & GRETH_RXBD_STATUS)) {
if (status & GRETH_RXBD_ERR_FT) {
@@ -802,7 +809,9 @@ static int greth_rx(struct net_device *dev, int limit)
dma_sync_single_for_device(greth->dev, dma_addr, MAX_FRAME_SIZE, DMA_FROM_DEVICE);
+ spin_lock_irqsave(&greth->devlock, flags); /* save from XMIT */
greth_enable_rx(greth);
+ spin_unlock_irqrestore(&greth->devlock, flags);
greth->rx_cur = NEXT_RX(greth->rx_cur);
}
@@ -836,6 +845,7 @@ static int greth_rx_gbit(struct net_device *dev, int limit)
int pkt_len;
int bad, count = 0;
u32 status, dma_addr;
+ unsigned long flags;
greth = netdev_priv(dev);
@@ -843,6 +853,8 @@ static int greth_rx_gbit(struct net_device *dev, int limit)
bdp = greth->rx_bd_base + greth->rx_cur;
skb = greth->rx_skbuff[greth->rx_cur];
+ GRETH_REGSAVE(greth->regs->status, GRETH_INT_RE | GRETH_INT_RX);
+ mb();
status = greth_read_bd(&bdp->stat);
bad = 0;
@@ -865,10 +877,9 @@ static int greth_rx_gbit(struct net_device *dev, int limit)
}
}
- /* Allocate new skb to replace current */
- newskb = netdev_alloc_skb(dev, MAX_FRAME_SIZE + NET_IP_ALIGN);
-
- if (!bad && newskb) {
+ /* Allocate new skb to replace current, not needed if the
+ * current skb can be reused */
+ if (!bad && (newskb=netdev_alloc_skb(dev, MAX_FRAME_SIZE + NET_IP_ALIGN))) {
skb_reserve(newskb, NET_IP_ALIGN);
dma_addr = dma_map_single(greth->dev,
@@ -905,11 +916,22 @@ static int greth_rx_gbit(struct net_device *dev, int limit)
if (net_ratelimit())
dev_warn(greth->dev, "Could not create DMA mapping, dropping packet\n");
dev_kfree_skb(newskb);
+ /* reusing current skb, so it is a drop */
dev->stats.rx_dropped++;
}
+ } else if (bad) {
+ /* Bad Frame transfer, the skb is reused */
+ dev->stats.rx_dropped++;
} else {
+ /* Failed Allocating a new skb. This is rather stupid
+ * but the current "filled" skb is reused, as if
+ * transfer failure. One could argue that RX descriptor
+ * table handling should be divided into cleaning and
+ * filling as the TX part of the driver
+ */
if (net_ratelimit())
dev_warn(greth->dev, "Could not allocate SKB, dropping packet\n");
+ /* reusing current skb, so it is a drop */
dev->stats.rx_dropped++;
}
@@ -920,7 +942,9 @@ static int greth_rx_gbit(struct net_device *dev, int limit)
wmb();
greth_write_bd(&bdp->stat, status);
+ spin_lock_irqsave(&greth->devlock, flags);
greth_enable_rx(greth);
+ spin_unlock_irqrestore(&greth->devlock, flags);
greth->rx_cur = NEXT_RX(greth->rx_cur);
}
@@ -932,15 +956,18 @@ static int greth_poll(struct napi_struct *napi, int budget)
{
struct greth_private *greth;
int work_done = 0;
+ unsigned long flags;
+ u32 mask, ctrl;
greth = container_of(napi, struct greth_private, napi);
- if (greth->gbit_mac) {
- greth_clean_tx_gbit(greth->netdev);
- } else {
- greth_clean_tx(greth->netdev);
+restart_txrx_poll:
+ if (netif_queue_stopped(greth->netdev)) {
+ if (greth->gbit_mac)
+ greth_clean_tx_gbit(greth->netdev);
+ else
+ greth_clean_tx(greth->netdev);
}
-restart_poll:
if (greth->gbit_mac) {
work_done += greth_rx_gbit(greth->netdev, budget - work_done);
} else {
@@ -949,15 +976,29 @@ restart_poll:
if (work_done < budget) {
- napi_complete(napi);
+ spin_lock_irqsave(&greth->devlock, flags);
+
+ ctrl = GRETH_REGLOAD(greth->regs->control);
+ if (netif_queue_stopped(greth->netdev)) {
+ GRETH_REGSAVE(greth->regs->control,
+ ctrl | GRETH_TXI | GRETH_RXI);
+ mask = GRETH_INT_RX | GRETH_INT_RE |
+ GRETH_INT_TX | GRETH_INT_TE;
+ } else {
+ GRETH_REGSAVE(greth->regs->control, ctrl | GRETH_RXI);
+ mask = GRETH_INT_RX | GRETH_INT_RE;
+ }
- if (greth_pending_packets(greth)) {
- napi_reschedule(napi);
- goto restart_poll;
+ if (GRETH_REGLOAD(greth->regs->status) & mask) {
+ GRETH_REGSAVE(greth->regs->control, ctrl);
+ spin_unlock_irqrestore(&greth->devlock, flags);
+ goto restart_txrx_poll;
+ } else {
+ __napi_complete(napi);
+ spin_unlock_irqrestore(&greth->devlock, flags);
}
}
- greth_enable_irqs(greth);
return work_done;
}
@@ -1152,11 +1193,11 @@ static const struct ethtool_ops greth_ethtool_ops = {
};
static struct net_device_ops greth_netdev_ops = {
- .ndo_open = greth_open,
- .ndo_stop = greth_close,
- .ndo_start_xmit = greth_start_xmit,
- .ndo_set_mac_address = greth_set_mac_add,
- .ndo_validate_addr = eth_validate_addr,
+ .ndo_open = greth_open,
+ .ndo_stop = greth_close,
+ .ndo_start_xmit = greth_start_xmit,
+ .ndo_set_mac_address = greth_set_mac_add,
+ .ndo_validate_addr = eth_validate_addr,
};
static inline int wait_for_mdio(struct greth_private *greth)
@@ -1217,29 +1258,26 @@ static void greth_link_change(struct net_device *dev)
struct greth_private *greth = netdev_priv(dev);
struct phy_device *phydev = greth->phy;
unsigned long flags;
-
int status_change = 0;
+ u32 ctrl;
spin_lock_irqsave(&greth->devlock, flags);
if (phydev->link) {
if ((greth->speed != phydev->speed) || (greth->duplex != phydev->duplex)) {
-
- GRETH_REGANDIN(greth->regs->control,
- ~(GRETH_CTRL_FD | GRETH_CTRL_SP | GRETH_CTRL_GB));
+ ctrl = GRETH_REGLOAD(greth->regs->control) &
+ ~(GRETH_CTRL_FD | GRETH_CTRL_SP | GRETH_CTRL_GB);
if (phydev->duplex)
- GRETH_REGORIN(greth->regs->control, GRETH_CTRL_FD);
-
- if (phydev->speed == SPEED_100) {
-
- GRETH_REGORIN(greth->regs->control, GRETH_CTRL_SP);
- }
+ ctrl |= GRETH_CTRL_FD;
+ if (phydev->speed == SPEED_100)
+ ctrl |= GRETH_CTRL_SP;
else if (phydev->speed == SPEED_1000)
- GRETH_REGORIN(greth->regs->control, GRETH_CTRL_GB);
+ ctrl |= GRETH_CTRL_GB;
+ GRETH_REGSAVE(greth->regs->control, ctrl);
greth->speed = phydev->speed;
greth->duplex = phydev->duplex;
status_change = 1;
@@ -1600,6 +1638,9 @@ static struct of_device_id greth_of_match[] = {
{
.name = "GAISLER_ETHMAC",
},
+ {
+ .name = "01_01d",
+ },
{},
};
diff --git a/drivers/net/greth.h b/drivers/net/greth.h
index 03ad903..be0f206 100644
--- a/drivers/net/greth.h
+++ b/drivers/net/greth.h
@@ -23,6 +23,7 @@
#define GRETH_BD_LEN 0x7FF
#define GRETH_TXEN 0x1
+#define GRETH_INT_TE 0x2
#define GRETH_INT_TX 0x8
#define GRETH_TXI 0x4
#define GRETH_TXBD_STATUS 0x0001C000
@@ -35,6 +36,7 @@
#define GRETH_TXBD_ERR_UE 0x4000
#define GRETH_TXBD_ERR_AL 0x8000
+#define GRETH_INT_RE 0x1
#define GRETH_INT_RX 0x4
#define GRETH_RXEN 0x2
#define GRETH_RXI 0x8
diff --git a/drivers/net/irda/sh_irda.c b/drivers/net/irda/sh_irda.c
index 9e3f4f5..4488bd5 100644
--- a/drivers/net/irda/sh_irda.c
+++ b/drivers/net/irda/sh_irda.c
@@ -635,7 +635,7 @@ static int sh_irda_hard_xmit(struct sk_buff *skb, struct net_device *ndev)
ret = sh_irda_set_baudrate(self, speed);
if (ret < 0)
- return ret;
+ goto sh_irda_hard_xmit_end;
self->tx_buff.len = 0;
if (skb->len) {
@@ -652,11 +652,21 @@ static int sh_irda_hard_xmit(struct sk_buff *skb, struct net_device *ndev)
sh_irda_write(self, IRTFLR, self->tx_buff.len);
sh_irda_write(self, IRTCTR, ARMOD | TE);
- }
+ } else
+ goto sh_irda_hard_xmit_end;
dev_kfree_skb(skb);
return 0;
+
+sh_irda_hard_xmit_end:
+ sh_irda_set_baudrate(self, 9600);
+ netif_wake_queue(self->ndev);
+ sh_irda_rcv_ctrl(self, 1);
+ dev_kfree_skb(skb);
+
+ return ret;
+
}
static int sh_irda_ioctl(struct net_device *ndev, struct ifreq *ifreq, int cmd)
diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c
index a060610..602078b 100644
--- a/drivers/net/ixgbe/ixgbe_main.c
+++ b/drivers/net/ixgbe/ixgbe_main.c
@@ -6667,8 +6667,6 @@ netdev_tx_t ixgbe_xmit_frame_ring(struct sk_buff *skb,
struct ixgbe_adapter *adapter,
struct ixgbe_ring *tx_ring)
{
- struct net_device *netdev = tx_ring->netdev;
- struct netdev_queue *txq;
unsigned int first;
unsigned int tx_flags = 0;
u8 hdr_len = 0;
@@ -6765,9 +6763,6 @@ netdev_tx_t ixgbe_xmit_frame_ring(struct sk_buff *skb,
/* add the ATR filter if ATR is on */
if (test_bit(__IXGBE_TX_FDIR_INIT_DONE, &tx_ring->state))
ixgbe_atr(tx_ring, skb, tx_flags, protocol);
- txq = netdev_get_tx_queue(netdev, tx_ring->queue_index);
- txq->tx_bytes += skb->len;
- txq->tx_packets++;
ixgbe_tx_queue(tx_ring, tx_flags, count, skb->len, hdr_len);
ixgbe_maybe_stop_tx(tx_ring, DESC_NEEDED);
@@ -6925,8 +6920,6 @@ static struct rtnl_link_stats64 *ixgbe_get_stats64(struct net_device *netdev,
struct ixgbe_adapter *adapter = netdev_priv(netdev);
int i;
- /* accurate rx/tx bytes/packets stats */
- dev_txq_stats_fold(netdev, stats);
rcu_read_lock();
for (i = 0; i < adapter->num_rx_queues; i++) {
struct ixgbe_ring *ring = ACCESS_ONCE(adapter->rx_ring[i]);
@@ -6943,6 +6936,22 @@ static struct rtnl_link_stats64 *ixgbe_get_stats64(struct net_device *netdev,
stats->rx_bytes += bytes;
}
}
+
+ for (i = 0; i < adapter->num_tx_queues; i++) {
+ struct ixgbe_ring *ring = ACCESS_ONCE(adapter->tx_ring[i]);
+ u64 bytes, packets;
+ unsigned int start;
+
+ if (ring) {
+ do {
+ start = u64_stats_fetch_begin_bh(&ring->syncp);
+ packets = ring->stats.packets;
+ bytes = ring->stats.bytes;
+ } while (u64_stats_fetch_retry_bh(&ring->syncp, start));
+ stats->tx_packets += packets;
+ stats->tx_bytes += bytes;
+ }
+ }
rcu_read_unlock();
/* following stats updated by ixgbe_watchdog_task() */
stats->multicast = netdev->stats.multicast;
diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c
index 21845af..5933621 100644
--- a/drivers/net/macvtap.c
+++ b/drivers/net/macvtap.c
@@ -585,7 +585,7 @@ err:
rcu_read_lock_bh();
vlan = rcu_dereference(q->vlan);
if (vlan)
- netdev_get_tx_queue(vlan->dev, 0)->tx_dropped++;
+ vlan->dev->stats.tx_dropped++;
rcu_read_unlock_bh();
return err;
diff --git a/drivers/net/mlx4/catas.c b/drivers/net/mlx4/catas.c
index 68aaa42..32f9471 100644
--- a/drivers/net/mlx4/catas.c
+++ b/drivers/net/mlx4/catas.c
@@ -113,7 +113,7 @@ static void catas_reset(struct work_struct *work)
void mlx4_start_catas_poll(struct mlx4_dev *dev)
{
struct mlx4_priv *priv = mlx4_priv(dev);
- unsigned long addr;
+ phys_addr_t addr;
INIT_LIST_HEAD(&priv->catas_err.list);
init_timer(&priv->catas_err.timer);
@@ -124,8 +124,8 @@ void mlx4_start_catas_poll(struct mlx4_dev *dev)
priv->catas_err.map = ioremap(addr, priv->fw.catas_size * 4);
if (!priv->catas_err.map) {
- mlx4_warn(dev, "Failed to map internal error buffer at 0x%lx\n",
- addr);
+ mlx4_warn(dev, "Failed to map internal error buffer at 0x%llx\n",
+ (unsigned long long) addr);
return;
}
diff --git a/drivers/net/mlx4/en_main.c b/drivers/net/mlx4/en_main.c
index f6e0d40..1ff6ca6 100644
--- a/drivers/net/mlx4/en_main.c
+++ b/drivers/net/mlx4/en_main.c
@@ -202,7 +202,8 @@ static void *mlx4_en_add(struct mlx4_dev *dev)
if (mlx4_uar_alloc(dev, &mdev->priv_uar))
goto err_pd;
- mdev->uar_map = ioremap(mdev->priv_uar.pfn << PAGE_SHIFT, PAGE_SIZE);
+ mdev->uar_map = ioremap((phys_addr_t) mdev->priv_uar.pfn << PAGE_SHIFT,
+ PAGE_SIZE);
if (!mdev->uar_map)
goto err_uar;
spin_lock_init(&mdev->uar_lock);
diff --git a/drivers/net/mlx4/main.c b/drivers/net/mlx4/main.c
index 782f11d..4ffdc18 100644
--- a/drivers/net/mlx4/main.c
+++ b/drivers/net/mlx4/main.c
@@ -829,7 +829,7 @@ static int mlx4_setup_hca(struct mlx4_dev *dev)
goto err_uar_table_free;
}
- priv->kar = ioremap(priv->driver_uar.pfn << PAGE_SHIFT, PAGE_SIZE);
+ priv->kar = ioremap((phys_addr_t) priv->driver_uar.pfn << PAGE_SHIFT, PAGE_SIZE);
if (!priv->kar) {
mlx4_err(dev, "Couldn't map kernel access region, "
"aborting.\n");
diff --git a/drivers/net/mlx4/mcg.c b/drivers/net/mlx4/mcg.c
index c4f88b7..79cf42d 100644
--- a/drivers/net/mlx4/mcg.c
+++ b/drivers/net/mlx4/mcg.c
@@ -95,7 +95,8 @@ static int mlx4_MGID_HASH(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox
* entry in hash chain and *mgm holds end of hash chain.
*/
static int find_mgm(struct mlx4_dev *dev,
- u8 *gid, struct mlx4_cmd_mailbox *mgm_mailbox,
+ u8 *gid, enum mlx4_protocol protocol,
+ struct mlx4_cmd_mailbox *mgm_mailbox,
u16 *hash, int *prev, int *index)
{
struct mlx4_cmd_mailbox *mailbox;
@@ -134,7 +135,8 @@ static int find_mgm(struct mlx4_dev *dev,
return err;
}
- if (!memcmp(mgm->gid, gid, 16))
+ if (!memcmp(mgm->gid, gid, 16) &&
+ be32_to_cpu(mgm->members_count) >> 30 == protocol)
return err;
*prev = *index;
@@ -146,7 +148,7 @@ static int find_mgm(struct mlx4_dev *dev,
}
int mlx4_multicast_attach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16],
- int block_mcast_loopback)
+ int block_mcast_loopback, enum mlx4_protocol protocol)
{
struct mlx4_priv *priv = mlx4_priv(dev);
struct mlx4_cmd_mailbox *mailbox;
@@ -165,7 +167,7 @@ int mlx4_multicast_attach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16],
mutex_lock(&priv->mcg_table.mutex);
- err = find_mgm(dev, gid, mailbox, &hash, &prev, &index);
+ err = find_mgm(dev, gid, protocol, mailbox, &hash, &prev, &index);
if (err)
goto out;
@@ -187,7 +189,7 @@ int mlx4_multicast_attach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16],
memcpy(mgm->gid, gid, 16);
}
- members_count = be32_to_cpu(mgm->members_count);
+ members_count = be32_to_cpu(mgm->members_count) & 0xffffff;
if (members_count == MLX4_QP_PER_MGM) {
mlx4_err(dev, "MGM at index %x is full.\n", index);
err = -ENOMEM;
@@ -207,7 +209,7 @@ int mlx4_multicast_attach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16],
else
mgm->qp[members_count++] = cpu_to_be32(qp->qpn & MGM_QPN_MASK);
- mgm->members_count = cpu_to_be32(members_count);
+ mgm->members_count = cpu_to_be32(members_count | (u32) protocol << 30);
err = mlx4_WRITE_MCG(dev, index, mailbox);
if (err)
@@ -242,7 +244,8 @@ out:
}
EXPORT_SYMBOL_GPL(mlx4_multicast_attach);
-int mlx4_multicast_detach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16])
+int mlx4_multicast_detach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16],
+ enum mlx4_protocol protocol)
{
struct mlx4_priv *priv = mlx4_priv(dev);
struct mlx4_cmd_mailbox *mailbox;
@@ -260,7 +263,7 @@ int mlx4_multicast_detach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16])
mutex_lock(&priv->mcg_table.mutex);
- err = find_mgm(dev, gid, mailbox, &hash, &prev, &index);
+ err = find_mgm(dev, gid, protocol, mailbox, &hash, &prev, &index);
if (err)
goto out;
@@ -270,7 +273,7 @@ int mlx4_multicast_detach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16])
goto out;
}
- members_count = be32_to_cpu(mgm->members_count);
+ members_count = be32_to_cpu(mgm->members_count) & 0xffffff;
for (loc = -1, i = 0; i < members_count; ++i)
if ((be32_to_cpu(mgm->qp[i]) & MGM_QPN_MASK) == qp->qpn)
loc = i;
@@ -282,7 +285,7 @@ int mlx4_multicast_detach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16])
}
- mgm->members_count = cpu_to_be32(--members_count);
+ mgm->members_count = cpu_to_be32(--members_count | (u32) protocol << 30);
mgm->qp[loc] = mgm->qp[i - 1];
mgm->qp[i - 1] = 0;
diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c
index a37fcf1..ea5cfe2 100644
--- a/drivers/net/myri10ge/myri10ge.c
+++ b/drivers/net/myri10ge/myri10ge.c
@@ -3403,9 +3403,7 @@ static int myri10ge_resume(struct pci_dev *pdev)
return -EIO;
}
- status = pci_restore_state(pdev);
- if (status)
- return status;
+ pci_restore_state(pdev);
status = pci_enable_device(pdev);
if (status) {
diff --git a/drivers/net/ns83820.c b/drivers/net/ns83820.c
index 84134c7..a41b2cf 100644
--- a/drivers/net/ns83820.c
+++ b/drivers/net/ns83820.c
@@ -1988,12 +1988,11 @@ static int __devinit ns83820_init_one(struct pci_dev *pci_dev,
}
ndev = alloc_etherdev(sizeof(struct ns83820));
- dev = PRIV(ndev);
-
err = -ENOMEM;
- if (!dev)
+ if (!ndev)
goto out;
+ dev = PRIV(ndev);
dev->ndev = ndev;
spin_lock_init(&dev->rx_info.lock);
diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c
index bb8645a..bde7d61 100644
--- a/drivers/net/r8169.c
+++ b/drivers/net/r8169.c
@@ -554,6 +554,8 @@ struct rtl8169_private {
struct mii_if_info mii;
struct rtl8169_counters counters;
u32 saved_wolopts;
+
+ const struct firmware *fw;
};
MODULE_AUTHOR("Realtek and the Linux r8169 crew <netdev@vger.kernel.org>");
@@ -1766,6 +1768,29 @@ rtl_phy_write_fw(struct rtl8169_private *tp, const struct firmware *fw)
}
}
+static void rtl_release_firmware(struct rtl8169_private *tp)
+{
+ release_firmware(tp->fw);
+ tp->fw = NULL;
+}
+
+static int rtl_apply_firmware(struct rtl8169_private *tp, const char *fw_name)
+{
+ const struct firmware **fw = &tp->fw;
+ int rc = !*fw;
+
+ if (rc) {
+ rc = request_firmware(fw, fw_name, &tp->pci_dev->dev);
+ if (rc < 0)
+ goto out;
+ }
+
+ /* TODO: release firmware once rtl_phy_write_fw signals failures. */
+ rtl_phy_write_fw(tp, *fw);
+out:
+ return rc;
+}
+
static void rtl8169s_hw_phy_config(struct rtl8169_private *tp)
{
static const struct phy_reg phy_reg_init[] = {
@@ -2139,7 +2164,6 @@ static void rtl8168d_1_hw_phy_config(struct rtl8169_private *tp)
{ 0x0d, 0xf880 }
};
void __iomem *ioaddr = tp->mmio_addr;
- const struct firmware *fw;
rtl_writephy_batch(tp, phy_reg_init_0, ARRAY_SIZE(phy_reg_init_0));
@@ -2203,11 +2227,8 @@ static void rtl8168d_1_hw_phy_config(struct rtl8169_private *tp)
rtl_writephy(tp, 0x1f, 0x0005);
rtl_writephy(tp, 0x05, 0x001b);
- if (rtl_readphy(tp, 0x06) == 0xbf00 &&
- request_firmware(&fw, FIRMWARE_8168D_1, &tp->pci_dev->dev) == 0) {
- rtl_phy_write_fw(tp, fw);
- release_firmware(fw);
- } else {
+ if ((rtl_readphy(tp, 0x06) != 0xbf00) ||
+ (rtl_apply_firmware(tp, FIRMWARE_8168D_1) < 0)) {
netif_warn(tp, probe, tp->dev, "unable to apply firmware patch\n");
}
@@ -2257,7 +2278,6 @@ static void rtl8168d_2_hw_phy_config(struct rtl8169_private *tp)
{ 0x0d, 0xf880 }
};
void __iomem *ioaddr = tp->mmio_addr;
- const struct firmware *fw;
rtl_writephy_batch(tp, phy_reg_init_0, ARRAY_SIZE(phy_reg_init_0));
@@ -2312,11 +2332,8 @@ static void rtl8168d_2_hw_phy_config(struct rtl8169_private *tp)
rtl_writephy(tp, 0x1f, 0x0005);
rtl_writephy(tp, 0x05, 0x001b);
- if (rtl_readphy(tp, 0x06) == 0xb300 &&
- request_firmware(&fw, FIRMWARE_8168D_2, &tp->pci_dev->dev) == 0) {
- rtl_phy_write_fw(tp, fw);
- release_firmware(fw);
- } else {
+ if ((rtl_readphy(tp, 0x06) != 0xb300) ||
+ (rtl_apply_firmware(tp, FIRMWARE_8168D_2) < 0)) {
netif_warn(tp, probe, tp->dev, "unable to apply firmware patch\n");
}
@@ -3200,6 +3217,8 @@ static void __devexit rtl8169_remove_one(struct pci_dev *pdev)
cancel_delayed_work_sync(&tp->task);
+ rtl_release_firmware(tp);
+
unregister_netdev(dev);
if (pci_dev_run_wake(pdev))
diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c
index 711449c..002bac7 100644
--- a/drivers/net/sfc/efx.c
+++ b/drivers/net/sfc/efx.c
@@ -1153,6 +1153,9 @@ static int efx_wanted_channels(void)
int count;
int cpu;
+ if (rss_cpus)
+ return rss_cpus;
+
if (unlikely(!zalloc_cpumask_var(&core_mask, GFP_KERNEL))) {
printk(KERN_WARNING
"sfc: RSS disabled due to allocation failure\n");
@@ -1266,27 +1269,18 @@ static void efx_remove_interrupts(struct efx_nic *efx)
efx->legacy_irq = 0;
}
-struct efx_tx_queue *
-efx_get_tx_queue(struct efx_nic *efx, unsigned index, unsigned type)
-{
- unsigned tx_channel_offset =
- separate_tx_channels ? efx->n_channels - efx->n_tx_channels : 0;
- EFX_BUG_ON_PARANOID(index >= efx->n_tx_channels ||
- type >= EFX_TXQ_TYPES);
- return &efx->channel[tx_channel_offset + index]->tx_queue[type];
-}
-
static void efx_set_channels(struct efx_nic *efx)
{
struct efx_channel *channel;
struct efx_tx_queue *tx_queue;
- unsigned tx_channel_offset =
+
+ efx->tx_channel_offset =
separate_tx_channels ? efx->n_channels - efx->n_tx_channels : 0;
/* Channel pointers were set in efx_init_struct() but we now
* need to clear them for TX queues in any RX-only channels. */
efx_for_each_channel(channel, efx) {
- if (channel->channel - tx_channel_offset >=
+ if (channel->channel - efx->tx_channel_offset >=
efx->n_tx_channels) {
efx_for_each_channel_tx_queue(tx_queue, channel)
tx_queue->channel = NULL;
diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c
index 70e4f7d..61ddd2c 100644
--- a/drivers/net/sfc/falcon.c
+++ b/drivers/net/sfc/falcon.c
@@ -1107,22 +1107,9 @@ static int __falcon_reset_hw(struct efx_nic *efx, enum reset_type method)
/* Restore PCI configuration if needed */
if (method == RESET_TYPE_WORLD) {
- if (efx_nic_is_dual_func(efx)) {
- rc = pci_restore_state(nic_data->pci_dev2);
- if (rc) {
- netif_err(efx, drv, efx->net_dev,
- "failed to restore PCI config for "
- "the secondary function\n");
- goto fail3;
- }
- }
- rc = pci_restore_state(efx->pci_dev);
- if (rc) {
- netif_err(efx, drv, efx->net_dev,
- "failed to restore PCI config for the "
- "primary function\n");
- goto fail4;
- }
+ if (efx_nic_is_dual_func(efx))
+ pci_restore_state(nic_data->pci_dev2);
+ pci_restore_state(efx->pci_dev);
netif_dbg(efx, drv, efx->net_dev,
"successfully restored PCI config\n");
}
@@ -1133,7 +1120,7 @@ static int __falcon_reset_hw(struct efx_nic *efx, enum reset_type method)
rc = -ETIMEDOUT;
netif_err(efx, hw, efx->net_dev,
"timed out waiting for hardware reset\n");
- goto fail5;
+ goto fail3;
}
netif_dbg(efx, hw, efx->net_dev, "hardware reset complete\n");
@@ -1141,11 +1128,9 @@ static int __falcon_reset_hw(struct efx_nic *efx, enum reset_type method)
/* pci_save_state() and pci_restore_state() MUST be called in pairs */
fail2:
-fail3:
pci_restore_state(efx->pci_dev);
fail1:
-fail4:
-fail5:
+fail3:
return rc;
}
diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h
index bdce66d..28df866 100644
--- a/drivers/net/sfc/net_driver.h
+++ b/drivers/net/sfc/net_driver.h
@@ -735,6 +735,7 @@ struct efx_nic {
unsigned next_buffer_table;
unsigned n_channels;
unsigned n_rx_channels;
+ unsigned tx_channel_offset;
unsigned n_tx_channels;
unsigned int rx_buffer_len;
unsigned int rx_buffer_order;
@@ -929,8 +930,13 @@ efx_get_channel(struct efx_nic *efx, unsigned index)
_channel = (_channel->channel + 1 < (_efx)->n_channels) ? \
(_efx)->channel[_channel->channel + 1] : NULL)
-extern struct efx_tx_queue *
-efx_get_tx_queue(struct efx_nic *efx, unsigned index, unsigned type);
+static inline struct efx_tx_queue *
+efx_get_tx_queue(struct efx_nic *efx, unsigned index, unsigned type)
+{
+ EFX_BUG_ON_PARANOID(index >= efx->n_tx_channels ||
+ type >= EFX_TXQ_TYPES);
+ return &efx->channel[efx->tx_channel_offset + index]->tx_queue[type];
+}
static inline struct efx_tx_queue *
efx_channel_get_tx_queue(struct efx_channel *channel, unsigned type)
diff --git a/drivers/net/tile/tilepro.c b/drivers/net/tile/tilepro.c
index 0e6bac5..7cb301d 100644
--- a/drivers/net/tile/tilepro.c
+++ b/drivers/net/tile/tilepro.c
@@ -142,14 +142,6 @@
MODULE_AUTHOR("Tilera");
MODULE_LICENSE("GPL");
-
-#define IS_MULTICAST(mac_addr) \
- (((u8 *)(mac_addr))[0] & 0x01)
-
-#define IS_BROADCAST(mac_addr) \
- (((u16 *)(mac_addr))[0] == 0xffff)
-
-
/*
* Queue of incoming packets for a specific cpu and device.
*
@@ -795,7 +787,7 @@ static bool tile_net_poll_aux(struct tile_net_cpu *info, int index)
/*
* FIXME: Implement HW multicast filter.
*/
- if (!IS_MULTICAST(buf) && !IS_BROADCAST(buf)) {
+ if (is_unicast_ether_addr(buf)) {
/* Filter packets not for our address. */
const u8 *mine = dev->dev_addr;
filter = compare_ether_addr(mine, buf);
diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c
index 73a3e0d..715e7b4 100644
--- a/drivers/net/ucc_geth.c
+++ b/drivers/net/ucc_geth.c
@@ -2032,7 +2032,7 @@ static void ucc_geth_set_multi(struct net_device *dev)
netdev_for_each_mc_addr(ha, dev) {
/* Only support group multicast for now.
*/
- if (!(ha->addr[0] & 1))
+ if (!is_multicast_ether_addr(ha->addr))
continue;
/* Ask CPM to run CRC and set bit in
diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c
index 593c104..04e8ce1 100644
--- a/drivers/net/usb/cdc_ncm.c
+++ b/drivers/net/usb/cdc_ncm.c
@@ -54,7 +54,7 @@
#include <linux/usb/usbnet.h>
#include <linux/usb/cdc.h>
-#define DRIVER_VERSION "30-Nov-2010"
+#define DRIVER_VERSION "17-Jan-2011"
/* CDC NCM subclass 3.2.1 */
#define USB_CDC_NCM_NDP16_LENGTH_MIN 0x10
@@ -868,15 +868,19 @@ static void cdc_ncm_tx_timeout(unsigned long arg)
if (ctx->tx_timer_pending != 0) {
ctx->tx_timer_pending--;
restart = 1;
- } else
+ } else {
restart = 0;
+ }
spin_unlock(&ctx->mtx);
- if (restart)
+ if (restart) {
+ spin_lock(&ctx->mtx);
cdc_ncm_tx_timeout_start(ctx);
- else if (ctx->netdev != NULL)
+ spin_unlock(&ctx->mtx);
+ } else if (ctx->netdev != NULL) {
usbnet_start_xmit(NULL, ctx->netdev);
+ }
}
static struct sk_buff *
@@ -900,7 +904,6 @@ cdc_ncm_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags)
skb_out = cdc_ncm_fill_tx_frame(ctx, skb);
if (ctx->tx_curr_skb != NULL)
need_timer = 1;
- spin_unlock(&ctx->mtx);
/* Start timer, if there is a remaining skb */
if (need_timer)
@@ -908,6 +911,8 @@ cdc_ncm_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags)
if (skb_out)
dev->net->stats.tx_packets += ctx->tx_curr_frame_num;
+
+ spin_unlock(&ctx->mtx);
return skb_out;
error:
@@ -1020,14 +1025,16 @@ static int cdc_ncm_rx_fixup(struct usbnet *dev, struct sk_buff *skb_in)
if (((offset + temp) > actlen) ||
(temp > CDC_NCM_MAX_DATAGRAM_SIZE) || (temp < ETH_HLEN)) {
pr_debug("invalid frame detected (ignored)"
- "offset[%u]=%u, length=%u, skb=%p\n",
- x, offset, temp, skb);
+ "offset[%u]=%u, length=%u, skb=%p\n",
+ x, offset, temp, skb_in);
if (!x)
goto error;
break;
} else {
skb = skb_clone(skb_in, GFP_ATOMIC);
+ if (!skb)
+ goto error;
skb->len = temp;
skb->data = ((u8 *)skb_in->data) + offset;
skb_set_tail_pointer(skb, temp);
diff --git a/drivers/net/vmxnet3/vmxnet3_drv.c b/drivers/net/vmxnet3/vmxnet3_drv.c
index d143e8b..cc14b4a 100644
--- a/drivers/net/vmxnet3/vmxnet3_drv.c
+++ b/drivers/net/vmxnet3/vmxnet3_drv.c
@@ -48,6 +48,9 @@ static atomic_t devices_found;
static int enable_mq = 1;
static int irq_share_mode;
+static void
+vmxnet3_write_mac_addr(struct vmxnet3_adapter *adapter, u8 *mac);
+
/*
* Enable/Disable the given intr
*/
@@ -139,9 +142,13 @@ vmxnet3_check_link(struct vmxnet3_adapter *adapter, bool affectTxQueue)
{
u32 ret;
int i;
+ unsigned long flags;
+ spin_lock_irqsave(&adapter->cmd_lock, flags);
VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD, VMXNET3_CMD_GET_LINK);
ret = VMXNET3_READ_BAR1_REG(adapter, VMXNET3_REG_CMD);
+ spin_unlock_irqrestore(&adapter->cmd_lock, flags);
+
adapter->link_speed = ret >> 16;
if (ret & 1) { /* Link is up. */
printk(KERN_INFO "%s: NIC Link is Up %d Mbps\n",
@@ -183,8 +190,10 @@ vmxnet3_process_events(struct vmxnet3_adapter *adapter)
/* Check if there is an error on xmit/recv queues */
if (events & (VMXNET3_ECR_TQERR | VMXNET3_ECR_RQERR)) {
+ spin_lock(&adapter->cmd_lock);
VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD,
VMXNET3_CMD_GET_QUEUE_STATUS);
+ spin_unlock(&adapter->cmd_lock);
for (i = 0; i < adapter->num_tx_queues; i++)
if (adapter->tqd_start[i].status.stopped)
@@ -804,30 +813,25 @@ vmxnet3_parse_and_copy_hdr(struct sk_buff *skb, struct vmxnet3_tx_queue *tq,
skb_transport_header(skb))->doff * 4;
ctx->copy_size = ctx->eth_ip_hdr_size + ctx->l4_hdr_size;
} else {
- unsigned int pull_size;
-
if (skb->ip_summed == CHECKSUM_PARTIAL) {
ctx->eth_ip_hdr_size = skb_checksum_start_offset(skb);
if (ctx->ipv4) {
struct iphdr *iph = (struct iphdr *)
skb_network_header(skb);
- if (iph->protocol == IPPROTO_TCP) {
- pull_size = ctx->eth_ip_hdr_size +
- sizeof(struct tcphdr);
-
- if (unlikely(!pskb_may_pull(skb,
- pull_size))) {
- goto err;
- }
+ if (iph->protocol == IPPROTO_TCP)
ctx->l4_hdr_size = ((struct tcphdr *)
skb_transport_header(skb))->doff * 4;
- } else if (iph->protocol == IPPROTO_UDP) {
+ 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 udphdr);
- } else {
+ sizeof(struct tcphdr);
+ else
ctx->l4_hdr_size = 0;
- }
} else {
/* for simplicity, don't copy L4 headers */
ctx->l4_hdr_size = 0;
@@ -1859,18 +1863,14 @@ vmxnet3_vlan_rx_register(struct net_device *netdev, struct vlan_group *grp)
struct vmxnet3_adapter *adapter = netdev_priv(netdev);
struct Vmxnet3_DriverShared *shared = adapter->shared;
u32 *vfTable = adapter->shared->devRead.rxFilterConf.vfTable;
+ unsigned long flags;
if (grp) {
/* add vlan rx stripping. */
if (adapter->netdev->features & NETIF_F_HW_VLAN_RX) {
int i;
- struct Vmxnet3_DSDevRead *devRead = &shared->devRead;
adapter->vlan_grp = grp;
- /* update FEATURES to device */
- devRead->misc.uptFeatures |= UPT1_F_RXVLAN;
- VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD,
- VMXNET3_CMD_UPDATE_FEATURE);
/*
* Clear entire vfTable; then enable untagged pkts.
* Note: setting one entry in vfTable to non-zero turns
@@ -1880,8 +1880,10 @@ vmxnet3_vlan_rx_register(struct net_device *netdev, struct vlan_group *grp)
vfTable[i] = 0;
VMXNET3_SET_VFTABLE_ENTRY(vfTable, 0);
+ spin_lock_irqsave(&adapter->cmd_lock, flags);
VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD,
VMXNET3_CMD_UPDATE_VLAN_FILTERS);
+ spin_unlock_irqrestore(&adapter->cmd_lock, flags);
} else {
printk(KERN_ERR "%s: vlan_rx_register when device has "
"no NETIF_F_HW_VLAN_RX\n", netdev->name);
@@ -1900,13 +1902,10 @@ vmxnet3_vlan_rx_register(struct net_device *netdev, struct vlan_group *grp)
*/
vfTable[i] = 0;
}
+ spin_lock_irqsave(&adapter->cmd_lock, flags);
VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD,
VMXNET3_CMD_UPDATE_VLAN_FILTERS);
-
- /* update FEATURES to device */
- devRead->misc.uptFeatures &= ~UPT1_F_RXVLAN;
- VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD,
- VMXNET3_CMD_UPDATE_FEATURE);
+ spin_unlock_irqrestore(&adapter->cmd_lock, flags);
}
}
}
@@ -1939,10 +1938,13 @@ vmxnet3_vlan_rx_add_vid(struct net_device *netdev, u16 vid)
{
struct vmxnet3_adapter *adapter = netdev_priv(netdev);
u32 *vfTable = adapter->shared->devRead.rxFilterConf.vfTable;
+ unsigned long flags;
VMXNET3_SET_VFTABLE_ENTRY(vfTable, vid);
+ spin_lock_irqsave(&adapter->cmd_lock, flags);
VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD,
VMXNET3_CMD_UPDATE_VLAN_FILTERS);
+ spin_unlock_irqrestore(&adapter->cmd_lock, flags);
}
@@ -1951,10 +1953,13 @@ vmxnet3_vlan_rx_kill_vid(struct net_device *netdev, u16 vid)
{
struct vmxnet3_adapter *adapter = netdev_priv(netdev);
u32 *vfTable = adapter->shared->devRead.rxFilterConf.vfTable;
+ unsigned long flags;
VMXNET3_CLEAR_VFTABLE_ENTRY(vfTable, vid);
+ spin_lock_irqsave(&adapter->cmd_lock, flags);
VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD,
VMXNET3_CMD_UPDATE_VLAN_FILTERS);
+ spin_unlock_irqrestore(&adapter->cmd_lock, flags);
}
@@ -1985,6 +1990,7 @@ static void
vmxnet3_set_mc(struct net_device *netdev)
{
struct vmxnet3_adapter *adapter = netdev_priv(netdev);
+ unsigned long flags;
struct Vmxnet3_RxFilterConf *rxConf =
&adapter->shared->devRead.rxFilterConf;
u8 *new_table = NULL;
@@ -2020,6 +2026,7 @@ vmxnet3_set_mc(struct net_device *netdev)
rxConf->mfTablePA = 0;
}
+ spin_lock_irqsave(&adapter->cmd_lock, flags);
if (new_mode != rxConf->rxMode) {
rxConf->rxMode = cpu_to_le32(new_mode);
VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD,
@@ -2028,6 +2035,7 @@ vmxnet3_set_mc(struct net_device *netdev)
VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD,
VMXNET3_CMD_UPDATE_MAC_FILTERS);
+ spin_unlock_irqrestore(&adapter->cmd_lock, flags);
kfree(new_table);
}
@@ -2080,10 +2088,8 @@ vmxnet3_setup_driver_shared(struct vmxnet3_adapter *adapter)
devRead->misc.uptFeatures |= UPT1_F_LRO;
devRead->misc.maxNumRxSG = cpu_to_le16(1 + MAX_SKB_FRAGS);
}
- if ((adapter->netdev->features & NETIF_F_HW_VLAN_RX) &&
- adapter->vlan_grp) {
+ if (adapter->netdev->features & NETIF_F_HW_VLAN_RX)
devRead->misc.uptFeatures |= UPT1_F_RXVLAN;
- }
devRead->misc.mtu = cpu_to_le32(adapter->netdev->mtu);
devRead->misc.queueDescPA = cpu_to_le64(adapter->queue_desc_pa);
@@ -2168,6 +2174,8 @@ vmxnet3_setup_driver_shared(struct vmxnet3_adapter *adapter)
/* rx filter settings */
devRead->rxFilterConf.rxMode = 0;
vmxnet3_restore_vlan(adapter);
+ vmxnet3_write_mac_addr(adapter, adapter->netdev->dev_addr);
+
/* the rest are already zeroed */
}
@@ -2177,6 +2185,7 @@ vmxnet3_activate_dev(struct vmxnet3_adapter *adapter)
{
int err, i;
u32 ret;
+ unsigned long flags;
dev_dbg(&adapter->netdev->dev, "%s: skb_buf_size %d, rx_buf_per_pkt %d,"
" ring sizes %u %u %u\n", adapter->netdev->name,
@@ -2206,9 +2215,11 @@ vmxnet3_activate_dev(struct vmxnet3_adapter *adapter)
adapter->shared_pa));
VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_DSAH, VMXNET3_GET_ADDR_HI(
adapter->shared_pa));
+ spin_lock_irqsave(&adapter->cmd_lock, flags);
VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD,
VMXNET3_CMD_ACTIVATE_DEV);
ret = VMXNET3_READ_BAR1_REG(adapter, VMXNET3_REG_CMD);
+ spin_unlock_irqrestore(&adapter->cmd_lock, flags);
if (ret != 0) {
printk(KERN_ERR "Failed to activate dev %s: error %u\n",
@@ -2255,7 +2266,10 @@ rq_err:
void
vmxnet3_reset_dev(struct vmxnet3_adapter *adapter)
{
+ unsigned long flags;
+ spin_lock_irqsave(&adapter->cmd_lock, flags);
VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD, VMXNET3_CMD_RESET_DEV);
+ spin_unlock_irqrestore(&adapter->cmd_lock, flags);
}
@@ -2263,12 +2277,15 @@ int
vmxnet3_quiesce_dev(struct vmxnet3_adapter *adapter)
{
int i;
+ unsigned long flags;
if (test_and_set_bit(VMXNET3_STATE_BIT_QUIESCED, &adapter->state))
return 0;
+ spin_lock_irqsave(&adapter->cmd_lock, flags);
VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD,
VMXNET3_CMD_QUIESCE_DEV);
+ spin_unlock_irqrestore(&adapter->cmd_lock, flags);
vmxnet3_disable_all_intrs(adapter);
for (i = 0; i < adapter->num_rx_queues; i++)
@@ -2426,7 +2443,7 @@ vmxnet3_adjust_rx_ring_size(struct vmxnet3_adapter *adapter)
sz = adapter->rx_buf_per_pkt * VMXNET3_RING_SIZE_ALIGN;
ring0_size = adapter->rx_queue[0].rx_ring[0].size;
ring0_size = (ring0_size + sz - 1) / sz * sz;
- ring0_size = min_t(u32, rq->rx_ring[0].size, VMXNET3_RX_RING_MAX_SIZE /
+ ring0_size = min_t(u32, ring0_size, VMXNET3_RX_RING_MAX_SIZE /
sz * sz);
ring1_size = adapter->rx_queue[0].rx_ring[1].size;
comp_size = ring0_size + ring1_size;
@@ -2695,7 +2712,7 @@ vmxnet3_acquire_msix_vectors(struct vmxnet3_adapter *adapter,
break;
} else {
/* If fails to enable required number of MSI-x vectors
- * try enabling 3 of them. One each for rx, tx and event
+ * try enabling minimum number of vectors required.
*/
vectors = vector_threshold;
printk(KERN_ERR "Failed to enable %d MSI-X for %s, try"
@@ -2718,9 +2735,11 @@ vmxnet3_alloc_intr_resources(struct vmxnet3_adapter *adapter)
u32 cfg;
/* intr settings */
+ spin_lock(&adapter->cmd_lock);
VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD,
VMXNET3_CMD_GET_CONF_INTR);
cfg = VMXNET3_READ_BAR1_REG(adapter, VMXNET3_REG_CMD);
+ spin_unlock(&adapter->cmd_lock);
adapter->intr.type = cfg & 0x3;
adapter->intr.mask_mode = (cfg >> 2) & 0x3;
@@ -2755,7 +2774,7 @@ vmxnet3_alloc_intr_resources(struct vmxnet3_adapter *adapter)
*/
if (err == VMXNET3_LINUX_MIN_MSIX_VECT) {
if (adapter->share_intr != VMXNET3_INTR_BUDDYSHARE
- || adapter->num_rx_queues != 2) {
+ || adapter->num_rx_queues != 1) {
adapter->share_intr = VMXNET3_INTR_TXSHARE;
printk(KERN_ERR "Number of rx queues : 1\n");
adapter->num_rx_queues = 1;
@@ -2905,6 +2924,7 @@ vmxnet3_probe_device(struct pci_dev *pdev,
adapter->netdev = netdev;
adapter->pdev = pdev;
+ spin_lock_init(&adapter->cmd_lock);
adapter->shared = pci_alloc_consistent(adapter->pdev,
sizeof(struct Vmxnet3_DriverShared),
&adapter->shared_pa);
@@ -3108,11 +3128,15 @@ vmxnet3_suspend(struct device *device)
u8 *arpreq;
struct in_device *in_dev;
struct in_ifaddr *ifa;
+ unsigned long flags;
int i = 0;
if (!netif_running(netdev))
return 0;
+ for (i = 0; i < adapter->num_rx_queues; i++)
+ napi_disable(&adapter->rx_queue[i].napi);
+
vmxnet3_disable_all_intrs(adapter);
vmxnet3_free_irqs(adapter);
vmxnet3_free_intr_resources(adapter);
@@ -3188,8 +3212,10 @@ skip_arp:
adapter->shared->devRead.pmConfDesc.confPA = cpu_to_le64(virt_to_phys(
pmConf));
+ spin_lock_irqsave(&adapter->cmd_lock, flags);
VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD,
VMXNET3_CMD_UPDATE_PMCFG);
+ spin_unlock_irqrestore(&adapter->cmd_lock, flags);
pci_save_state(pdev);
pci_enable_wake(pdev, pci_choose_state(pdev, PMSG_SUSPEND),
@@ -3204,7 +3230,8 @@ skip_arp:
static int
vmxnet3_resume(struct device *device)
{
- int err;
+ int err, i = 0;
+ unsigned long flags;
struct pci_dev *pdev = to_pci_dev(device);
struct net_device *netdev = pci_get_drvdata(pdev);
struct vmxnet3_adapter *adapter = netdev_priv(netdev);
@@ -3232,10 +3259,14 @@ vmxnet3_resume(struct device *device)
pci_enable_wake(pdev, PCI_D0, 0);
+ spin_lock_irqsave(&adapter->cmd_lock, flags);
VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD,
VMXNET3_CMD_UPDATE_PMCFG);
+ spin_unlock_irqrestore(&adapter->cmd_lock, flags);
vmxnet3_alloc_intr_resources(adapter);
vmxnet3_request_irqs(adapter);
+ for (i = 0; i < adapter->num_rx_queues; i++)
+ napi_enable(&adapter->rx_queue[i].napi);
vmxnet3_enable_all_intrs(adapter);
return 0;
diff --git a/drivers/net/vmxnet3/vmxnet3_ethtool.c b/drivers/net/vmxnet3/vmxnet3_ethtool.c
index 8e17fc8..81254be 100644
--- a/drivers/net/vmxnet3/vmxnet3_ethtool.c
+++ b/drivers/net/vmxnet3/vmxnet3_ethtool.c
@@ -45,6 +45,7 @@ static int
vmxnet3_set_rx_csum(struct net_device *netdev, u32 val)
{
struct vmxnet3_adapter *adapter = netdev_priv(netdev);
+ unsigned long flags;
if (adapter->rxcsum != val) {
adapter->rxcsum = val;
@@ -56,8 +57,10 @@ vmxnet3_set_rx_csum(struct net_device *netdev, u32 val)
adapter->shared->devRead.misc.uptFeatures &=
~UPT1_F_RXCSUM;
+ spin_lock_irqsave(&adapter->cmd_lock, flags);
VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD,
VMXNET3_CMD_UPDATE_FEATURE);
+ spin_unlock_irqrestore(&adapter->cmd_lock, flags);
}
}
return 0;
@@ -68,76 +71,78 @@ vmxnet3_set_rx_csum(struct net_device *netdev, u32 val)
static const struct vmxnet3_stat_desc
vmxnet3_tq_dev_stats[] = {
/* description, offset */
- { "TSO pkts tx", offsetof(struct UPT1_TxStats, TSOPktsTxOK) },
- { "TSO bytes tx", offsetof(struct UPT1_TxStats, TSOBytesTxOK) },
- { "ucast pkts tx", offsetof(struct UPT1_TxStats, ucastPktsTxOK) },
- { "ucast bytes tx", offsetof(struct UPT1_TxStats, ucastBytesTxOK) },
- { "mcast pkts tx", offsetof(struct UPT1_TxStats, mcastPktsTxOK) },
- { "mcast bytes tx", offsetof(struct UPT1_TxStats, mcastBytesTxOK) },
- { "bcast pkts tx", offsetof(struct UPT1_TxStats, bcastPktsTxOK) },
- { "bcast bytes tx", offsetof(struct UPT1_TxStats, bcastBytesTxOK) },
- { "pkts tx err", offsetof(struct UPT1_TxStats, pktsTxError) },
- { "pkts tx discard", offsetof(struct UPT1_TxStats, pktsTxDiscard) },
+ { "Tx Queue#", 0 },
+ { " TSO pkts tx", offsetof(struct UPT1_TxStats, TSOPktsTxOK) },
+ { " TSO bytes tx", offsetof(struct UPT1_TxStats, TSOBytesTxOK) },
+ { " ucast pkts tx", offsetof(struct UPT1_TxStats, ucastPktsTxOK) },
+ { " ucast bytes tx", offsetof(struct UPT1_TxStats, ucastBytesTxOK) },
+ { " mcast pkts tx", offsetof(struct UPT1_TxStats, mcastPktsTxOK) },
+ { " mcast bytes tx", offsetof(struct UPT1_TxStats, mcastBytesTxOK) },
+ { " bcast pkts tx", offsetof(struct UPT1_TxStats, bcastPktsTxOK) },
+ { " bcast bytes tx", offsetof(struct UPT1_TxStats, bcastBytesTxOK) },
+ { " pkts tx err", offsetof(struct UPT1_TxStats, pktsTxError) },
+ { " pkts tx discard", offsetof(struct UPT1_TxStats, pktsTxDiscard) },
};
/* per tq stats maintained by the driver */
static const struct vmxnet3_stat_desc
vmxnet3_tq_driver_stats[] = {
/* description, offset */
- {"drv dropped tx total", offsetof(struct vmxnet3_tq_driver_stats,
- drop_total) },
- { " too many frags", offsetof(struct vmxnet3_tq_driver_stats,
- drop_too_many_frags) },
- { " giant hdr", offsetof(struct vmxnet3_tq_driver_stats,
- drop_oversized_hdr) },
- { " hdr err", offsetof(struct vmxnet3_tq_driver_stats,
- drop_hdr_inspect_err) },
- { " tso", offsetof(struct vmxnet3_tq_driver_stats,
- drop_tso) },
- { "ring full", offsetof(struct vmxnet3_tq_driver_stats,
- tx_ring_full) },
- { "pkts linearized", offsetof(struct vmxnet3_tq_driver_stats,
- linearized) },
- { "hdr cloned", offsetof(struct vmxnet3_tq_driver_stats,
- copy_skb_header) },
- { "giant hdr", offsetof(struct vmxnet3_tq_driver_stats,
- oversized_hdr) },
+ {" drv dropped tx total", offsetof(struct vmxnet3_tq_driver_stats,
+ drop_total) },
+ { " too many frags", offsetof(struct vmxnet3_tq_driver_stats,
+ drop_too_many_frags) },
+ { " giant hdr", offsetof(struct vmxnet3_tq_driver_stats,
+ drop_oversized_hdr) },
+ { " hdr err", offsetof(struct vmxnet3_tq_driver_stats,
+ drop_hdr_inspect_err) },
+ { " tso", offsetof(struct vmxnet3_tq_driver_stats,
+ drop_tso) },
+ { " ring full", offsetof(struct vmxnet3_tq_driver_stats,
+ tx_ring_full) },
+ { " pkts linearized", offsetof(struct vmxnet3_tq_driver_stats,
+ linearized) },
+ { " hdr cloned", offsetof(struct vmxnet3_tq_driver_stats,
+ copy_skb_header) },
+ { " giant hdr", offsetof(struct vmxnet3_tq_driver_stats,
+ oversized_hdr) },
};
/* per rq stats maintained by the device */
static const struct vmxnet3_stat_desc
vmxnet3_rq_dev_stats[] = {
- { "LRO pkts rx", offsetof(struct UPT1_RxStats, LROPktsRxOK) },
- { "LRO byte rx", offsetof(struct UPT1_RxStats, LROBytesRxOK) },
- { "ucast pkts rx", offsetof(struct UPT1_RxStats, ucastPktsRxOK) },
- { "ucast bytes rx", offsetof(struct UPT1_RxStats, ucastBytesRxOK) },
- { "mcast pkts rx", offsetof(struct UPT1_RxStats, mcastPktsRxOK) },
- { "mcast bytes rx", offsetof(struct UPT1_RxStats, mcastBytesRxOK) },
- { "bcast pkts rx", offsetof(struct UPT1_RxStats, bcastPktsRxOK) },
- { "bcast bytes rx", offsetof(struct UPT1_RxStats, bcastBytesRxOK) },
- { "pkts rx out of buf", offsetof(struct UPT1_RxStats, pktsRxOutOfBuf) },
- { "pkts rx err", offsetof(struct UPT1_RxStats, pktsRxError) },
+ { "Rx Queue#", 0 },
+ { " LRO pkts rx", offsetof(struct UPT1_RxStats, LROPktsRxOK) },
+ { " LRO byte rx", offsetof(struct UPT1_RxStats, LROBytesRxOK) },
+ { " ucast pkts rx", offsetof(struct UPT1_RxStats, ucastPktsRxOK) },
+ { " ucast bytes rx", offsetof(struct UPT1_RxStats, ucastBytesRxOK) },
+ { " mcast pkts rx", offsetof(struct UPT1_RxStats, mcastPktsRxOK) },
+ { " mcast bytes rx", offsetof(struct UPT1_RxStats, mcastBytesRxOK) },
+ { " bcast pkts rx", offsetof(struct UPT1_RxStats, bcastPktsRxOK) },
+ { " bcast bytes rx", offsetof(struct UPT1_RxStats, bcastBytesRxOK) },
+ { " pkts rx OOB", offsetof(struct UPT1_RxStats, pktsRxOutOfBuf) },
+ { " pkts rx err", offsetof(struct UPT1_RxStats, pktsRxError) },
};
/* per rq stats maintained by the driver */
static const struct vmxnet3_stat_desc
vmxnet3_rq_driver_stats[] = {
/* description, offset */
- { "drv dropped rx total", offsetof(struct vmxnet3_rq_driver_stats,
- drop_total) },
- { " err", offsetof(struct vmxnet3_rq_driver_stats,
- drop_err) },
- { " fcs", offsetof(struct vmxnet3_rq_driver_stats,
- drop_fcs) },
- { "rx buf alloc fail", offsetof(struct vmxnet3_rq_driver_stats,
- rx_buf_alloc_failure) },
+ { " drv dropped rx total", offsetof(struct vmxnet3_rq_driver_stats,
+ drop_total) },
+ { " err", offsetof(struct vmxnet3_rq_driver_stats,
+ drop_err) },
+ { " fcs", offsetof(struct vmxnet3_rq_driver_stats,
+ drop_fcs) },
+ { " rx buf alloc fail", offsetof(struct vmxnet3_rq_driver_stats,
+ rx_buf_alloc_failure) },
};
/* gloabl stats maintained by the driver */
static const struct vmxnet3_stat_desc
vmxnet3_global_stats[] = {
/* description, offset */
- { "tx timeout count", offsetof(struct vmxnet3_adapter,
+ { "tx timeout count", offsetof(struct vmxnet3_adapter,
tx_timeout_count) }
};
@@ -151,12 +156,15 @@ vmxnet3_get_stats(struct net_device *netdev)
struct UPT1_TxStats *devTxStats;
struct UPT1_RxStats *devRxStats;
struct net_device_stats *net_stats = &netdev->stats;
+ unsigned long flags;
int i;
adapter = netdev_priv(netdev);
/* Collect the dev stats into the shared area */
+ spin_lock_irqsave(&adapter->cmd_lock, flags);
VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD, VMXNET3_CMD_GET_STATS);
+ spin_unlock_irqrestore(&adapter->cmd_lock, flags);
memset(net_stats, 0, sizeof(*net_stats));
for (i = 0; i < adapter->num_tx_queues; i++) {
@@ -193,12 +201,15 @@ vmxnet3_get_stats(struct net_device *netdev)
static int
vmxnet3_get_sset_count(struct net_device *netdev, int sset)
{
+ struct vmxnet3_adapter *adapter = netdev_priv(netdev);
switch (sset) {
case ETH_SS_STATS:
- return ARRAY_SIZE(vmxnet3_tq_dev_stats) +
- ARRAY_SIZE(vmxnet3_tq_driver_stats) +
- ARRAY_SIZE(vmxnet3_rq_dev_stats) +
- ARRAY_SIZE(vmxnet3_rq_driver_stats) +
+ return (ARRAY_SIZE(vmxnet3_tq_dev_stats) +
+ ARRAY_SIZE(vmxnet3_tq_driver_stats)) *
+ adapter->num_tx_queues +
+ (ARRAY_SIZE(vmxnet3_rq_dev_stats) +
+ ARRAY_SIZE(vmxnet3_rq_driver_stats)) *
+ adapter->num_rx_queues +
ARRAY_SIZE(vmxnet3_global_stats);
default:
return -EOPNOTSUPP;
@@ -206,10 +217,16 @@ vmxnet3_get_sset_count(struct net_device *netdev, int sset)
}
+/* Should be multiple of 4 */
+#define NUM_TX_REGS 8
+#define NUM_RX_REGS 12
+
static int
vmxnet3_get_regs_len(struct net_device *netdev)
{
- return 20 * sizeof(u32);
+ struct vmxnet3_adapter *adapter = netdev_priv(netdev);
+ return (adapter->num_tx_queues * NUM_TX_REGS * sizeof(u32) +
+ adapter->num_rx_queues * NUM_RX_REGS * sizeof(u32));
}
@@ -240,29 +257,37 @@ vmxnet3_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *drvinfo)
static void
vmxnet3_get_strings(struct net_device *netdev, u32 stringset, u8 *buf)
{
+ struct vmxnet3_adapter *adapter = netdev_priv(netdev);
if (stringset == ETH_SS_STATS) {
- int i;
-
- for (i = 0; i < ARRAY_SIZE(vmxnet3_tq_dev_stats); i++) {
- memcpy(buf, vmxnet3_tq_dev_stats[i].desc,
- ETH_GSTRING_LEN);
- buf += ETH_GSTRING_LEN;
- }
- for (i = 0; i < ARRAY_SIZE(vmxnet3_tq_driver_stats); i++) {
- memcpy(buf, vmxnet3_tq_driver_stats[i].desc,
- ETH_GSTRING_LEN);
- buf += ETH_GSTRING_LEN;
- }
- for (i = 0; i < ARRAY_SIZE(vmxnet3_rq_dev_stats); i++) {
- memcpy(buf, vmxnet3_rq_dev_stats[i].desc,
- ETH_GSTRING_LEN);
- buf += ETH_GSTRING_LEN;
+ int i, j;
+ for (j = 0; j < adapter->num_tx_queues; j++) {
+ for (i = 0; i < ARRAY_SIZE(vmxnet3_tq_dev_stats); i++) {
+ memcpy(buf, vmxnet3_tq_dev_stats[i].desc,
+ ETH_GSTRING_LEN);
+ buf += ETH_GSTRING_LEN;
+ }
+ for (i = 0; i < ARRAY_SIZE(vmxnet3_tq_driver_stats);
+ i++) {
+ memcpy(buf, vmxnet3_tq_driver_stats[i].desc,
+ ETH_GSTRING_LEN);
+ buf += ETH_GSTRING_LEN;
+ }
}
- for (i = 0; i < ARRAY_SIZE(vmxnet3_rq_driver_stats); i++) {
- memcpy(buf, vmxnet3_rq_driver_stats[i].desc,
- ETH_GSTRING_LEN);
- buf += ETH_GSTRING_LEN;
+
+ for (j = 0; j < adapter->num_rx_queues; j++) {
+ for (i = 0; i < ARRAY_SIZE(vmxnet3_rq_dev_stats); i++) {
+ memcpy(buf, vmxnet3_rq_dev_stats[i].desc,
+ ETH_GSTRING_LEN);
+ buf += ETH_GSTRING_LEN;
+ }
+ for (i = 0; i < ARRAY_SIZE(vmxnet3_rq_driver_stats);
+ i++) {
+ memcpy(buf, vmxnet3_rq_driver_stats[i].desc,
+ ETH_GSTRING_LEN);
+ buf += ETH_GSTRING_LEN;
+ }
}
+
for (i = 0; i < ARRAY_SIZE(vmxnet3_global_stats); i++) {
memcpy(buf, vmxnet3_global_stats[i].desc,
ETH_GSTRING_LEN);
@@ -277,6 +302,7 @@ vmxnet3_set_flags(struct net_device *netdev, u32 data)
struct vmxnet3_adapter *adapter = netdev_priv(netdev);
u8 lro_requested = (data & ETH_FLAG_LRO) == 0 ? 0 : 1;
u8 lro_present = (netdev->features & NETIF_F_LRO) == 0 ? 0 : 1;
+ unsigned long flags;
if (data & ~ETH_FLAG_LRO)
return -EOPNOTSUPP;
@@ -292,8 +318,10 @@ vmxnet3_set_flags(struct net_device *netdev, u32 data)
else
adapter->shared->devRead.misc.uptFeatures &=
~UPT1_F_LRO;
+ spin_lock_irqsave(&adapter->cmd_lock, flags);
VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD,
VMXNET3_CMD_UPDATE_FEATURE);
+ spin_unlock_irqrestore(&adapter->cmd_lock, flags);
}
return 0;
}
@@ -303,30 +331,41 @@ vmxnet3_get_ethtool_stats(struct net_device *netdev,
struct ethtool_stats *stats, u64 *buf)
{
struct vmxnet3_adapter *adapter = netdev_priv(netdev);
+ unsigned long flags;
u8 *base;
int i;
int j = 0;
+ spin_lock_irqsave(&adapter->cmd_lock, flags);
VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD, VMXNET3_CMD_GET_STATS);
+ spin_unlock_irqrestore(&adapter->cmd_lock, flags);
/* this does assume each counter is 64-bit wide */
-/* TODO change this for multiple queues */
-
- base = (u8 *)&adapter->tqd_start[j].stats;
- for (i = 0; i < ARRAY_SIZE(vmxnet3_tq_dev_stats); i++)
- *buf++ = *(u64 *)(base + vmxnet3_tq_dev_stats[i].offset);
-
- base = (u8 *)&adapter->tx_queue[j].stats;
- for (i = 0; i < ARRAY_SIZE(vmxnet3_tq_driver_stats); i++)
- *buf++ = *(u64 *)(base + vmxnet3_tq_driver_stats[i].offset);
-
- base = (u8 *)&adapter->rqd_start[j].stats;
- for (i = 0; i < ARRAY_SIZE(vmxnet3_rq_dev_stats); i++)
- *buf++ = *(u64 *)(base + vmxnet3_rq_dev_stats[i].offset);
+ for (j = 0; j < adapter->num_tx_queues; j++) {
+ base = (u8 *)&adapter->tqd_start[j].stats;
+ *buf++ = (u64)j;
+ for (i = 1; i < ARRAY_SIZE(vmxnet3_tq_dev_stats); i++)
+ *buf++ = *(u64 *)(base +
+ vmxnet3_tq_dev_stats[i].offset);
+
+ base = (u8 *)&adapter->tx_queue[j].stats;
+ for (i = 0; i < ARRAY_SIZE(vmxnet3_tq_driver_stats); i++)
+ *buf++ = *(u64 *)(base +
+ vmxnet3_tq_driver_stats[i].offset);
+ }
- base = (u8 *)&adapter->rx_queue[j].stats;
- for (i = 0; i < ARRAY_SIZE(vmxnet3_rq_driver_stats); i++)
- *buf++ = *(u64 *)(base + vmxnet3_rq_driver_stats[i].offset);
+ for (j = 0; j < adapter->num_tx_queues; j++) {
+ base = (u8 *)&adapter->rqd_start[j].stats;
+ *buf++ = (u64) j;
+ for (i = 1; i < ARRAY_SIZE(vmxnet3_rq_dev_stats); i++)
+ *buf++ = *(u64 *)(base +
+ vmxnet3_rq_dev_stats[i].offset);
+
+ base = (u8 *)&adapter->rx_queue[j].stats;
+ for (i = 0; i < ARRAY_SIZE(vmxnet3_rq_driver_stats); i++)
+ *buf++ = *(u64 *)(base +
+ vmxnet3_rq_driver_stats[i].offset);
+ }
base = (u8 *)adapter;
for (i = 0; i < ARRAY_SIZE(vmxnet3_global_stats); i++)
@@ -339,7 +378,7 @@ vmxnet3_get_regs(struct net_device *netdev, struct ethtool_regs *regs, void *p)
{
struct vmxnet3_adapter *adapter = netdev_priv(netdev);
u32 *buf = p;
- int i = 0;
+ int i = 0, j = 0;
memset(p, 0, vmxnet3_get_regs_len(netdev));
@@ -348,31 +387,35 @@ vmxnet3_get_regs(struct net_device *netdev, struct ethtool_regs *regs, void *p)
/* Update vmxnet3_get_regs_len if we want to dump more registers */
/* make each ring use multiple of 16 bytes */
-/* TODO change this for multiple queues */
- buf[0] = adapter->tx_queue[i].tx_ring.next2fill;
- buf[1] = adapter->tx_queue[i].tx_ring.next2comp;
- buf[2] = adapter->tx_queue[i].tx_ring.gen;
- buf[3] = 0;
-
- buf[4] = adapter->tx_queue[i].comp_ring.next2proc;
- buf[5] = adapter->tx_queue[i].comp_ring.gen;
- buf[6] = adapter->tx_queue[i].stopped;
- buf[7] = 0;
-
- buf[8] = adapter->rx_queue[i].rx_ring[0].next2fill;
- buf[9] = adapter->rx_queue[i].rx_ring[0].next2comp;
- buf[10] = adapter->rx_queue[i].rx_ring[0].gen;
- buf[11] = 0;
-
- buf[12] = adapter->rx_queue[i].rx_ring[1].next2fill;
- buf[13] = adapter->rx_queue[i].rx_ring[1].next2comp;
- buf[14] = adapter->rx_queue[i].rx_ring[1].gen;
- buf[15] = 0;
-
- buf[16] = adapter->rx_queue[i].comp_ring.next2proc;
- buf[17] = adapter->rx_queue[i].comp_ring.gen;
- buf[18] = 0;
- buf[19] = 0;
+ for (i = 0; i < adapter->num_tx_queues; i++) {
+ buf[j++] = adapter->tx_queue[i].tx_ring.next2fill;
+ buf[j++] = adapter->tx_queue[i].tx_ring.next2comp;
+ buf[j++] = adapter->tx_queue[i].tx_ring.gen;
+ buf[j++] = 0;
+
+ buf[j++] = adapter->tx_queue[i].comp_ring.next2proc;
+ buf[j++] = adapter->tx_queue[i].comp_ring.gen;
+ buf[j++] = adapter->tx_queue[i].stopped;
+ buf[j++] = 0;
+ }
+
+ for (i = 0; i < adapter->num_rx_queues; i++) {
+ buf[j++] = adapter->rx_queue[i].rx_ring[0].next2fill;
+ buf[j++] = adapter->rx_queue[i].rx_ring[0].next2comp;
+ buf[j++] = adapter->rx_queue[i].rx_ring[0].gen;
+ buf[j++] = 0;
+
+ buf[j++] = adapter->rx_queue[i].rx_ring[1].next2fill;
+ buf[j++] = adapter->rx_queue[i].rx_ring[1].next2comp;
+ buf[j++] = adapter->rx_queue[i].rx_ring[1].gen;
+ buf[j++] = 0;
+
+ buf[j++] = adapter->rx_queue[i].comp_ring.next2proc;
+ buf[j++] = adapter->rx_queue[i].comp_ring.gen;
+ buf[j++] = 0;
+ buf[j++] = 0;
+ }
+
}
@@ -574,6 +617,7 @@ vmxnet3_set_rss_indir(struct net_device *netdev,
const struct ethtool_rxfh_indir *p)
{
unsigned int i;
+ unsigned long flags;
struct vmxnet3_adapter *adapter = netdev_priv(netdev);
struct UPT1_RSSConf *rssConf = adapter->rss_conf;
@@ -592,8 +636,10 @@ vmxnet3_set_rss_indir(struct net_device *netdev,
for (i = 0; i < rssConf->indTableSize; i++)
rssConf->indTable[i] = p->ring_index[i];
+ spin_lock_irqsave(&adapter->cmd_lock, flags);
VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD,
VMXNET3_CMD_UPDATE_RSSIDT);
+ spin_unlock_irqrestore(&adapter->cmd_lock, flags);
return 0;
diff --git a/drivers/net/vmxnet3/vmxnet3_int.h b/drivers/net/vmxnet3/vmxnet3_int.h
index 7fadeed..fb5d245 100644
--- a/drivers/net/vmxnet3/vmxnet3_int.h
+++ b/drivers/net/vmxnet3/vmxnet3_int.h
@@ -68,10 +68,10 @@
/*
* Version numbers
*/
-#define VMXNET3_DRIVER_VERSION_STRING "1.0.16.0-k"
+#define VMXNET3_DRIVER_VERSION_STRING "1.0.25.0-k"
/* a 32-bit int, each byte encode a verion number in VMXNET3_DRIVER_VERSION */
-#define VMXNET3_DRIVER_VERSION_NUM 0x01001000
+#define VMXNET3_DRIVER_VERSION_NUM 0x01001900
#if defined(CONFIG_PCI_MSI)
/* RSS only makes sense if MSI-X is supported. */
@@ -289,7 +289,7 @@ struct vmxnet3_rx_queue {
#define VMXNET3_LINUX_MAX_MSIX_VECT (VMXNET3_DEVICE_MAX_TX_QUEUES + \
VMXNET3_DEVICE_MAX_RX_QUEUES + 1)
-#define VMXNET3_LINUX_MIN_MSIX_VECT 3 /* 1 for each : tx, rx and event */
+#define VMXNET3_LINUX_MIN_MSIX_VECT 2 /* 1 for tx-rx pair and 1 for event */
struct vmxnet3_intr {
@@ -317,6 +317,7 @@ struct vmxnet3_adapter {
struct vmxnet3_rx_queue rx_queue[VMXNET3_DEVICE_MAX_RX_QUEUES];
struct vlan_group *vlan_grp;
struct vmxnet3_intr intr;
+ spinlock_t cmd_lock;
struct Vmxnet3_DriverShared *shared;
struct Vmxnet3_PMConf *pm_conf;
struct Vmxnet3_TxQueueDesc *tqd_start; /* all tx queue desc */
diff --git a/drivers/net/vxge/vxge-main.c b/drivers/net/vxge/vxge-main.c
index 1ac9b56..c81a651 100644
--- a/drivers/net/vxge/vxge-main.c
+++ b/drivers/net/vxge/vxge-main.c
@@ -4120,6 +4120,7 @@ int vxge_fw_upgrade(struct vxgedev *vdev, char *fw_name, int override)
"hotplug event.\n");
out:
+ release_firmware(fw);
return ret;
}
diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c
index 019a74d..09ae4ef 100644
--- a/drivers/net/wireless/ath/ath5k/base.c
+++ b/drivers/net/wireless/ath/ath5k/base.c
@@ -2294,6 +2294,8 @@ ath5k_tx_complete_poll_work(struct work_struct *work)
int i;
bool needreset = false;
+ mutex_lock(&sc->lock);
+
for (i = 0; i < ARRAY_SIZE(sc->txqs); i++) {
if (sc->txqs[i].setup) {
txq = &sc->txqs[i];
@@ -2321,6 +2323,8 @@ ath5k_tx_complete_poll_work(struct work_struct *work)
ath5k_reset(sc, NULL, true);
}
+ mutex_unlock(&sc->lock);
+
ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work,
msecs_to_jiffies(ATH5K_TX_COMPLETE_POLL_INT));
}
diff --git a/drivers/net/wireless/ath/ath9k/ar9002_calib.c b/drivers/net/wireless/ath/ath9k/ar9002_calib.c
index 01880aa..5e300bd 100644
--- a/drivers/net/wireless/ath/ath9k/ar9002_calib.c
+++ b/drivers/net/wireless/ath/ath9k/ar9002_calib.c
@@ -679,10 +679,6 @@ static bool ar9002_hw_calibrate(struct ath_hw *ah,
/* Do NF cal only at longer intervals */
if (longcal || nfcal_pending) {
- /* Do periodic PAOffset Cal */
- ar9002_hw_pa_cal(ah, false);
- ar9002_hw_olc_temp_compensation(ah);
-
/*
* Get the value from the previous NF cal and update
* history buffer.
@@ -697,8 +693,12 @@ static bool ar9002_hw_calibrate(struct ath_hw *ah,
ath9k_hw_loadnf(ah, ah->curchan);
}
- if (longcal)
+ if (longcal) {
ath9k_hw_start_nfcal(ah, false);
+ /* Do periodic PAOffset Cal */
+ ar9002_hw_pa_cal(ah, false);
+ ar9002_hw_olc_temp_compensation(ah);
+ }
}
return iscaldone;
@@ -954,6 +954,9 @@ static void ar9002_hw_init_cal_settings(struct ath_hw *ah)
&adc_dc_cal_multi_sample;
}
ah->supp_cals = ADC_GAIN_CAL | ADC_DC_CAL | IQ_MISMATCH_CAL;
+
+ if (AR_SREV_9287(ah))
+ ah->supp_cals &= ~ADC_GAIN_CAL;
}
}
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h b/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h
index 81f9cf2..9ecca93 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h
+++ b/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h
@@ -1842,7 +1842,7 @@ static const u32 ar9300_2p2_soc_preamble[][2] = {
static const u32 ar9300PciePhy_pll_on_clkreq_disable_L1_2p2[][2] = {
/* Addr allmodes */
- {0x00004040, 0x08212e5e},
+ {0x00004040, 0x0821265e},
{0x00004040, 0x0008003b},
{0x00004044, 0x00000000},
};
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_hw.c b/drivers/net/wireless/ath/ath9k/ar9003_hw.c
index 6137634..06fb2c8 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_hw.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_hw.c
@@ -146,8 +146,8 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah)
/* Sleep Setting */
INIT_INI_ARRAY(&ah->iniPcieSerdesLowPower,
- ar9300PciePhy_clkreq_enable_L1_2p2,
- ARRAY_SIZE(ar9300PciePhy_clkreq_enable_L1_2p2),
+ ar9300PciePhy_pll_on_clkreq_disable_L1_2p2,
+ ARRAY_SIZE(ar9300PciePhy_pll_on_clkreq_disable_L1_2p2),
2);
/* Fast clock modal settings */
diff --git a/drivers/net/wireless/ath/ath9k/eeprom_def.c b/drivers/net/wireless/ath/ath9k/eeprom_def.c
index 088f141..749a936 100644
--- a/drivers/net/wireless/ath/ath9k/eeprom_def.c
+++ b/drivers/net/wireless/ath/ath9k/eeprom_def.c
@@ -226,6 +226,10 @@ static int ath9k_hw_def_check_eeprom(struct ath_hw *ah)
eep->baseEepHeader.pwdclkind == 0)
ah->need_an_top2_fixup = 1;
+ if ((common->bus_ops->ath_bus_type == ATH_USB) &&
+ (AR_SREV_9280(ah)))
+ eep->modalHeader[0].xpaBiasLvl = 0;
+
return 0;
}
diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h
index a099b3e..780ac5e 100644
--- a/drivers/net/wireless/ath/ath9k/htc.h
+++ b/drivers/net/wireless/ath/ath9k/htc.h
@@ -78,7 +78,7 @@ struct tx_frame_hdr {
u8 node_idx;
u8 vif_idx;
u8 tidno;
- u32 flags; /* ATH9K_HTC_TX_* */
+ __be32 flags; /* ATH9K_HTC_TX_* */
u8 key_type;
u8 keyix;
u8 reserved[26];
@@ -433,6 +433,7 @@ void ath9k_htc_txep(void *priv, struct sk_buff *skb, enum htc_endpoint_id ep_id,
void ath9k_htc_beaconep(void *drv_priv, struct sk_buff *skb,
enum htc_endpoint_id ep_id, bool txok);
+int ath9k_htc_update_cap_target(struct ath9k_htc_priv *priv);
void ath9k_htc_station_work(struct work_struct *work);
void ath9k_htc_aggr_work(struct work_struct *work);
void ath9k_ani_work(struct work_struct *work);;
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c
index 845b4c9..f4d576b 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c
@@ -301,6 +301,16 @@ static int ath9k_htc_add_monitor_interface(struct ath9k_htc_priv *priv)
priv->nstations++;
+ /*
+ * Set chainmask etc. on the target.
+ */
+ ret = ath9k_htc_update_cap_target(priv);
+ if (ret)
+ ath_dbg(common, ATH_DBG_CONFIG,
+ "Failed to update capability in target\n");
+
+ priv->ah->is_monitoring = true;
+
return 0;
err_vif:
@@ -328,6 +338,7 @@ static int ath9k_htc_remove_monitor_interface(struct ath9k_htc_priv *priv)
}
priv->nstations--;
+ priv->ah->is_monitoring = false;
return 0;
}
@@ -419,7 +430,7 @@ static int ath9k_htc_remove_station(struct ath9k_htc_priv *priv,
return 0;
}
-static int ath9k_htc_update_cap_target(struct ath9k_htc_priv *priv)
+int ath9k_htc_update_cap_target(struct ath9k_htc_priv *priv)
{
struct ath9k_htc_cap_target tcap;
int ret;
@@ -1186,6 +1197,20 @@ static int ath9k_htc_config(struct ieee80211_hw *hw, u32 changed)
}
}
+ /*
+ * Monitor interface should be added before
+ * IEEE80211_CONF_CHANGE_CHANNEL is handled.
+ */
+ if (changed & IEEE80211_CONF_CHANGE_MONITOR) {
+ if (conf->flags & IEEE80211_CONF_MONITOR) {
+ if (ath9k_htc_add_monitor_interface(priv))
+ ath_err(common, "Failed to set monitor mode\n");
+ else
+ ath_dbg(common, ATH_DBG_CONFIG,
+ "HW opmode set to Monitor mode\n");
+ }
+ }
+
if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
struct ieee80211_channel *curchan = hw->conf.channel;
int pos = curchan->hw_value;
@@ -1221,16 +1246,6 @@ static int ath9k_htc_config(struct ieee80211_hw *hw, u32 changed)
ath_update_txpow(priv);
}
- if (changed & IEEE80211_CONF_CHANGE_MONITOR) {
- if (conf->flags & IEEE80211_CONF_MONITOR) {
- if (ath9k_htc_add_monitor_interface(priv))
- ath_err(common, "Failed to set monitor mode\n");
- else
- ath_dbg(common, ATH_DBG_CONFIG,
- "HW opmode set to Monitor mode\n");
- }
- }
-
if (changed & IEEE80211_CONF_CHANGE_IDLE) {
mutex_lock(&priv->htc_pm_lock);
if (!priv->ps_idle) {
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c
index 33f3602..7a5ffca 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c
@@ -113,6 +113,7 @@ int ath9k_htc_tx_start(struct ath9k_htc_priv *priv, struct sk_buff *skb)
if (ieee80211_is_data(fc)) {
struct tx_frame_hdr tx_hdr;
+ u32 flags = 0;
u8 *qc;
memset(&tx_hdr, 0, sizeof(struct tx_frame_hdr));
@@ -136,13 +137,14 @@ int ath9k_htc_tx_start(struct ath9k_htc_priv *priv, struct sk_buff *skb)
/* Check for RTS protection */
if (priv->hw->wiphy->rts_threshold != (u32) -1)
if (skb->len > priv->hw->wiphy->rts_threshold)
- tx_hdr.flags |= ATH9K_HTC_TX_RTSCTS;
+ flags |= ATH9K_HTC_TX_RTSCTS;
/* CTS-to-self */
- if (!(tx_hdr.flags & ATH9K_HTC_TX_RTSCTS) &&
+ if (!(flags & ATH9K_HTC_TX_RTSCTS) &&
(priv->op_flags & OP_PROTECT_ENABLE))
- tx_hdr.flags |= ATH9K_HTC_TX_CTSONLY;
+ flags |= ATH9K_HTC_TX_CTSONLY;
+ tx_hdr.flags = cpu_to_be32(flags);
tx_hdr.key_type = ath9k_cmn_get_hw_crypto_keytype(skb);
if (tx_hdr.key_type == ATH9K_KEY_TYPE_CLEAR)
tx_hdr.keyix = (u8) ATH9K_TXKEYIX_INVALID;
diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c
index fde9786..1afb8bb 100644
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
@@ -436,9 +436,10 @@ static int ath9k_hw_init_macaddr(struct ath_hw *ah)
static int ath9k_hw_post_init(struct ath_hw *ah)
{
+ struct ath_common *common = ath9k_hw_common(ah);
int ecode;
- if (!AR_SREV_9271(ah)) {
+ if (common->bus_ops->ath_bus_type != ATH_USB) {
if (!ath9k_hw_chip_test(ah))
return -ENODEV;
}
@@ -1213,7 +1214,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
ah->txchainmask = common->tx_chainmask;
ah->rxchainmask = common->rx_chainmask;
- if (!ah->chip_fullsleep) {
+ if ((common->bus_ops->ath_bus_type != ATH_USB) && !ah->chip_fullsleep) {
ath9k_hw_abortpcurecv(ah);
if (!ath9k_hw_stopdmarecv(ah)) {
ath_dbg(common, ATH_DBG_XMIT,
diff --git a/drivers/net/wireless/hostap/hostap_cs.c b/drivers/net/wireless/hostap/hostap_cs.c
index bd8a413..2176ede 100644
--- a/drivers/net/wireless/hostap/hostap_cs.c
+++ b/drivers/net/wireless/hostap/hostap_cs.c
@@ -518,22 +518,21 @@ static int prism2_config(struct pcmcia_device *link)
hw_priv->link = link;
/*
- * Make sure the IRQ handler cannot proceed until at least
- * dev->base_addr is initialized.
+ * We enable IRQ here, but IRQ handler will not proceed
+ * until dev->base_addr is set below. This protect us from
+ * receive interrupts when driver is not initialized.
*/
- spin_lock_irqsave(&local->irq_init_lock, flags);
-
ret = pcmcia_request_irq(link, prism2_interrupt);
if (ret)
- goto failed_unlock;
+ goto failed;
ret = pcmcia_enable_device(link);
if (ret)
- goto failed_unlock;
+ goto failed;
+ spin_lock_irqsave(&local->irq_init_lock, flags);
dev->irq = link->irq;
dev->base_addr = link->resource[0]->start;
-
spin_unlock_irqrestore(&local->irq_init_lock, flags);
local->shutdown = 0;
@@ -546,8 +545,6 @@ static int prism2_config(struct pcmcia_device *link)
return ret;
- failed_unlock:
- spin_unlock_irqrestore(&local->irq_init_lock, flags);
failed:
kfree(hw_priv);
prism2_release((u_long)link);
diff --git a/drivers/net/wireless/ipw2x00/ipw2200.c b/drivers/net/wireless/ipw2x00/ipw2200.c
index 8d6ed5f..ae438ed 100644
--- a/drivers/net/wireless/ipw2x00/ipw2200.c
+++ b/drivers/net/wireless/ipw2x00/ipw2200.c
@@ -1973,6 +1973,13 @@ static void ipw_irq_tasklet(struct ipw_priv *priv)
inta = ipw_read32(priv, IPW_INTA_RW);
inta_mask = ipw_read32(priv, IPW_INTA_MASK_R);
+
+ if (inta == 0xFFFFFFFF) {
+ /* Hardware disappeared */
+ IPW_WARNING("TASKLET INTA == 0xFFFFFFFF\n");
+ /* Only handle the cached INTA values */
+ inta = 0;
+ }
inta &= (IPW_INTA_MASK_ALL & inta_mask);
/* Add any cached INTA values that need to be handled */
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-agn-eeprom.c
index 97906dd..14ceb4d 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-eeprom.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-eeprom.c
@@ -168,7 +168,7 @@ int iwl_eeprom_check_sku(struct iwl_priv *priv)
/* not using .cfg overwrite */
radio_cfg = iwl_eeprom_query16(priv, EEPROM_RADIO_CONFIG);
priv->cfg->valid_tx_ant = EEPROM_RF_CFG_TX_ANT_MSK(radio_cfg);
- priv->cfg->valid_rx_ant = EEPROM_RF_CFG_TX_ANT_MSK(radio_cfg);
+ priv->cfg->valid_rx_ant = EEPROM_RF_CFG_RX_ANT_MSK(radio_cfg);
if (!priv->cfg->valid_tx_ant || !priv->cfg->valid_rx_ant) {
IWL_ERR(priv, "Invalid chain (0X%x, 0X%x)\n",
priv->cfg->valid_tx_ant,
diff --git a/drivers/net/wireless/iwmc3200wifi/netdev.c b/drivers/net/wireless/iwmc3200wifi/netdev.c
index 13a69eb..5091d77 100644
--- a/drivers/net/wireless/iwmc3200wifi/netdev.c
+++ b/drivers/net/wireless/iwmc3200wifi/netdev.c
@@ -126,6 +126,7 @@ void *iwm_if_alloc(int sizeof_bus, struct device *dev,
ndev = alloc_netdev_mq(0, "wlan%d", ether_setup, IWM_TX_QUEUES);
if (!ndev) {
dev_err(dev, "no memory for network device instance\n");
+ ret = -ENOMEM;
goto out_priv;
}
@@ -138,6 +139,7 @@ void *iwm_if_alloc(int sizeof_bus, struct device *dev,
GFP_KERNEL);
if (!iwm->umac_profile) {
dev_err(dev, "Couldn't alloc memory for profile\n");
+ ret = -ENOMEM;
goto out_profile;
}
diff --git a/drivers/net/wireless/p54/txrx.c b/drivers/net/wireless/p54/txrx.c
index 76b2318a..f618b96 100644
--- a/drivers/net/wireless/p54/txrx.c
+++ b/drivers/net/wireless/p54/txrx.c
@@ -618,7 +618,7 @@ static void p54_tx_80211_header(struct p54_common *priv, struct sk_buff *skb,
else
*burst_possible = false;
- if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ)
+ if (!(info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ))
*flags |= P54_HDR_FLAG_DATA_OUT_SEQNR;
if (info->flags & IEEE80211_TX_CTL_PSPOLL_RESPONSE)
diff --git a/drivers/net/wireless/rt2x00/rt2x00firmware.c b/drivers/net/wireless/rt2x00/rt2x00firmware.c
index f0e1eb7..be0ff78 100644
--- a/drivers/net/wireless/rt2x00/rt2x00firmware.c
+++ b/drivers/net/wireless/rt2x00/rt2x00firmware.c
@@ -58,6 +58,7 @@ static int rt2x00lib_request_firmware(struct rt2x00_dev *rt2x00dev)
if (!fw || !fw->size || !fw->data) {
ERROR(rt2x00dev, "Failed to read Firmware.\n");
+ release_firmware(fw);
return -ENOENT;
}
diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.c b/drivers/net/wireless/rt2x00/rt2x00pci.c
index 73631c6..ace0b66 100644
--- a/drivers/net/wireless/rt2x00/rt2x00pci.c
+++ b/drivers/net/wireless/rt2x00/rt2x00pci.c
@@ -363,12 +363,12 @@ int rt2x00pci_resume(struct pci_dev *pci_dev)
struct rt2x00_dev *rt2x00dev = hw->priv;
if (pci_set_power_state(pci_dev, PCI_D0) ||
- pci_enable_device(pci_dev) ||
- pci_restore_state(pci_dev)) {
+ pci_enable_device(pci_dev)) {
ERROR(rt2x00dev, "Failed to resume device.\n");
return -EIO;
}
+ pci_restore_state(pci_dev);
return rt2x00lib_resume(rt2x00dev);
}
EXPORT_SYMBOL_GPL(rt2x00pci_resume);
diff --git a/drivers/nfc/pn544.c b/drivers/nfc/pn544.c
index 401c44b..bae6472 100644
--- a/drivers/nfc/pn544.c
+++ b/drivers/nfc/pn544.c
@@ -69,7 +69,7 @@ struct pn544_info {
struct mutex read_mutex; /* Serialize read_irq access */
struct mutex mutex; /* Serialize info struct access */
u8 *buf;
- unsigned int buflen;
+ size_t buflen;
};
static const char reg_vdd_io[] = "Vdd_IO";
diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c
index c787c3d..af824e7 100644
--- a/drivers/of/fdt.c
+++ b/drivers/of/fdt.c
@@ -692,12 +692,6 @@ int __init early_init_dt_scan_chosen(unsigned long node, const char *uname,
return 1;
}
-static void *__init early_device_tree_alloc(u64 size, u64 align)
-{
- unsigned long mem = early_init_dt_alloc_memory_arch(size, align);
- return __va(mem);
-}
-
/**
* unflatten_device_tree - create tree of device_nodes from flat blob
*
@@ -709,7 +703,7 @@ static void *__init early_device_tree_alloc(u64 size, u64 align)
void __init unflatten_device_tree(void)
{
__unflatten_device_tree(initial_boot_params, &allnodes,
- early_device_tree_alloc);
+ early_init_dt_alloc_memory_arch);
/* Get pointer to OF "/chosen" node for use everywhere */
of_chosen = of_find_node_by_path("/chosen");
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
index 7c24dce..44b0aee 100644
--- a/drivers/pci/msi.c
+++ b/drivers/pci/msi.c
@@ -168,8 +168,9 @@ static u32 __msix_mask_irq(struct msi_desc *desc, u32 flag)
u32 mask_bits = desc->masked;
unsigned offset = desc->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE +
PCI_MSIX_ENTRY_VECTOR_CTRL;
- mask_bits &= ~1;
- mask_bits |= flag;
+ mask_bits &= ~PCI_MSIX_ENTRY_CTRL_MASKBIT;
+ if (flag)
+ mask_bits |= PCI_MSIX_ENTRY_CTRL_MASKBIT;
writel(mask_bits, desc->mask_base + offset);
return mask_bits;
diff --git a/drivers/pci/msi.h b/drivers/pci/msi.h
index feff3be..65c42f8 100644
--- a/drivers/pci/msi.h
+++ b/drivers/pci/msi.h
@@ -6,12 +6,6 @@
#ifndef MSI_H
#define MSI_H
-#define PCI_MSIX_ENTRY_SIZE 16
-#define PCI_MSIX_ENTRY_LOWER_ADDR 0
-#define PCI_MSIX_ENTRY_UPPER_ADDR 4
-#define PCI_MSIX_ENTRY_DATA 8
-#define PCI_MSIX_ENTRY_VECTOR_CTRL 12
-
#define msi_control_reg(base) (base + PCI_MSI_FLAGS)
#define msi_lower_address_reg(base) (base + PCI_MSI_ADDRESS_LO)
#define msi_upper_address_reg(base) (base + PCI_MSI_ADDRESS_HI)
diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c
index 24e19c5..6fe0772 100644
--- a/drivers/pci/pci-acpi.c
+++ b/drivers/pci/pci-acpi.c
@@ -46,9 +46,9 @@ static void pci_acpi_wake_dev(acpi_handle handle, u32 event, void *context)
struct pci_dev *pci_dev = context;
if (event == ACPI_NOTIFY_DEVICE_WAKE && pci_dev) {
+ pci_wakeup_event(pci_dev);
pci_check_pme_status(pci_dev);
pm_runtime_resume(&pci_dev->dev);
- pci_wakeup_event(pci_dev);
if (pci_dev->subordinate)
pci_pme_wakeup_bus(pci_dev->subordinate);
}
@@ -399,6 +399,7 @@ static int __init acpi_pci_init(void)
if (acpi_gbl_FADT.boot_flags & ACPI_FADT_NO_ASPM) {
printk(KERN_INFO"ACPI FADT declares the system doesn't support PCIe ASPM, so disable it\n");
+ pcie_clear_aspm();
pcie_no_aspm();
}
diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c
index 8a6f797..88246dd 100644
--- a/drivers/pci/pci-driver.c
+++ b/drivers/pci/pci-driver.c
@@ -338,7 +338,7 @@ static int pci_call_probe(struct pci_driver *drv, struct pci_dev *dev,
}
/**
- * __pci_device_probe()
+ * __pci_device_probe - check if a driver wants to claim a specific PCI device
* @drv: driver to call to check if it wants the PCI device
* @pci_dev: PCI device being probed
*
@@ -449,7 +449,8 @@ static int pci_restore_standard_config(struct pci_dev *pci_dev)
return error;
}
- return pci_restore_state(pci_dev);
+ pci_restore_state(pci_dev);
+ return 0;
}
static void pci_pm_default_resume_early(struct pci_dev *pci_dev)
diff --git a/drivers/pci/pci-stub.c b/drivers/pci/pci-stub.c
index f7b68ca..775e933 100644
--- a/drivers/pci/pci-stub.c
+++ b/drivers/pci/pci-stub.c
@@ -47,6 +47,10 @@ static int __init pci_stub_init(void)
if (rc)
return rc;
+ /* no ids passed actually */
+ if (ids[0] == '\0')
+ return 0;
+
/* add ids specified in the module parameter */
p = ids;
while ((id = strsep(&p, ","))) {
@@ -54,6 +58,9 @@ static int __init pci_stub_init(void)
subdevice = PCI_ANY_ID, class=0, class_mask=0;
int fields;
+ if (!strlen(id))
+ continue;
+
fields = sscanf(id, "%x:%x:%x:%x:%x:%x",
&vendor, &device, &subvendor, &subdevice,
&class, &class_mask);
diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c
index 63d5042..8ecaac9 100644
--- a/drivers/pci/pci-sysfs.c
+++ b/drivers/pci/pci-sysfs.c
@@ -1149,7 +1149,7 @@ int __must_check pci_create_sysfs_dev_files (struct pci_dev *pdev)
sysfs_bin_attr_init(attr);
attr->size = rom_size;
attr->attr.name = "rom";
- attr->attr.mode = S_IRUSR;
+ attr->attr.mode = S_IRUSR | S_IWUSR;
attr->read = pci_read_rom;
attr->write = pci_write_rom;
retval = sysfs_create_bin_file(&pdev->dev.kobj, attr);
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 710c8a2..b714d78 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -937,14 +937,13 @@ pci_save_state(struct pci_dev *dev)
* pci_restore_state - Restore the saved state of a PCI device
* @dev: - PCI device that we're dealing with
*/
-int
-pci_restore_state(struct pci_dev *dev)
+void pci_restore_state(struct pci_dev *dev)
{
int i;
u32 val;
if (!dev->state_saved)
- return 0;
+ return;
/* PCI Express register must be restored first */
pci_restore_pcie_state(dev);
@@ -968,8 +967,6 @@ pci_restore_state(struct pci_dev *dev)
pci_restore_iov_state(dev);
dev->state_saved = false;
-
- return 0;
}
static int do_pci_enable_device(struct pci_dev *dev, int bars)
@@ -1300,22 +1297,6 @@ bool pci_check_pme_status(struct pci_dev *dev)
return ret;
}
-/*
- * Time to wait before the system can be put into a sleep state after reporting
- * a wakeup event signaled by a PCI device.
- */
-#define PCI_WAKEUP_COOLDOWN 100
-
-/**
- * pci_wakeup_event - Report a wakeup event related to a given PCI device.
- * @dev: Device to report the wakeup event for.
- */
-void pci_wakeup_event(struct pci_dev *dev)
-{
- if (device_may_wakeup(&dev->dev))
- pm_wakeup_event(&dev->dev, PCI_WAKEUP_COOLDOWN);
-}
-
/**
* pci_pme_wakeup - Wake up a PCI device if its PME Status bit is set.
* @dev: Device to handle.
@@ -1327,8 +1308,8 @@ void pci_wakeup_event(struct pci_dev *dev)
static int pci_pme_wakeup(struct pci_dev *dev, void *ign)
{
if (pci_check_pme_status(dev)) {
- pm_request_resume(&dev->dev);
pci_wakeup_event(dev);
+ pm_request_resume(&dev->dev);
}
return 0;
}
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index 7d33f66..f69d6e0 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -74,6 +74,12 @@ extern void pci_pm_init(struct pci_dev *dev);
extern void platform_pci_wakeup_init(struct pci_dev *dev);
extern void pci_allocate_cap_save_buffers(struct pci_dev *dev);
+static inline void pci_wakeup_event(struct pci_dev *dev)
+{
+ /* Wait 100 ms before the system can be put into a sleep state. */
+ pm_wakeup_event(&dev->dev, 100);
+}
+
static inline bool pci_is_bridge(struct pci_dev *pci_dev)
{
return !!(pci_dev->subordinate);
@@ -140,14 +146,6 @@ static inline void pci_no_msi(void) { }
static inline void pci_msi_init_pci_dev(struct pci_dev *dev) { }
#endif
-#ifdef CONFIG_PCIEAER
-void pci_no_aer(void);
-bool pci_aer_available(void);
-#else
-static inline void pci_no_aer(void) { }
-static inline bool pci_aer_available(void) { return false; }
-#endif
-
static inline int pci_no_d1d2(struct pci_dev *dev)
{
unsigned int parent_dstates = 0;
diff --git a/drivers/pci/pcie/Kconfig b/drivers/pci/pcie/Kconfig
index dda7098..dc29348 100644
--- a/drivers/pci/pcie/Kconfig
+++ b/drivers/pci/pcie/Kconfig
@@ -31,7 +31,7 @@ source "drivers/pci/pcie/aer/Kconfig"
# PCI Express ASPM
#
config PCIEASPM
- bool "PCI Express ASPM control" if EMBEDDED
+ bool "PCI Express ASPM control" if EXPERT
depends on PCI && PCIEPORTBUS
default y
help
diff --git a/drivers/pci/pcie/aer/aerdrv.c b/drivers/pci/pcie/aer/aerdrv.c
index 2b2b650..58ad791 100644
--- a/drivers/pci/pcie/aer/aerdrv.c
+++ b/drivers/pci/pcie/aer/aerdrv.c
@@ -17,6 +17,7 @@
#include <linux/module.h>
#include <linux/pci.h>
+#include <linux/pci-acpi.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/errno.h>
diff --git a/drivers/pci/pcie/aer/aerdrv.h b/drivers/pci/pcie/aer/aerdrv.h
index 9656e30..80c11d1 100644
--- a/drivers/pci/pcie/aer/aerdrv.h
+++ b/drivers/pci/pcie/aer/aerdrv.h
@@ -132,7 +132,6 @@ static inline int aer_osc_setup(struct pcie_device *pciedev)
#ifdef CONFIG_ACPI_APEI
extern int pcie_aer_get_firmware_first(struct pci_dev *pci_dev);
-extern bool aer_acpi_firmware_first(void);
#else
static inline int pcie_aer_get_firmware_first(struct pci_dev *pci_dev)
{
@@ -140,8 +139,6 @@ static inline int pcie_aer_get_firmware_first(struct pci_dev *pci_dev)
return pci_dev->__aer_firmware_first;
return 0;
}
-
-static inline bool aer_acpi_firmware_first(void) { return false; }
#endif
static inline void pcie_aer_force_firmware_first(struct pci_dev *pci_dev,
diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c
index 7122281..3188cd9 100644
--- a/drivers/pci/pcie/aspm.c
+++ b/drivers/pci/pcie/aspm.c
@@ -68,7 +68,7 @@ struct pcie_link_state {
struct aspm_latency acceptable[8];
};
-static int aspm_disabled, aspm_force;
+static int aspm_disabled, aspm_force, aspm_clear_state;
static DEFINE_MUTEX(aspm_lock);
static LIST_HEAD(link_list);
@@ -139,7 +139,7 @@ static void pcie_set_clkpm(struct pcie_link_state *link, int enable)
{
/* Don't enable Clock PM if the link is not Clock PM capable */
if (!link->clkpm_capable && enable)
- return;
+ enable = 0;
/* Need nothing if the specified equals to current state */
if (link->clkpm_enabled == enable)
return;
@@ -498,6 +498,10 @@ static int pcie_aspm_sanity_check(struct pci_dev *pdev)
struct pci_dev *child;
int pos;
u32 reg32;
+
+ if (aspm_clear_state)
+ return -EINVAL;
+
/*
* Some functions in a slot might not all be PCIe functions,
* very strange. Disable ASPM for the whole slot
@@ -563,12 +567,15 @@ void pcie_aspm_init_link_state(struct pci_dev *pdev)
struct pcie_link_state *link;
int blacklist = !!pcie_aspm_sanity_check(pdev);
- if (aspm_disabled || !pci_is_pcie(pdev) || pdev->link_state)
+ if (!pci_is_pcie(pdev) || pdev->link_state)
return;
if (pdev->pcie_type != PCI_EXP_TYPE_ROOT_PORT &&
pdev->pcie_type != PCI_EXP_TYPE_DOWNSTREAM)
return;
+ if (aspm_disabled && !aspm_clear_state)
+ return;
+
/* VIA has a strange chipset, root port is under a bridge */
if (pdev->pcie_type == PCI_EXP_TYPE_ROOT_PORT &&
pdev->bus->self)
@@ -641,7 +648,7 @@ void pcie_aspm_exit_link_state(struct pci_dev *pdev)
struct pci_dev *parent = pdev->bus->self;
struct pcie_link_state *link, *root, *parent_link;
- if (aspm_disabled || !pci_is_pcie(pdev) ||
+ if ((aspm_disabled && !aspm_clear_state) || !pci_is_pcie(pdev) ||
!parent || !parent->link_state)
return;
if ((parent->pcie_type != PCI_EXP_TYPE_ROOT_PORT) &&
@@ -899,6 +906,12 @@ static int __init pcie_aspm_disable(char *str)
__setup("pcie_aspm=", pcie_aspm_disable);
+void pcie_clear_aspm(void)
+{
+ if (!aspm_force)
+ aspm_clear_state = 1;
+}
+
void pcie_no_aspm(void)
{
if (!aspm_force)
diff --git a/drivers/pci/pcie/pme.c b/drivers/pci/pcie/pme.c
index 2f3c904..0057344 100644
--- a/drivers/pci/pcie/pme.c
+++ b/drivers/pci/pcie/pme.c
@@ -26,9 +26,6 @@
#include "../pci.h"
#include "portdrv.h"
-#define PCI_EXP_RTSTA_PME 0x10000 /* PME status */
-#define PCI_EXP_RTSTA_PENDING 0x20000 /* PME pending */
-
/*
* If this switch is set, MSI will not be used for PCIe PME signaling. This
* causes the PCIe port driver to use INTx interrupts only, but it turns out
@@ -74,22 +71,6 @@ void pcie_pme_interrupt_enable(struct pci_dev *dev, bool enable)
}
/**
- * pcie_pme_clear_status - Clear root port PME interrupt status.
- * @dev: PCIe root port or event collector.
- */
-static void pcie_pme_clear_status(struct pci_dev *dev)
-{
- int rtsta_pos;
- u32 rtsta;
-
- rtsta_pos = pci_pcie_cap(dev) + PCI_EXP_RTSTA;
-
- pci_read_config_dword(dev, rtsta_pos, &rtsta);
- rtsta |= PCI_EXP_RTSTA_PME;
- pci_write_config_dword(dev, rtsta_pos, rtsta);
-}
-
-/**
* pcie_pme_walk_bus - Scan a PCI bus for devices asserting PME#.
* @bus: PCI bus to scan.
*
@@ -103,8 +84,8 @@ static bool pcie_pme_walk_bus(struct pci_bus *bus)
list_for_each_entry(dev, &bus->devices, bus_list) {
/* Skip PCIe devices in case we started from a root port. */
if (!pci_is_pcie(dev) && pci_check_pme_status(dev)) {
- pm_request_resume(&dev->dev);
pci_wakeup_event(dev);
+ pm_request_resume(&dev->dev);
ret = true;
}
@@ -206,8 +187,8 @@ static void pcie_pme_handle_request(struct pci_dev *port, u16 req_id)
/* The device is there, but we have to check its PME status. */
found = pci_check_pme_status(dev);
if (found) {
- pm_request_resume(&dev->dev);
pci_wakeup_event(dev);
+ pm_request_resume(&dev->dev);
}
pci_dev_put(dev);
} else if (devfn) {
@@ -253,7 +234,7 @@ static void pcie_pme_work_fn(struct work_struct *work)
* Clear PME status of the port. If there are other
* pending PMEs, the status will be set again.
*/
- pcie_pme_clear_status(port);
+ pcie_clear_root_pme_status(port);
spin_unlock_irq(&data->lock);
pcie_pme_handle_request(port, rtsta & 0xffff);
@@ -378,7 +359,7 @@ static int pcie_pme_probe(struct pcie_device *srv)
port = srv->port;
pcie_pme_interrupt_enable(port, false);
- pcie_pme_clear_status(port);
+ pcie_clear_root_pme_status(port);
ret = request_irq(srv->irq, pcie_pme_irq, IRQF_SHARED, "PCIe PME", srv);
if (ret) {
@@ -402,7 +383,7 @@ static int pcie_pme_suspend(struct pcie_device *srv)
spin_lock_irq(&data->lock);
pcie_pme_interrupt_enable(port, false);
- pcie_pme_clear_status(port);
+ pcie_clear_root_pme_status(port);
data->noirq = true;
spin_unlock_irq(&data->lock);
@@ -422,7 +403,7 @@ static int pcie_pme_resume(struct pcie_device *srv)
spin_lock_irq(&data->lock);
data->noirq = false;
- pcie_pme_clear_status(port);
+ pcie_clear_root_pme_status(port);
pcie_pme_interrupt_enable(port, true);
spin_unlock_irq(&data->lock);
diff --git a/drivers/pci/pcie/portdrv.h b/drivers/pci/pcie/portdrv.h
index 7b5aba0..bd00a01 100644
--- a/drivers/pci/pcie/portdrv.h
+++ b/drivers/pci/pcie/portdrv.h
@@ -20,9 +20,6 @@
#define get_descriptor_id(type, service) (((type - 4) << 4) | service)
-extern bool pcie_ports_disabled;
-extern bool pcie_ports_auto;
-
extern struct bus_type pcie_port_bus_type;
extern int pcie_port_device_register(struct pci_dev *dev);
#ifdef CONFIG_PM
@@ -35,6 +32,8 @@ extern void pcie_port_bus_unregister(void);
struct pci_dev;
+extern void pcie_clear_root_pme_status(struct pci_dev *dev);
+
#ifdef CONFIG_PCIE_PME
extern bool pcie_pme_msi_disabled;
diff --git a/drivers/pci/pcie/portdrv_acpi.c b/drivers/pci/pcie/portdrv_acpi.c
index 5982b6a..a86b56e 100644
--- a/drivers/pci/pcie/portdrv_acpi.c
+++ b/drivers/pci/pcie/portdrv_acpi.c
@@ -33,7 +33,7 @@
*/
int pcie_port_acpi_setup(struct pci_dev *port, int *srv_mask)
{
- acpi_status status;
+ struct acpi_pci_root *root;
acpi_handle handle;
u32 flags;
@@ -44,26 +44,11 @@ int pcie_port_acpi_setup(struct pci_dev *port, int *srv_mask)
if (!handle)
return -EINVAL;
- flags = OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL
- | OSC_PCI_EXPRESS_NATIVE_HP_CONTROL
- | OSC_PCI_EXPRESS_PME_CONTROL;
-
- if (pci_aer_available()) {
- if (aer_acpi_firmware_first())
- dev_dbg(&port->dev, "PCIe errors handled by BIOS.\n");
- else
- flags |= OSC_PCI_EXPRESS_AER_CONTROL;
- }
-
- status = acpi_pci_osc_control_set(handle, &flags,
- OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL);
- if (ACPI_FAILURE(status)) {
- dev_dbg(&port->dev, "ACPI _OSC request failed (code %d)\n",
- status);
+ root = acpi_pci_find_root(handle);
+ if (!root)
return -ENODEV;
- }
- dev_info(&port->dev, "ACPI _OSC control granted for 0x%02x\n", flags);
+ flags = root->osc_control_set;
*srv_mask = PCIE_PORT_SERVICE_VC;
if (flags & OSC_PCI_EXPRESS_NATIVE_HP_CONTROL)
diff --git a/drivers/pci/pcie/portdrv_core.c b/drivers/pci/pcie/portdrv_core.c
index a9c222d..5130d0d 100644
--- a/drivers/pci/pcie/portdrv_core.c
+++ b/drivers/pci/pcie/portdrv_core.c
@@ -241,17 +241,17 @@ static int get_port_device_capability(struct pci_dev *dev)
int cap_mask;
int err;
+ if (pcie_ports_disabled)
+ return 0;
+
err = pcie_port_platform_notify(dev, &cap_mask);
- if (pcie_ports_auto) {
- if (err) {
- pcie_no_aspm();
- return 0;
- }
- } else {
+ if (!pcie_ports_auto) {
cap_mask = PCIE_PORT_SERVICE_PME | PCIE_PORT_SERVICE_HP
| PCIE_PORT_SERVICE_VC;
if (pci_aer_available())
cap_mask |= PCIE_PORT_SERVICE_AER;
+ } else if (err) {
+ return 0;
}
pos = pci_pcie_cap(dev);
@@ -349,15 +349,18 @@ int pcie_port_device_register(struct pci_dev *dev)
int status, capabilities, i, nr_service;
int irqs[PCIE_PORT_DEVICE_MAXSERVICES];
- /* Get and check PCI Express port services */
- capabilities = get_port_device_capability(dev);
- if (!capabilities)
- return -ENODEV;
-
/* Enable PCI Express port device */
status = pci_enable_device(dev);
if (status)
return status;
+
+ /* Get and check PCI Express port services */
+ capabilities = get_port_device_capability(dev);
+ if (!capabilities) {
+ pcie_no_aspm();
+ return 0;
+ }
+
pci_set_master(dev);
/*
* Initialize service irqs. Don't use service devices that
diff --git a/drivers/pci/pcie/portdrv_pci.c b/drivers/pci/pcie/portdrv_pci.c
index f9033e1..e0610bd 100644
--- a/drivers/pci/pcie/portdrv_pci.c
+++ b/drivers/pci/pcie/portdrv_pci.c
@@ -57,6 +57,22 @@ __setup("pcie_ports=", pcie_port_setup);
/* global data */
+/**
+ * pcie_clear_root_pme_status - Clear root port PME interrupt status.
+ * @dev: PCIe root port or event collector.
+ */
+void pcie_clear_root_pme_status(struct pci_dev *dev)
+{
+ int rtsta_pos;
+ u32 rtsta;
+
+ rtsta_pos = pci_pcie_cap(dev) + PCI_EXP_RTSTA;
+
+ pci_read_config_dword(dev, rtsta_pos, &rtsta);
+ rtsta |= PCI_EXP_RTSTA_PME;
+ pci_write_config_dword(dev, rtsta_pos, rtsta);
+}
+
static int pcie_portdrv_restore_config(struct pci_dev *dev)
{
int retval;
@@ -69,6 +85,20 @@ static int pcie_portdrv_restore_config(struct pci_dev *dev)
}
#ifdef CONFIG_PM
+static int pcie_port_resume_noirq(struct device *dev)
+{
+ struct pci_dev *pdev = to_pci_dev(dev);
+
+ /*
+ * Some BIOSes forget to clear Root PME Status bits after system wakeup
+ * which breaks ACPI-based runtime wakeup on PCI Express, so clear those
+ * bits now just in case (shouldn't hurt).
+ */
+ if(pdev->pcie_type == PCI_EXP_TYPE_ROOT_PORT)
+ pcie_clear_root_pme_status(pdev);
+ return 0;
+}
+
static const struct dev_pm_ops pcie_portdrv_pm_ops = {
.suspend = pcie_port_device_suspend,
.resume = pcie_port_device_resume,
@@ -76,6 +106,7 @@ static const struct dev_pm_ops pcie_portdrv_pm_ops = {
.thaw = pcie_port_device_resume,
.poweroff = pcie_port_device_suspend,
.restore = pcie_port_device_resume,
+ .resume_noirq = pcie_port_resume_noirq,
};
#define PCIE_PORTDRV_PM_OPS (&pcie_portdrv_pm_ops)
@@ -327,10 +358,8 @@ static int __init pcie_portdrv_init(void)
{
int retval;
- if (pcie_ports_disabled) {
- pcie_no_aspm();
- return -EACCES;
- }
+ if (pcie_ports_disabled)
+ return pci_register_driver(&pcie_portdriver);
dmi_check_system(pcie_portdrv_dmi_table);
diff --git a/drivers/pcmcia/Kconfig b/drivers/pcmcia/Kconfig
index de886f3..6e318ce 100644
--- a/drivers/pcmcia/Kconfig
+++ b/drivers/pcmcia/Kconfig
@@ -69,7 +69,7 @@ comment "PC-card bridges"
config YENTA
tristate "CardBus yenta-compatible bridge support"
depends on PCI
- select CARDBUS if !EMBEDDED
+ select CARDBUS if !EXPERT
select PCCARD_NONSTATIC if PCMCIA != n
---help---
This option enables support for CardBus host bridges. Virtually
@@ -84,27 +84,27 @@ config YENTA
config YENTA_O2
default y
- bool "Special initialization for O2Micro bridges" if EMBEDDED
+ bool "Special initialization for O2Micro bridges" if EXPERT
depends on YENTA
config YENTA_RICOH
default y
- bool "Special initialization for Ricoh bridges" if EMBEDDED
+ bool "Special initialization for Ricoh bridges" if EXPERT
depends on YENTA
config YENTA_TI
default y
- bool "Special initialization for TI and EnE bridges" if EMBEDDED
+ bool "Special initialization for TI and EnE bridges" if EXPERT
depends on YENTA
config YENTA_ENE_TUNE
default y
- bool "Auto-tune EnE bridges for CB cards" if EMBEDDED
+ bool "Auto-tune EnE bridges for CB cards" if EXPERT
depends on YENTA_TI && CARDBUS
config YENTA_TOSHIBA
default y
- bool "Special initialization for Toshiba ToPIC bridges" if EMBEDDED
+ bool "Special initialization for Toshiba ToPIC bridges" if EXPERT
depends on YENTA
config PD6729
diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c
index 19e92b2..95e3b09 100644
--- a/drivers/platform/x86/fujitsu-laptop.c
+++ b/drivers/platform/x86/fujitsu-laptop.c
@@ -689,7 +689,7 @@ static int acpi_fujitsu_add(struct acpi_device *device)
if (error)
goto err_free_input_dev;
- result = acpi_bus_get_power(fujitsu->acpi_handle, &state);
+ result = acpi_bus_update_power(fujitsu->acpi_handle, &state);
if (result) {
printk(KERN_ERR "Error reading power state\n");
goto err_unregister_input_dev;
@@ -857,7 +857,7 @@ static int acpi_fujitsu_hotkey_add(struct acpi_device *device)
if (error)
goto err_free_input_dev;
- result = acpi_bus_get_power(fujitsu_hotkey->acpi_handle, &state);
+ result = acpi_bus_update_power(fujitsu_hotkey->acpi_handle, &state);
if (result) {
printk(KERN_ERR "Error reading power state\n");
goto err_unregister_input_dev;
diff --git a/drivers/platform/x86/intel_scu_ipc.c b/drivers/platform/x86/intel_scu_ipc.c
index 1752ef0..f374c59 100644
--- a/drivers/platform/x86/intel_scu_ipc.c
+++ b/drivers/platform/x86/intel_scu_ipc.c
@@ -161,7 +161,7 @@ static int pwr_reg_rdwr(u16 *addr, u8 *data, u32 count, u32 op, u32 id)
{
int i, nc, bytes, d;
u32 offset = 0;
- u32 err = 0;
+ int err;
u8 cbuf[IPC_WWBUF_SIZE] = { };
u32 *wbuf = (u32 *)&cbuf;
@@ -404,7 +404,7 @@ EXPORT_SYMBOL(intel_scu_ipc_update_register);
*/
int intel_scu_ipc_simple_command(int cmd, int sub)
{
- u32 err = 0;
+ int err;
mutex_lock(&ipclock);
if (ipcdev.pdev == NULL) {
@@ -434,8 +434,7 @@ EXPORT_SYMBOL(intel_scu_ipc_simple_command);
int intel_scu_ipc_command(int cmd, int sub, u32 *in, int inlen,
u32 *out, int outlen)
{
- u32 err = 0;
- int i = 0;
+ int i, err;
mutex_lock(&ipclock);
if (ipcdev.pdev == NULL) {
diff --git a/drivers/platform/x86/intel_scu_ipcutil.c b/drivers/platform/x86/intel_scu_ipcutil.c
index ba3231d..b93a032 100644
--- a/drivers/platform/x86/intel_scu_ipcutil.c
+++ b/drivers/platform/x86/intel_scu_ipcutil.c
@@ -128,6 +128,6 @@ static void __exit ipc_module_exit(void)
module_init(ipc_module_init);
module_exit(ipc_module_exit);
-MODULE_LICENSE("GPL V2");
+MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("Utility driver for intel scu ipc");
MODULE_AUTHOR("Sreedhara <sreedhara.ds@intel.com>");
diff --git a/drivers/pnp/Makefile b/drivers/pnp/Makefile
index 8de3775..bfba893 100644
--- a/drivers/pnp/Makefile
+++ b/drivers/pnp/Makefile
@@ -2,11 +2,13 @@
# Makefile for the Linux Plug-and-Play Support.
#
-obj-y := core.o card.o driver.o resource.o manager.o support.o interface.o quirks.o
+obj-y := pnp.o
+
+pnp-y := core.o card.o driver.o resource.o manager.o support.o interface.o quirks.o
obj-$(CONFIG_PNPACPI) += pnpacpi/
obj-$(CONFIG_PNPBIOS) += pnpbios/
obj-$(CONFIG_ISAPNP) += isapnp/
# pnp_system_init goes after pnpacpi/pnpbios init
-obj-y += system.o
+pnp-y += system.o
diff --git a/drivers/pnp/core.c b/drivers/pnp/core.c
index 0f34d96..cb6ce42 100644
--- a/drivers/pnp/core.c
+++ b/drivers/pnp/core.c
@@ -220,10 +220,5 @@ subsys_initcall(pnp_init);
int pnp_debug;
#if defined(CONFIG_PNP_DEBUG_MESSAGES)
-static int __init pnp_debug_setup(char *__unused)
-{
- pnp_debug = 1;
- return 1;
-}
-__setup("pnp.debug", pnp_debug_setup);
+module_param_named(debug, pnp_debug, int, 0644);
#endif
diff --git a/drivers/pnp/driver.c b/drivers/pnp/driver.c
index d1dbb9d..00e9403 100644
--- a/drivers/pnp/driver.c
+++ b/drivers/pnp/driver.c
@@ -189,8 +189,11 @@ static int pnp_bus_resume(struct device *dev)
if (!pnp_drv)
return 0;
- if (pnp_dev->protocol->resume)
- pnp_dev->protocol->resume(pnp_dev);
+ if (pnp_dev->protocol->resume) {
+ error = pnp_dev->protocol->resume(pnp_dev);
+ if (error)
+ return error;
+ }
if (pnp_can_write(pnp_dev)) {
error = pnp_start_dev(pnp_dev);
diff --git a/drivers/pnp/isapnp/Makefile b/drivers/pnp/isapnp/Makefile
index cac18bb..6e607aa 100644
--- a/drivers/pnp/isapnp/Makefile
+++ b/drivers/pnp/isapnp/Makefile
@@ -1,7 +1,7 @@
#
# Makefile for the kernel ISAPNP driver.
#
+obj-y += pnp.o
+pnp-y := core.o compat.o
-isapnp-proc-$(CONFIG_PROC_FS) = proc.o
-
-obj-y := core.o compat.o $(isapnp-proc-y)
+pnp-$(CONFIG_PROC_FS) += proc.o
diff --git a/drivers/pnp/pnpacpi/Makefile b/drivers/pnp/pnpacpi/Makefile
index 905326f..40c93da 100644
--- a/drivers/pnp/pnpacpi/Makefile
+++ b/drivers/pnp/pnpacpi/Makefile
@@ -1,5 +1,6 @@
#
# Makefile for the kernel PNPACPI driver.
#
+obj-y += pnp.o
-obj-y := core.o rsparser.o
+pnp-y := core.o rsparser.o
diff --git a/drivers/pnp/pnpacpi/core.c b/drivers/pnp/pnpacpi/core.c
index 57313f4..ca84d50 100644
--- a/drivers/pnp/pnpacpi/core.c
+++ b/drivers/pnp/pnpacpi/core.c
@@ -81,12 +81,19 @@ static int pnpacpi_get_resources(struct pnp_dev *dev)
static int pnpacpi_set_resources(struct pnp_dev *dev)
{
- struct acpi_device *acpi_dev = dev->data;
- acpi_handle handle = acpi_dev->handle;
+ struct acpi_device *acpi_dev;
+ acpi_handle handle;
struct acpi_buffer buffer;
int ret;
pnp_dbg(&dev->dev, "set resources\n");
+
+ handle = DEVICE_ACPI_HANDLE(&dev->dev);
+ if (!handle || ACPI_FAILURE(acpi_bus_get_device(handle, &acpi_dev))) {
+ dev_dbg(&dev->dev, "ACPI device not found in %s!\n", __func__);
+ return -ENODEV;
+ }
+
ret = pnpacpi_build_resource_template(dev, &buffer);
if (ret)
return ret;
@@ -105,12 +112,18 @@ static int pnpacpi_set_resources(struct pnp_dev *dev)
static int pnpacpi_disable_resources(struct pnp_dev *dev)
{
- struct acpi_device *acpi_dev = dev->data;
- acpi_handle handle = acpi_dev->handle;
+ struct acpi_device *acpi_dev;
+ acpi_handle handle;
int ret;
dev_dbg(&dev->dev, "disable resources\n");
+ handle = DEVICE_ACPI_HANDLE(&dev->dev);
+ if (!handle || ACPI_FAILURE(acpi_bus_get_device(handle, &acpi_dev))) {
+ dev_dbg(&dev->dev, "ACPI device not found in %s!\n", __func__);
+ return 0;
+ }
+
/* acpi_unregister_gsi(pnp_irq(dev, 0)); */
ret = 0;
if (acpi_bus_power_manageable(handle))
@@ -124,46 +137,74 @@ static int pnpacpi_disable_resources(struct pnp_dev *dev)
#ifdef CONFIG_ACPI_SLEEP
static bool pnpacpi_can_wakeup(struct pnp_dev *dev)
{
- struct acpi_device *acpi_dev = dev->data;
- acpi_handle handle = acpi_dev->handle;
+ struct acpi_device *acpi_dev;
+ acpi_handle handle;
+
+ handle = DEVICE_ACPI_HANDLE(&dev->dev);
+ if (!handle || ACPI_FAILURE(acpi_bus_get_device(handle, &acpi_dev))) {
+ dev_dbg(&dev->dev, "ACPI device not found in %s!\n", __func__);
+ return false;
+ }
return acpi_bus_can_wakeup(handle);
}
static int pnpacpi_suspend(struct pnp_dev *dev, pm_message_t state)
{
- struct acpi_device *acpi_dev = dev->data;
- acpi_handle handle = acpi_dev->handle;
- int power_state;
+ struct acpi_device *acpi_dev;
+ acpi_handle handle;
+ int error = 0;
+
+ handle = DEVICE_ACPI_HANDLE(&dev->dev);
+ if (!handle || ACPI_FAILURE(acpi_bus_get_device(handle, &acpi_dev))) {
+ dev_dbg(&dev->dev, "ACPI device not found in %s!\n", __func__);
+ return 0;
+ }
if (device_can_wakeup(&dev->dev)) {
- int rc = acpi_pm_device_sleep_wake(&dev->dev,
+ error = acpi_pm_device_sleep_wake(&dev->dev,
device_may_wakeup(&dev->dev));
+ if (error)
+ return error;
+ }
+
+ if (acpi_bus_power_manageable(handle)) {
+ int power_state = acpi_pm_device_sleep_state(&dev->dev, NULL);
+
+ if (power_state < 0)
+ power_state = (state.event == PM_EVENT_ON) ?
+ ACPI_STATE_D0 : ACPI_STATE_D3;
- if (rc)
- return rc;
+ /*
+ * acpi_bus_set_power() often fails (keyboard port can't be
+ * powered-down?), and in any case, our return value is ignored
+ * by pnp_bus_suspend(). Hence we don't revert the wakeup
+ * setting if the set_power fails.
+ */
+ error = acpi_bus_set_power(handle, power_state);
}
- power_state = acpi_pm_device_sleep_state(&dev->dev, NULL);
- if (power_state < 0)
- power_state = (state.event == PM_EVENT_ON) ?
- ACPI_STATE_D0 : ACPI_STATE_D3;
-
- /* acpi_bus_set_power() often fails (keyboard port can't be
- * powered-down?), and in any case, our return value is ignored
- * by pnp_bus_suspend(). Hence we don't revert the wakeup
- * setting if the set_power fails.
- */
- return acpi_bus_set_power(handle, power_state);
+
+ return error;
}
static int pnpacpi_resume(struct pnp_dev *dev)
{
- struct acpi_device *acpi_dev = dev->data;
- acpi_handle handle = acpi_dev->handle;
+ struct acpi_device *acpi_dev;
+ acpi_handle handle = DEVICE_ACPI_HANDLE(&dev->dev);
+ int error = 0;
+
+ if (!handle || ACPI_FAILURE(acpi_bus_get_device(handle, &acpi_dev))) {
+ dev_dbg(&dev->dev, "ACPI device not found in %s!\n", __func__);
+ return -ENODEV;
+ }
if (device_may_wakeup(&dev->dev))
acpi_pm_device_sleep_wake(&dev->dev, false);
- return acpi_bus_set_power(handle, ACPI_STATE_D0);
+
+ if (acpi_bus_power_manageable(handle))
+ error = acpi_bus_set_power(handle, ACPI_STATE_D0);
+
+ return error;
}
#endif
diff --git a/drivers/pnp/pnpbios/Makefile b/drivers/pnp/pnpbios/Makefile
index 3cd3ed7..240b0ff 100644
--- a/drivers/pnp/pnpbios/Makefile
+++ b/drivers/pnp/pnpbios/Makefile
@@ -1,7 +1,8 @@
#
# Makefile for the kernel PNPBIOS driver.
#
+obj-y := pnp.o
-pnpbios-proc-$(CONFIG_PNPBIOS_PROC_FS) = proc.o
+pnp-y := core.o bioscalls.o rsparser.o
-obj-y := core.o bioscalls.o rsparser.o $(pnpbios-proc-y)
+pnp-$(CONFIG_PNPBIOS_PROC_FS) += proc.o
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
index 60d83d9..61bf5d7 100644
--- a/drivers/power/Kconfig
+++ b/drivers/power/Kconfig
@@ -136,6 +136,16 @@ config BATTERY_MAX17040
in handheld and portable equipment. The MAX17040 is configured
to operate with a single lithium cell
+config BATTERY_MAX17042
+ tristate "Maxim MAX17042/8997/8966 Fuel Gauge"
+ depends on I2C
+ help
+ MAX17042 is fuel-gauge systems for lithium-ion (Li+) batteries
+ in handheld and portable equipment. The MAX17042 is configured
+ to operate with a single lithium cell. MAX8997 and MAX8966 are
+ multi-function devices that include fuel gauages that are compatible
+ with MAX17042.
+
config BATTERY_Z2
tristate "Z2 battery driver"
depends on I2C && MACH_ZIPIT2
@@ -185,4 +195,14 @@ config CHARGER_TWL4030
help
Say Y here to enable support for TWL4030 Battery Charge Interface.
+config CHARGER_GPIO
+ tristate "GPIO charger"
+ depends on GPIOLIB
+ help
+ Say Y to include support for chargers which report their online status
+ through a GPIO pin.
+
+ This driver can be build as a module. If so, the module will be
+ called gpio-charger.
+
endif # POWER_SUPPLY
diff --git a/drivers/power/Makefile b/drivers/power/Makefile
index c75772e..8385bfa 100644
--- a/drivers/power/Makefile
+++ b/drivers/power/Makefile
@@ -25,6 +25,7 @@ obj-$(CONFIG_BATTERY_BQ20Z75) += bq20z75.o
obj-$(CONFIG_BATTERY_BQ27x00) += bq27x00_battery.o
obj-$(CONFIG_BATTERY_DA9030) += da9030_battery.o
obj-$(CONFIG_BATTERY_MAX17040) += max17040_battery.o
+obj-$(CONFIG_BATTERY_MAX17042) += max17042_battery.o
obj-$(CONFIG_BATTERY_Z2) += z2_battery.o
obj-$(CONFIG_BATTERY_S3C_ADC) += s3c_adc_battery.o
obj-$(CONFIG_CHARGER_PCF50633) += pcf50633-charger.o
@@ -32,3 +33,4 @@ obj-$(CONFIG_BATTERY_JZ4740) += jz4740-battery.o
obj-$(CONFIG_BATTERY_INTEL_MID) += intel_mid_battery.o
obj-$(CONFIG_CHARGER_ISP1704) += isp1704_charger.o
obj-$(CONFIG_CHARGER_TWL4030) += twl4030_charger.o
+obj-$(CONFIG_CHARGER_GPIO) += gpio-charger.o
diff --git a/drivers/power/collie_battery.c b/drivers/power/collie_battery.c
index 039f41a..548d263 100644
--- a/drivers/power/collie_battery.c
+++ b/drivers/power/collie_battery.c
@@ -295,7 +295,7 @@ static struct {
static int collie_bat_suspend(struct ucb1x00_dev *dev, pm_message_t state)
{
/* flush all pending status updates */
- flush_scheduled_work();
+ flush_work_sync(&bat_work);
return 0;
}
@@ -362,7 +362,7 @@ err_psy_reg_bu:
err_psy_reg_main:
/* see comment in collie_bat_remove */
- flush_scheduled_work();
+ cancel_work_sync(&bat_work);
i--;
err_gpio:
@@ -382,12 +382,11 @@ static void __devexit collie_bat_remove(struct ucb1x00_dev *dev)
power_supply_unregister(&collie_bat_main.psy);
/*
- * now flush all pending work.
- * we won't get any more schedules, since all
- * sources (isr and external_power_changed)
- * are unregistered now.
+ * Now cancel the bat_work. We won't get any more schedules,
+ * since all sources (isr and external_power_changed) are
+ * unregistered now.
*/
- flush_scheduled_work();
+ cancel_work_sync(&bat_work);
for (i = ARRAY_SIZE(gpios) - 1; i >= 0; i--)
gpio_free(gpios[i].gpio);
diff --git a/drivers/power/ds2760_battery.c b/drivers/power/ds2760_battery.c
index e7f8978..e534290 100644
--- a/drivers/power/ds2760_battery.c
+++ b/drivers/power/ds2760_battery.c
@@ -212,7 +212,7 @@ static int ds2760_battery_read_status(struct ds2760_device_info *di)
if (di->rem_capacity > 100)
di->rem_capacity = 100;
- if (di->current_uA >= 100L)
+ if (di->current_uA < -100L)
di->life_sec = -((di->accum_current_uAh - di->empty_uAh) * 36L)
/ (di->current_uA / 100L);
else
diff --git a/drivers/power/gpio-charger.c b/drivers/power/gpio-charger.c
new file mode 100644
index 0000000..25b88ac
--- /dev/null
+++ b/drivers/power/gpio-charger.c
@@ -0,0 +1,188 @@
+/*
+ * Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de>
+ * Driver for chargers which report their online status through a GPIO pin
+ *
+ * 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.
+ *
+ * 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.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <linux/device.h>
+#include <linux/gpio.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/power_supply.h>
+#include <linux/slab.h>
+
+#include <linux/power/gpio-charger.h>
+
+struct gpio_charger {
+ const struct gpio_charger_platform_data *pdata;
+ unsigned int irq;
+
+ struct power_supply charger;
+};
+
+static irqreturn_t gpio_charger_irq(int irq, void *devid)
+{
+ struct power_supply *charger = devid;
+
+ power_supply_changed(charger);
+
+ return IRQ_HANDLED;
+}
+
+static inline struct gpio_charger *psy_to_gpio_charger(struct power_supply *psy)
+{
+ return container_of(psy, struct gpio_charger, charger);
+}
+
+static int gpio_charger_get_property(struct power_supply *psy,
+ enum power_supply_property psp, union power_supply_propval *val)
+{
+ struct gpio_charger *gpio_charger = psy_to_gpio_charger(psy);
+ const struct gpio_charger_platform_data *pdata = gpio_charger->pdata;
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_ONLINE:
+ val->intval = gpio_get_value(pdata->gpio);
+ val->intval ^= pdata->gpio_active_low;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static enum power_supply_property gpio_charger_properties[] = {
+ POWER_SUPPLY_PROP_ONLINE,
+};
+
+static int __devinit gpio_charger_probe(struct platform_device *pdev)
+{
+ const struct gpio_charger_platform_data *pdata = pdev->dev.platform_data;
+ struct gpio_charger *gpio_charger;
+ struct power_supply *charger;
+ int ret;
+ int irq;
+
+ if (!pdata) {
+ dev_err(&pdev->dev, "No platform data\n");
+ return -EINVAL;
+ }
+
+ if (!gpio_is_valid(pdata->gpio)) {
+ dev_err(&pdev->dev, "Invalid gpio pin\n");
+ return -EINVAL;
+ }
+
+ gpio_charger = kzalloc(sizeof(*gpio_charger), GFP_KERNEL);
+ if (!gpio_charger) {
+ dev_err(&pdev->dev, "Failed to alloc driver structure\n");
+ return -ENOMEM;
+ }
+
+ charger = &gpio_charger->charger;
+
+ charger->name = pdata->name ? pdata->name : "gpio-charger";
+ charger->type = pdata->type;
+ charger->properties = gpio_charger_properties;
+ charger->num_properties = ARRAY_SIZE(gpio_charger_properties);
+ charger->get_property = gpio_charger_get_property;
+ charger->supplied_to = pdata->supplied_to;
+ charger->num_supplicants = pdata->num_supplicants;
+
+ ret = gpio_request(pdata->gpio, dev_name(&pdev->dev));
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to request gpio pin: %d\n", ret);
+ goto err_free;
+ }
+ ret = gpio_direction_input(pdata->gpio);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to set gpio to input: %d\n", ret);
+ goto err_gpio_free;
+ }
+
+ gpio_charger->pdata = pdata;
+
+ ret = power_supply_register(&pdev->dev, charger);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Failed to register power supply: %d\n",
+ ret);
+ goto err_gpio_free;
+ }
+
+ irq = gpio_to_irq(pdata->gpio);
+ if (irq > 0) {
+ ret = request_any_context_irq(irq, gpio_charger_irq,
+ IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+ dev_name(&pdev->dev), charger);
+ if (ret)
+ dev_warn(&pdev->dev, "Failed to request irq: %d\n", ret);
+ else
+ gpio_charger->irq = irq;
+ }
+
+ platform_set_drvdata(pdev, gpio_charger);
+
+ return 0;
+
+err_gpio_free:
+ gpio_free(pdata->gpio);
+err_free:
+ kfree(gpio_charger);
+ return ret;
+}
+
+static int __devexit gpio_charger_remove(struct platform_device *pdev)
+{
+ struct gpio_charger *gpio_charger = platform_get_drvdata(pdev);
+
+ if (gpio_charger->irq)
+ free_irq(gpio_charger->irq, &gpio_charger->charger);
+
+ power_supply_unregister(&gpio_charger->charger);
+
+ gpio_free(gpio_charger->pdata->gpio);
+
+ platform_set_drvdata(pdev, NULL);
+ kfree(gpio_charger);
+
+ return 0;
+}
+
+static struct platform_driver gpio_charger_driver = {
+ .probe = gpio_charger_probe,
+ .remove = __devexit_p(gpio_charger_remove),
+ .driver = {
+ .name = "gpio-charger",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init gpio_charger_init(void)
+{
+ return platform_driver_register(&gpio_charger_driver);
+}
+module_init(gpio_charger_init);
+
+static void __exit gpio_charger_exit(void)
+{
+ platform_driver_unregister(&gpio_charger_driver);
+}
+module_exit(gpio_charger_exit);
+
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_DESCRIPTION("Driver for chargers which report their online status through a GPIO");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:gpio-charger");
diff --git a/drivers/power/intel_mid_battery.c b/drivers/power/intel_mid_battery.c
index 36cf402..bce3a01 100644
--- a/drivers/power/intel_mid_battery.c
+++ b/drivers/power/intel_mid_battery.c
@@ -765,7 +765,7 @@ static int __devexit platform_pmic_battery_remove(struct platform_device *pdev)
power_supply_unregister(&pbi->usb);
power_supply_unregister(&pbi->batt);
- flush_scheduled_work();
+ cancel_work_sync(&pbi->handler);
kfree(pbi);
return 0;
}
diff --git a/drivers/power/isp1704_charger.c b/drivers/power/isp1704_charger.c
index 7251218..2ad9b14 100644
--- a/drivers/power/isp1704_charger.c
+++ b/drivers/power/isp1704_charger.c
@@ -59,11 +59,61 @@ struct isp1704_charger {
struct notifier_block nb;
struct work_struct work;
- char model[7];
+ /* properties */
+ char model[8];
unsigned present:1;
+ unsigned online:1;
+ unsigned current_max;
+
+ /* temp storage variables */
+ unsigned long event;
+ unsigned max_power;
};
/*
+ * Determine is the charging port DCP (dedicated charger) or CDP (Host/HUB
+ * chargers).
+ *
+ * REVISIT: The method is defined in Battery Charging Specification and is
+ * applicable to any ULPI transceiver. Nothing isp170x specific here.
+ */
+static inline int isp1704_charger_type(struct isp1704_charger *isp)
+{
+ u8 reg;
+ u8 func_ctrl;
+ u8 otg_ctrl;
+ int type = POWER_SUPPLY_TYPE_USB_DCP;
+
+ func_ctrl = otg_io_read(isp->otg, ULPI_FUNC_CTRL);
+ otg_ctrl = otg_io_read(isp->otg, ULPI_OTG_CTRL);
+
+ /* disable pulldowns */
+ reg = ULPI_OTG_CTRL_DM_PULLDOWN | ULPI_OTG_CTRL_DP_PULLDOWN;
+ otg_io_write(isp->otg, ULPI_CLR(ULPI_OTG_CTRL), reg);
+
+ /* full speed */
+ otg_io_write(isp->otg, ULPI_CLR(ULPI_FUNC_CTRL),
+ ULPI_FUNC_CTRL_XCVRSEL_MASK);
+ otg_io_write(isp->otg, ULPI_SET(ULPI_FUNC_CTRL),
+ ULPI_FUNC_CTRL_FULL_SPEED);
+
+ /* Enable strong pull-up on DP (1.5K) and reset */
+ reg = ULPI_FUNC_CTRL_TERMSELECT | ULPI_FUNC_CTRL_RESET;
+ otg_io_write(isp->otg, ULPI_SET(ULPI_FUNC_CTRL), reg);
+ usleep_range(1000, 2000);
+
+ reg = otg_io_read(isp->otg, ULPI_DEBUG);
+ if ((reg & 3) != 3)
+ type = POWER_SUPPLY_TYPE_USB_CDP;
+
+ /* recover original state */
+ otg_io_write(isp->otg, ULPI_FUNC_CTRL, func_ctrl);
+ otg_io_write(isp->otg, ULPI_OTG_CTRL, otg_ctrl);
+
+ return type;
+}
+
+/*
* ISP1704 detects PS/2 adapters as charger. To make sure the detected charger
* is actually a dedicated charger, the following steps need to be taken.
*/
@@ -127,16 +177,19 @@ static inline int isp1704_charger_verify(struct isp1704_charger *isp)
static inline int isp1704_charger_detect(struct isp1704_charger *isp)
{
unsigned long timeout;
- u8 r;
+ u8 pwr_ctrl;
int ret = 0;
+ pwr_ctrl = otg_io_read(isp->otg, ISP1704_PWR_CTRL);
+
/* set SW control bit in PWR_CTRL register */
otg_io_write(isp->otg, ISP1704_PWR_CTRL,
ISP1704_PWR_CTRL_SWCTRL);
/* enable manual charger detection */
- r = (ISP1704_PWR_CTRL_SWCTRL | ISP1704_PWR_CTRL_DPVSRC_EN);
- otg_io_write(isp->otg, ULPI_SET(ISP1704_PWR_CTRL), r);
+ otg_io_write(isp->otg, ULPI_SET(ISP1704_PWR_CTRL),
+ ISP1704_PWR_CTRL_SWCTRL
+ | ISP1704_PWR_CTRL_DPVSRC_EN);
usleep_range(1000, 2000);
timeout = jiffies + msecs_to_jiffies(300);
@@ -147,7 +200,10 @@ static inline int isp1704_charger_detect(struct isp1704_charger *isp)
ret = isp1704_charger_verify(isp);
break;
}
- } while (!time_after(jiffies, timeout));
+ } while (!time_after(jiffies, timeout) && isp->online);
+
+ /* recover original state */
+ otg_io_write(isp->otg, ISP1704_PWR_CTRL, pwr_ctrl);
return ret;
}
@@ -155,52 +211,92 @@ static inline int isp1704_charger_detect(struct isp1704_charger *isp)
static void isp1704_charger_work(struct work_struct *data)
{
int detect;
+ unsigned long event;
+ unsigned power;
struct isp1704_charger *isp =
container_of(data, struct isp1704_charger, work);
+ static DEFINE_MUTEX(lock);
- /*
- * FIXME Only supporting dedicated chargers even though isp1704 can
- * detect HUB and HOST chargers. If the device has already been
- * enumerated, the detection will break the connection.
- */
- if (isp->otg->state != OTG_STATE_B_IDLE)
- return;
+ event = isp->event;
+ power = isp->max_power;
- /* disable data pullups */
- if (isp->otg->gadget)
- usb_gadget_disconnect(isp->otg->gadget);
+ mutex_lock(&lock);
+
+ switch (event) {
+ case USB_EVENT_VBUS:
+ isp->online = true;
+
+ /* detect charger */
+ detect = isp1704_charger_detect(isp);
+
+ if (detect) {
+ isp->present = detect;
+ isp->psy.type = isp1704_charger_type(isp);
+ }
- /* detect charger */
- detect = isp1704_charger_detect(isp);
- if (detect) {
- isp->present = detect;
- power_supply_changed(&isp->psy);
+ switch (isp->psy.type) {
+ case POWER_SUPPLY_TYPE_USB_DCP:
+ isp->current_max = 1800;
+ break;
+ case POWER_SUPPLY_TYPE_USB_CDP:
+ /*
+ * Only 500mA here or high speed chirp
+ * handshaking may break
+ */
+ isp->current_max = 500;
+ /* FALLTHROUGH */
+ case POWER_SUPPLY_TYPE_USB:
+ default:
+ /* enable data pullups */
+ if (isp->otg->gadget)
+ usb_gadget_connect(isp->otg->gadget);
+ }
+ break;
+ case USB_EVENT_NONE:
+ isp->online = false;
+ isp->current_max = 0;
+ isp->present = 0;
+ isp->current_max = 0;
+ isp->psy.type = POWER_SUPPLY_TYPE_USB;
+
+ /*
+ * Disable data pullups. We need to prevent the controller from
+ * enumerating.
+ *
+ * FIXME: This is here to allow charger detection with Host/HUB
+ * chargers. The pullups may be enabled elsewhere, so this can
+ * not be the final solution.
+ */
+ if (isp->otg->gadget)
+ usb_gadget_disconnect(isp->otg->gadget);
+ break;
+ case USB_EVENT_ENUMERATED:
+ if (isp->present)
+ isp->current_max = 1800;
+ else
+ isp->current_max = power;
+ break;
+ default:
+ goto out;
}
- /* enable data pullups */
- if (isp->otg->gadget)
- usb_gadget_connect(isp->otg->gadget);
+ power_supply_changed(&isp->psy);
+out:
+ mutex_unlock(&lock);
}
static int isp1704_notifier_call(struct notifier_block *nb,
- unsigned long event, void *unused)
+ unsigned long event, void *power)
{
struct isp1704_charger *isp =
container_of(nb, struct isp1704_charger, nb);
- switch (event) {
- case USB_EVENT_VBUS:
- schedule_work(&isp->work);
- break;
- case USB_EVENT_NONE:
- if (isp->present) {
- isp->present = 0;
- power_supply_changed(&isp->psy);
- }
- break;
- default:
- return NOTIFY_DONE;
- }
+ isp->event = event;
+
+ if (power)
+ isp->max_power = *((unsigned *)power);
+
+ schedule_work(&isp->work);
return NOTIFY_OK;
}
@@ -216,6 +312,12 @@ static int isp1704_charger_get_property(struct power_supply *psy,
case POWER_SUPPLY_PROP_PRESENT:
val->intval = isp->present;
break;
+ case POWER_SUPPLY_PROP_ONLINE:
+ val->intval = isp->online;
+ break;
+ case POWER_SUPPLY_PROP_CURRENT_MAX:
+ val->intval = isp->current_max;
+ break;
case POWER_SUPPLY_PROP_MODEL_NAME:
val->strval = isp->model;
break;
@@ -230,6 +332,8 @@ static int isp1704_charger_get_property(struct power_supply *psy,
static enum power_supply_property power_props[] = {
POWER_SUPPLY_PROP_PRESENT,
+ POWER_SUPPLY_PROP_ONLINE,
+ POWER_SUPPLY_PROP_CURRENT_MAX,
POWER_SUPPLY_PROP_MODEL_NAME,
POWER_SUPPLY_PROP_MANUFACTURER,
};
@@ -287,13 +391,13 @@ static int __devinit isp1704_charger_probe(struct platform_device *pdev)
if (!isp->otg)
goto fail0;
+ isp->dev = &pdev->dev;
+ platform_set_drvdata(pdev, isp);
+
ret = isp1704_test_ulpi(isp);
if (ret < 0)
goto fail1;
- isp->dev = &pdev->dev;
- platform_set_drvdata(pdev, isp);
-
isp->psy.name = "isp1704";
isp->psy.type = POWER_SUPPLY_TYPE_USB;
isp->psy.properties = power_props;
@@ -318,6 +422,23 @@ static int __devinit isp1704_charger_probe(struct platform_device *pdev)
dev_info(isp->dev, "registered with product id %s\n", isp->model);
+ /*
+ * Taking over the D+ pullup.
+ *
+ * FIXME: The device will be disconnected if it was already
+ * enumerated. The charger driver should be always loaded before any
+ * gadget is loaded.
+ */
+ if (isp->otg->gadget)
+ usb_gadget_disconnect(isp->otg->gadget);
+
+ /* Detect charger if VBUS is valid (the cable was already plugged). */
+ ret = otg_io_read(isp->otg, ULPI_USB_INT_STS);
+ if ((ret & ULPI_INT_VBUS_VALID) && !isp->otg->default_a) {
+ isp->event = USB_EVENT_VBUS;
+ schedule_work(&isp->work);
+ }
+
return 0;
fail2:
power_supply_unregister(&isp->psy);
diff --git a/drivers/power/jz4740-battery.c b/drivers/power/jz4740-battery.c
index a8108a7..02414db 100644
--- a/drivers/power/jz4740-battery.c
+++ b/drivers/power/jz4740-battery.c
@@ -19,6 +19,7 @@
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
+#include <linux/io.h>
#include <linux/delay.h>
#include <linux/gpio.h>
@@ -47,6 +48,8 @@ struct jz_battery {
struct power_supply battery;
struct delayed_work work;
+
+ struct mutex lock;
};
static inline struct jz_battery *psy_to_jz_battery(struct power_supply *psy)
@@ -68,6 +71,8 @@ static long jz_battery_read_voltage(struct jz_battery *battery)
unsigned long val;
long voltage;
+ mutex_lock(&battery->lock);
+
INIT_COMPLETION(battery->read_completion);
enable_irq(battery->irq);
@@ -91,6 +96,8 @@ static long jz_battery_read_voltage(struct jz_battery *battery)
battery->cell->disable(battery->pdev);
disable_irq(battery->irq);
+ mutex_unlock(&battery->lock);
+
return voltage;
}
@@ -240,6 +247,11 @@ static int __devinit jz_battery_probe(struct platform_device *pdev)
struct jz_battery *jz_battery;
struct power_supply *battery;
+ if (!pdata) {
+ dev_err(&pdev->dev, "No platform_data supplied\n");
+ return -ENXIO;
+ }
+
jz_battery = kzalloc(sizeof(*jz_battery), GFP_KERNEL);
if (!jz_battery) {
dev_err(&pdev->dev, "Failed to allocate driver structure\n");
@@ -291,6 +303,7 @@ static int __devinit jz_battery_probe(struct platform_device *pdev)
jz_battery->pdev = pdev;
init_completion(&jz_battery->read_completion);
+ mutex_init(&jz_battery->lock);
INIT_DELAYED_WORK(&jz_battery->work, jz_battery_work);
diff --git a/drivers/power/max17042_battery.c b/drivers/power/max17042_battery.c
new file mode 100644
index 0000000..c5c8805
--- /dev/null
+++ b/drivers/power/max17042_battery.c
@@ -0,0 +1,239 @@
+/*
+ * Fuel gauge driver for Maxim 17042 / 8966 / 8997
+ * Note that Maxim 8966 and 8997 are mfd and this is its subdevice.
+ *
+ * Copyright (C) 2011 Samsung Electronics
+ * MyungJoo Ham <myungjoo.ham@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.
+ *
+ * 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
+ *
+ * This driver is based on max17040_battery.c
+ */
+
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/mod_devicetable.h>
+#include <linux/power_supply.h>
+#include <linux/power/max17042_battery.h>
+
+enum max17042_register {
+ MAX17042_STATUS = 0x00,
+ MAX17042_VALRT_Th = 0x01,
+ MAX17042_TALRT_Th = 0x02,
+ MAX17042_SALRT_Th = 0x03,
+ MAX17042_AtRate = 0x04,
+ MAX17042_RepCap = 0x05,
+ MAX17042_RepSOC = 0x06,
+ MAX17042_Age = 0x07,
+ MAX17042_TEMP = 0x08,
+ MAX17042_VCELL = 0x09,
+ MAX17042_Current = 0x0A,
+ MAX17042_AvgCurrent = 0x0B,
+ MAX17042_Qresidual = 0x0C,
+ MAX17042_SOC = 0x0D,
+ MAX17042_AvSOC = 0x0E,
+ MAX17042_RemCap = 0x0F,
+ MAX17402_FullCAP = 0x10,
+ MAX17042_TTE = 0x11,
+ MAX17042_V_empty = 0x12,
+
+ MAX17042_RSLOW = 0x14,
+
+ MAX17042_AvgTA = 0x16,
+ MAX17042_Cycles = 0x17,
+ MAX17042_DesignCap = 0x18,
+ MAX17042_AvgVCELL = 0x19,
+ MAX17042_MinMaxTemp = 0x1A,
+ MAX17042_MinMaxVolt = 0x1B,
+ MAX17042_MinMaxCurr = 0x1C,
+ MAX17042_CONFIG = 0x1D,
+ MAX17042_ICHGTerm = 0x1E,
+ MAX17042_AvCap = 0x1F,
+ MAX17042_ManName = 0x20,
+ MAX17042_DevName = 0x21,
+ MAX17042_DevChem = 0x22,
+
+ MAX17042_TempNom = 0x24,
+ MAX17042_TempCold = 0x25,
+ MAX17042_TempHot = 0x26,
+ MAX17042_AIN = 0x27,
+ MAX17042_LearnCFG = 0x28,
+ MAX17042_SHFTCFG = 0x29,
+ MAX17042_RelaxCFG = 0x2A,
+ MAX17042_MiscCFG = 0x2B,
+ MAX17042_TGAIN = 0x2C,
+ MAx17042_TOFF = 0x2D,
+ MAX17042_CGAIN = 0x2E,
+ MAX17042_COFF = 0x2F,
+
+ MAX17042_Q_empty = 0x33,
+ MAX17042_T_empty = 0x34,
+
+ MAX17042_RCOMP0 = 0x38,
+ MAX17042_TempCo = 0x39,
+ MAX17042_Rx = 0x3A,
+ MAX17042_T_empty0 = 0x3B,
+ MAX17042_TaskPeriod = 0x3C,
+ MAX17042_FSTAT = 0x3D,
+
+ MAX17042_SHDNTIMER = 0x3F,
+
+ MAX17042_VFRemCap = 0x4A,
+
+ MAX17042_QH = 0x4D,
+ MAX17042_QL = 0x4E,
+};
+
+struct max17042_chip {
+ struct i2c_client *client;
+ struct power_supply battery;
+ struct max17042_platform_data *pdata;
+};
+
+static int max17042_write_reg(struct i2c_client *client, u8 reg, u16 value)
+{
+ int ret = i2c_smbus_write_word_data(client, reg, value);
+
+ if (ret < 0)
+ dev_err(&client->dev, "%s: err %d\n", __func__, ret);
+
+ return ret;
+}
+
+static int max17042_read_reg(struct i2c_client *client, u8 reg)
+{
+ int ret = i2c_smbus_read_word_data(client, reg);
+
+ if (ret < 0)
+ dev_err(&client->dev, "%s: err %d\n", __func__, ret);
+
+ return ret;
+}
+
+static enum power_supply_property max17042_battery_props[] = {
+ POWER_SUPPLY_PROP_VOLTAGE_NOW,
+ POWER_SUPPLY_PROP_VOLTAGE_AVG,
+ POWER_SUPPLY_PROP_CAPACITY,
+};
+
+static int max17042_get_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ struct max17042_chip *chip = container_of(psy,
+ struct max17042_chip, battery);
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+ val->intval = max17042_read_reg(chip->client,
+ MAX17042_VCELL) * 83; /* 1000 / 12 = 83 */
+ break;
+ case POWER_SUPPLY_PROP_VOLTAGE_AVG:
+ val->intval = max17042_read_reg(chip->client,
+ MAX17042_AvgVCELL) * 83;
+ break;
+ case POWER_SUPPLY_PROP_CAPACITY:
+ val->intval = max17042_read_reg(chip->client,
+ MAX17042_SOC) / 256;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int __devinit max17042_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
+ struct max17042_chip *chip;
+ int ret;
+
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA))
+ return -EIO;
+
+ chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+ if (!chip)
+ return -ENOMEM;
+
+ chip->client = client;
+ chip->pdata = client->dev.platform_data;
+
+ i2c_set_clientdata(client, chip);
+
+ chip->battery.name = "max17042_battery";
+ chip->battery.type = POWER_SUPPLY_TYPE_BATTERY;
+ chip->battery.get_property = max17042_get_property;
+ chip->battery.properties = max17042_battery_props;
+ chip->battery.num_properties = ARRAY_SIZE(max17042_battery_props);
+
+ ret = power_supply_register(&client->dev, &chip->battery);
+ if (ret) {
+ dev_err(&client->dev, "failed: power supply register\n");
+ i2c_set_clientdata(client, NULL);
+ kfree(chip);
+ return ret;
+ }
+
+ if (!chip->pdata->enable_current_sense) {
+ max17042_write_reg(client, MAX17042_CGAIN, 0x0000);
+ max17042_write_reg(client, MAX17042_MiscCFG, 0x0003);
+ max17042_write_reg(client, MAX17042_LearnCFG, 0x0007);
+ }
+
+ return 0;
+}
+
+static int __devexit max17042_remove(struct i2c_client *client)
+{
+ struct max17042_chip *chip = i2c_get_clientdata(client);
+
+ power_supply_unregister(&chip->battery);
+ i2c_set_clientdata(client, NULL);
+ kfree(chip);
+ return 0;
+}
+
+static const struct i2c_device_id max17042_id[] = {
+ { "max17042", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, max17042_id);
+
+static struct i2c_driver max17042_i2c_driver = {
+ .driver = {
+ .name = "max17042",
+ },
+ .probe = max17042_probe,
+ .remove = __devexit_p(max17042_remove),
+ .id_table = max17042_id,
+};
+
+static int __init max17042_init(void)
+{
+ return i2c_add_driver(&max17042_i2c_driver);
+}
+module_init(max17042_init);
+
+static void __exit max17042_exit(void)
+{
+ i2c_del_driver(&max17042_i2c_driver);
+}
+module_exit(max17042_exit);
+
+MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>");
+MODULE_DESCRIPTION("MAX17042 Fuel Gauge");
+MODULE_LICENSE("GPL");
diff --git a/drivers/power/olpc_battery.c b/drivers/power/olpc_battery.c
index 5bc1dcf..0b0ff3a 100644
--- a/drivers/power/olpc_battery.c
+++ b/drivers/power/olpc_battery.c
@@ -201,6 +201,72 @@ static int olpc_bat_get_tech(union power_supply_propval *val)
return ret;
}
+static int olpc_bat_get_charge_full_design(union power_supply_propval *val)
+{
+ uint8_t ec_byte;
+ union power_supply_propval tech;
+ int ret, mfr;
+
+ ret = olpc_bat_get_tech(&tech);
+ if (ret)
+ return ret;
+
+ ec_byte = BAT_ADDR_MFR_TYPE;
+ ret = olpc_ec_cmd(EC_BAT_EEPROM, &ec_byte, 1, &ec_byte, 1);
+ if (ret)
+ return ret;
+
+ mfr = ec_byte >> 4;
+
+ switch (tech.intval) {
+ case POWER_SUPPLY_TECHNOLOGY_NiMH:
+ switch (mfr) {
+ case 1: /* Gold Peak */
+ val->intval = 3000000*.8;
+ break;
+ default:
+ return -EIO;
+ }
+ break;
+
+ case POWER_SUPPLY_TECHNOLOGY_LiFe:
+ switch (mfr) {
+ case 1: /* Gold Peak */
+ val->intval = 2800000;
+ break;
+ case 2: /* BYD */
+ val->intval = 3100000;
+ break;
+ default:
+ return -EIO;
+ }
+ break;
+
+ default:
+ return -EIO;
+ }
+
+ return ret;
+}
+
+static int olpc_bat_get_charge_now(union power_supply_propval *val)
+{
+ uint8_t soc;
+ union power_supply_propval full;
+ int ret;
+
+ ret = olpc_ec_cmd(EC_BAT_SOC, NULL, 0, &soc, 1);
+ if (ret)
+ return ret;
+
+ ret = olpc_bat_get_charge_full_design(&full);
+ if (ret)
+ return ret;
+
+ val->intval = soc * (full.intval / 100);
+ return 0;
+}
+
/*********************************************************************
* Battery properties
*********************************************************************/
@@ -267,6 +333,7 @@ static int olpc_bat_get_property(struct power_supply *psy,
return ret;
break;
case POWER_SUPPLY_PROP_VOLTAGE_AVG:
+ case POWER_SUPPLY_PROP_VOLTAGE_NOW:
ret = olpc_ec_cmd(EC_BAT_VOLTAGE, NULL, 0, (void *)&ec_word, 2);
if (ret)
return ret;
@@ -274,6 +341,7 @@ static int olpc_bat_get_property(struct power_supply *psy,
val->intval = (s16)be16_to_cpu(ec_word) * 9760L / 32;
break;
case POWER_SUPPLY_PROP_CURRENT_AVG:
+ case POWER_SUPPLY_PROP_CURRENT_NOW:
ret = olpc_ec_cmd(EC_BAT_CURRENT, NULL, 0, (void *)&ec_word, 2);
if (ret)
return ret;
@@ -294,6 +362,16 @@ static int olpc_bat_get_property(struct power_supply *psy,
else
val->intval = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL;
break;
+ case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
+ ret = olpc_bat_get_charge_full_design(val);
+ if (ret)
+ return ret;
+ break;
+ case POWER_SUPPLY_PROP_CHARGE_NOW:
+ ret = olpc_bat_get_charge_now(val);
+ if (ret)
+ return ret;
+ break;
case POWER_SUPPLY_PROP_TEMP:
ret = olpc_ec_cmd(EC_BAT_TEMP, NULL, 0, (void *)&ec_word, 2);
if (ret)
@@ -331,16 +409,20 @@ static int olpc_bat_get_property(struct power_supply *psy,
return ret;
}
-static enum power_supply_property olpc_bat_props[] = {
+static enum power_supply_property olpc_xo1_bat_props[] = {
POWER_SUPPLY_PROP_STATUS,
POWER_SUPPLY_PROP_CHARGE_TYPE,
POWER_SUPPLY_PROP_PRESENT,
POWER_SUPPLY_PROP_HEALTH,
POWER_SUPPLY_PROP_TECHNOLOGY,
POWER_SUPPLY_PROP_VOLTAGE_AVG,
+ POWER_SUPPLY_PROP_VOLTAGE_NOW,
POWER_SUPPLY_PROP_CURRENT_AVG,
+ POWER_SUPPLY_PROP_CURRENT_NOW,
POWER_SUPPLY_PROP_CAPACITY,
POWER_SUPPLY_PROP_CAPACITY_LEVEL,
+ POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
+ POWER_SUPPLY_PROP_CHARGE_NOW,
POWER_SUPPLY_PROP_TEMP,
POWER_SUPPLY_PROP_TEMP_AMBIENT,
POWER_SUPPLY_PROP_MANUFACTURER,
@@ -348,6 +430,27 @@ static enum power_supply_property olpc_bat_props[] = {
POWER_SUPPLY_PROP_CHARGE_COUNTER,
};
+/* XO-1.5 does not have ambient temperature property */
+static enum power_supply_property olpc_xo15_bat_props[] = {
+ POWER_SUPPLY_PROP_STATUS,
+ POWER_SUPPLY_PROP_CHARGE_TYPE,
+ POWER_SUPPLY_PROP_PRESENT,
+ POWER_SUPPLY_PROP_HEALTH,
+ POWER_SUPPLY_PROP_TECHNOLOGY,
+ POWER_SUPPLY_PROP_VOLTAGE_AVG,
+ POWER_SUPPLY_PROP_VOLTAGE_NOW,
+ POWER_SUPPLY_PROP_CURRENT_AVG,
+ POWER_SUPPLY_PROP_CURRENT_NOW,
+ POWER_SUPPLY_PROP_CAPACITY,
+ POWER_SUPPLY_PROP_CAPACITY_LEVEL,
+ POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
+ POWER_SUPPLY_PROP_CHARGE_NOW,
+ POWER_SUPPLY_PROP_TEMP,
+ POWER_SUPPLY_PROP_MANUFACTURER,
+ POWER_SUPPLY_PROP_SERIAL_NUMBER,
+ POWER_SUPPLY_PROP_CHARGE_COUNTER,
+};
+
/* EEPROM reading goes completely around the power_supply API, sadly */
#define EEPROM_START 0x20
@@ -419,8 +522,6 @@ static struct device_attribute olpc_bat_error = {
static struct platform_device *bat_pdev;
static struct power_supply olpc_bat = {
- .properties = olpc_bat_props,
- .num_properties = ARRAY_SIZE(olpc_bat_props),
.get_property = olpc_bat_get_property,
.use_for_apm = 1,
};
@@ -466,6 +567,13 @@ static int __init olpc_bat_init(void)
goto ac_failed;
olpc_bat.name = bat_pdev->name;
+ if (olpc_board_at_least(olpc_board_pre(0xd0))) { /* XO-1.5 */
+ olpc_bat.properties = olpc_xo15_bat_props;
+ olpc_bat.num_properties = ARRAY_SIZE(olpc_xo15_bat_props);
+ } else { /* XO-1 */
+ olpc_bat.properties = olpc_xo1_bat_props;
+ olpc_bat.num_properties = ARRAY_SIZE(olpc_xo1_bat_props);
+ }
ret = power_supply_register(&bat_pdev->dev, &olpc_bat);
if (ret)
diff --git a/drivers/power/power_supply_core.c b/drivers/power/power_supply_core.c
index 91606bb..970f733 100644
--- a/drivers/power/power_supply_core.c
+++ b/drivers/power/power_supply_core.c
@@ -190,10 +190,10 @@ int power_supply_register(struct device *parent, struct power_supply *psy)
goto success;
create_triggers_failed:
- device_unregister(psy->dev);
+ device_del(dev);
kobject_set_name_failed:
device_add_failed:
- kfree(dev);
+ put_device(dev);
success:
return rc;
}
@@ -201,7 +201,7 @@ EXPORT_SYMBOL_GPL(power_supply_register);
void power_supply_unregister(struct power_supply *psy)
{
- flush_scheduled_work();
+ cancel_work_sync(&psy->changed_work);
power_supply_remove_triggers(psy);
device_unregister(psy->dev);
}
diff --git a/drivers/power/s3c_adc_battery.c b/drivers/power/s3c_adc_battery.c
index 4a8ae39..4255f23 100644
--- a/drivers/power/s3c_adc_battery.c
+++ b/drivers/power/s3c_adc_battery.c
@@ -112,6 +112,13 @@ static int calc_full_volt(int volt_val, int cur_val, int impedance)
return volt_val + cur_val * impedance / 1000;
}
+static int charge_finished(struct s3c_adc_bat *bat)
+{
+ return bat->pdata->gpio_inverted ?
+ !gpio_get_value(bat->pdata->gpio_charge_finished) :
+ gpio_get_value(bat->pdata->gpio_charge_finished);
+}
+
static int s3c_adc_bat_get_property(struct power_supply *psy,
enum power_supply_property psp,
union power_supply_propval *val)
@@ -140,7 +147,7 @@ static int s3c_adc_bat_get_property(struct power_supply *psy,
if (bat->cable_plugged &&
((bat->pdata->gpio_charge_finished < 0) ||
- !gpio_get_value(bat->pdata->gpio_charge_finished))) {
+ !charge_finished(bat))) {
lut = bat->pdata->lut_acin;
lut_size = bat->pdata->lut_acin_cnt;
}
@@ -236,8 +243,7 @@ static void s3c_adc_bat_work(struct work_struct *work)
}
} else {
if ((bat->pdata->gpio_charge_finished >= 0) && is_plugged) {
- is_charged = gpio_get_value(
- main_bat.pdata->gpio_charge_finished);
+ is_charged = charge_finished(&main_bat);
if (is_charged) {
if (bat->pdata->disable_charger)
bat->pdata->disable_charger();
diff --git a/drivers/power/tosa_battery.c b/drivers/power/tosa_battery.c
index ee04936..53f0d35 100644
--- a/drivers/power/tosa_battery.c
+++ b/drivers/power/tosa_battery.c
@@ -332,7 +332,7 @@ static struct {
static int tosa_bat_suspend(struct platform_device *dev, pm_message_t state)
{
/* flush all pending status updates */
- flush_scheduled_work();
+ flush_work_sync(&bat_work);
return 0;
}
@@ -422,7 +422,7 @@ err_psy_reg_jacket:
err_psy_reg_main:
/* see comment in tosa_bat_remove */
- flush_scheduled_work();
+ cancel_work_sync(&bat_work);
i--;
err_gpio:
@@ -445,12 +445,11 @@ static int __devexit tosa_bat_remove(struct platform_device *dev)
power_supply_unregister(&tosa_bat_main.psy);
/*
- * now flush all pending work.
- * we won't get any more schedules, since all
- * sources (isr and external_power_changed)
- * are unregistered now.
+ * Now cancel the bat_work. We won't get any more schedules,
+ * since all sources (isr and external_power_changed) are
+ * unregistered now.
*/
- flush_scheduled_work();
+ cancel_work_sync(&bat_work);
for (i = ARRAY_SIZE(gpios) - 1; i >= 0; i--)
gpio_free(gpios[i].gpio);
diff --git a/drivers/power/wm97xx_battery.c b/drivers/power/wm97xx_battery.c
index 5071d85..156559e 100644
--- a/drivers/power/wm97xx_battery.c
+++ b/drivers/power/wm97xx_battery.c
@@ -147,7 +147,7 @@ static irqreturn_t wm97xx_chrg_irq(int irq, void *data)
#ifdef CONFIG_PM
static int wm97xx_bat_suspend(struct device *dev)
{
- flush_scheduled_work();
+ flush_work_sync(&bat_work);
return 0;
}
@@ -273,7 +273,7 @@ static int __devexit wm97xx_bat_remove(struct platform_device *dev)
free_irq(gpio_to_irq(pdata->charge_gpio), dev);
gpio_free(pdata->charge_gpio);
}
- flush_scheduled_work();
+ cancel_work_sync(&bat_work);
power_supply_unregister(&bat_ps);
kfree(prop);
return 0;
diff --git a/drivers/power/z2_battery.c b/drivers/power/z2_battery.c
index 85064a9..e5ed52d 100644
--- a/drivers/power/z2_battery.c
+++ b/drivers/power/z2_battery.c
@@ -254,7 +254,7 @@ static int __devexit z2_batt_remove(struct i2c_client *client)
struct z2_charger *charger = i2c_get_clientdata(client);
struct z2_battery_info *info = charger->info;
- flush_scheduled_work();
+ cancel_work_sync(&charger->bat_work);
power_supply_unregister(&charger->batt_ps);
kfree(charger->batt_ps.properties);
@@ -271,7 +271,9 @@ static int __devexit z2_batt_remove(struct i2c_client *client)
#ifdef CONFIG_PM
static int z2_batt_suspend(struct i2c_client *client, pm_message_t state)
{
- flush_scheduled_work();
+ struct z2_charger *charger = i2c_get_clientdata(client);
+
+ flush_work_sync(&charger->bat_work);
return 0;
}
diff --git a/drivers/rapidio/rio-scan.c b/drivers/rapidio/rio-scan.c
index 467e82b..a50391b 100644
--- a/drivers/rapidio/rio-scan.c
+++ b/drivers/rapidio/rio-scan.c
@@ -943,6 +943,8 @@ static int rio_enum_complete(struct rio_mport *port)
* @port: Master port to send transactions
* @destid: Current destination ID in network
* @hopcount: Number of hops into the network
+ * @prev: previous rio_dev
+ * @prev_port: previous port number
*
* Recursively discovers a RIO network. Transactions are sent via the
* master port passed in @port.
diff --git a/drivers/regulator/max8998.c b/drivers/regulator/max8998.c
index 7568df6..0ec49ca 100644
--- a/drivers/regulator/max8998.c
+++ b/drivers/regulator/max8998.c
@@ -424,6 +424,9 @@ static int max8998_set_voltage_buck(struct regulator_dev *rdev,
}
}
+ if (pdata->buck_voltage_lock)
+ return -EINVAL;
+
/* no predefine regulator found */
max8998->buck1_idx = (buck1_last_val % 2) + 2;
dev_dbg(max8998->dev, "max8998->buck1_idx:%d\n",
@@ -451,18 +454,26 @@ buck1_exit:
"BUCK2, i:%d buck2_vol1:%d, buck2_vol2:%d\n"
, i, max8998->buck2_vol[0], max8998->buck2_vol[1]);
if (gpio_is_valid(pdata->buck2_set3)) {
- if (max8998->buck2_vol[0] == i) {
- max8998->buck1_idx = 0;
- buck2_gpio_set(pdata->buck2_set3, 0);
- } else {
- max8998->buck1_idx = 1;
- ret = max8998_get_voltage_register(rdev, &reg,
- &shift,
- &mask);
- ret = max8998_write_reg(i2c, reg, i);
- max8998->buck2_vol[1] = i;
- buck2_gpio_set(pdata->buck2_set3, 1);
+
+ /* check if requested voltage */
+ /* value is already defined */
+ for (j = 0; j < ARRAY_SIZE(max8998->buck2_vol); j++) {
+ if (max8998->buck2_vol[j] == i) {
+ max8998->buck2_idx = j;
+ buck2_gpio_set(pdata->buck2_set3, j);
+ goto buck2_exit;
+ }
}
+
+ if (pdata->buck_voltage_lock)
+ return -EINVAL;
+
+ max8998_get_voltage_register(rdev,
+ &reg, &shift, &mask);
+ ret = max8998_write_reg(i2c, reg, i);
+ max8998->buck2_vol[max8998->buck2_idx] = i;
+ buck2_gpio_set(pdata->buck2_set3, max8998->buck2_idx);
+buck2_exit:
dev_dbg(max8998->dev, "%s: SET3:%d\n", i2c->name,
gpio_get_value(pdata->buck2_set3));
} else {
@@ -707,6 +718,9 @@ static __devinit int max8998_pmic_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, max8998);
i2c = max8998->iodev->i2c;
+ max8998->buck1_idx = pdata->buck1_default_idx;
+ max8998->buck2_idx = pdata->buck2_default_idx;
+
/* NOTE: */
/* For unused GPIO NOT marked as -1 (thereof equal to 0) WARN_ON */
/* will be displayed */
@@ -739,23 +753,46 @@ static __devinit int max8998_pmic_probe(struct platform_device *pdev)
i = 0;
while (buck12_voltage_map_desc.min +
buck12_voltage_map_desc.step*i
- != (pdata->buck1_max_voltage1 / 1000))
+ < (pdata->buck1_voltage1 / 1000))
i++;
- printk(KERN_ERR "i:%d, buck1_idx:%d\n", i, max8998->buck1_idx);
max8998->buck1_vol[0] = i;
ret = max8998_write_reg(i2c, MAX8998_REG_BUCK1_VOLTAGE1, i);
+ if (ret)
+ return ret;
/* Set predefined value for BUCK1 register 2 */
i = 0;
while (buck12_voltage_map_desc.min +
buck12_voltage_map_desc.step*i
- != (pdata->buck1_max_voltage2 / 1000))
+ < (pdata->buck1_voltage2 / 1000))
i++;
max8998->buck1_vol[1] = i;
- printk(KERN_ERR "i:%d, buck1_idx:%d\n", i, max8998->buck1_idx);
- ret = max8998_write_reg(i2c, MAX8998_REG_BUCK1_VOLTAGE2, i)
- + ret;
+ ret = max8998_write_reg(i2c, MAX8998_REG_BUCK1_VOLTAGE2, i);
+ if (ret)
+ return ret;
+
+ /* Set predefined value for BUCK1 register 3 */
+ i = 0;
+ while (buck12_voltage_map_desc.min +
+ buck12_voltage_map_desc.step*i
+ < (pdata->buck1_voltage3 / 1000))
+ i++;
+
+ max8998->buck1_vol[2] = i;
+ ret = max8998_write_reg(i2c, MAX8998_REG_BUCK1_VOLTAGE3, i);
+ if (ret)
+ return ret;
+
+ /* Set predefined value for BUCK1 register 4 */
+ i = 0;
+ while (buck12_voltage_map_desc.min +
+ buck12_voltage_map_desc.step*i
+ < (pdata->buck1_voltage4 / 1000))
+ i++;
+
+ max8998->buck1_vol[3] = i;
+ ret = max8998_write_reg(i2c, MAX8998_REG_BUCK1_VOLTAGE4, i);
if (ret)
return ret;
@@ -772,18 +809,28 @@ static __devinit int max8998_pmic_probe(struct platform_device *pdev)
gpio_direction_output(pdata->buck2_set3,
max8998->buck2_idx & 0x1);
- /* BUCK2 - set preset default voltage value to buck2_vol[0] */
+ /* BUCK2 register 1 */
i = 0;
while (buck12_voltage_map_desc.min +
buck12_voltage_map_desc.step*i
- != (pdata->buck2_max_voltage / 1000))
+ < (pdata->buck2_voltage1 / 1000))
i++;
- printk(KERN_ERR "i:%d, buck2_idx:%d\n", i, max8998->buck2_idx);
max8998->buck2_vol[0] = i;
ret = max8998_write_reg(i2c, MAX8998_REG_BUCK2_VOLTAGE1, i);
if (ret)
return ret;
+ /* BUCK2 register 2 */
+ i = 0;
+ while (buck12_voltage_map_desc.min +
+ buck12_voltage_map_desc.step*i
+ < (pdata->buck2_voltage2 / 1000))
+ i++;
+ printk(KERN_ERR "i2:%d, buck2_idx:%d\n", i, max8998->buck2_idx);
+ max8998->buck2_vol[1] = i;
+ ret = max8998_write_reg(i2c, MAX8998_REG_BUCK2_VOLTAGE2, i);
+ if (ret)
+ return ret;
}
for (i = 0; i < pdata->num_regulators; i++) {
@@ -835,6 +882,12 @@ static int __devexit max8998_pmic_remove(struct platform_device *pdev)
return 0;
}
+static const struct platform_device_id max8998_pmic_id[] = {
+ { "max8998-pmic", TYPE_MAX8998 },
+ { "lp3974-pmic", TYPE_LP3974 },
+ { }
+};
+
static struct platform_driver max8998_pmic_driver = {
.driver = {
.name = "max8998-pmic",
@@ -842,6 +895,7 @@ static struct platform_driver max8998_pmic_driver = {
},
.probe = max8998_pmic_probe,
.remove = __devexit_p(max8998_pmic_remove),
+ .id_table = max8998_pmic_id,
};
static int __init max8998_pmic_init(void)
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 4941cad..cdd9719 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -97,18 +97,6 @@ config RTC_INTF_DEV
If unsure, say Y.
-config RTC_INTF_DEV_UIE_EMUL
- bool "RTC UIE emulation on dev interface"
- depends on RTC_INTF_DEV
- help
- Provides an emulation for RTC_UIE if the underlying rtc chip
- driver does not expose RTC_UIE ioctls. Those requests generate
- once-per-second update interrupts, used for synchronization.
-
- The emulation code will read the time from the hardware
- clock several times per second, please enable this option
- only if you know that you really need it.
-
config RTC_DRV_TEST
tristate "Test driver/device"
help
diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c
index 90384b9..925006d 100644
--- a/drivers/rtc/interface.c
+++ b/drivers/rtc/interface.c
@@ -16,6 +16,9 @@
#include <linux/log2.h>
#include <linux/workqueue.h>
+static int rtc_timer_enqueue(struct rtc_device *rtc, struct rtc_timer *timer);
+static void rtc_timer_remove(struct rtc_device *rtc, struct rtc_timer *timer);
+
static int __rtc_read_time(struct rtc_device *rtc, struct rtc_time *tm)
{
int err;
@@ -120,12 +123,18 @@ int rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
err = mutex_lock_interruptible(&rtc->ops_lock);
if (err)
return err;
- alarm->enabled = rtc->aie_timer.enabled;
- if (alarm->enabled)
+ if (rtc->ops == NULL)
+ err = -ENODEV;
+ else if (!rtc->ops->read_alarm)
+ err = -EINVAL;
+ else {
+ memset(alarm, 0, sizeof(struct rtc_wkalrm));
+ alarm->enabled = rtc->aie_timer.enabled;
alarm->time = rtc_ktime_to_tm(rtc->aie_timer.node.expires);
+ }
mutex_unlock(&rtc->ops_lock);
- return 0;
+ return err;
}
EXPORT_SYMBOL_GPL(rtc_read_alarm);
@@ -175,16 +184,14 @@ int rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
return err;
if (rtc->aie_timer.enabled) {
rtc_timer_remove(rtc, &rtc->aie_timer);
- rtc->aie_timer.enabled = 0;
}
rtc->aie_timer.node.expires = rtc_tm_to_ktime(alarm->time);
rtc->aie_timer.period = ktime_set(0, 0);
if (alarm->enabled) {
- rtc->aie_timer.enabled = 1;
- rtc_timer_enqueue(rtc, &rtc->aie_timer);
+ err = rtc_timer_enqueue(rtc, &rtc->aie_timer);
}
mutex_unlock(&rtc->ops_lock);
- return 0;
+ return err;
}
EXPORT_SYMBOL_GPL(rtc_set_alarm);
@@ -195,15 +202,15 @@ int rtc_alarm_irq_enable(struct rtc_device *rtc, unsigned int enabled)
return err;
if (rtc->aie_timer.enabled != enabled) {
- if (enabled) {
- rtc->aie_timer.enabled = 1;
- rtc_timer_enqueue(rtc, &rtc->aie_timer);
- } else {
+ if (enabled)
+ err = rtc_timer_enqueue(rtc, &rtc->aie_timer);
+ else
rtc_timer_remove(rtc, &rtc->aie_timer);
- rtc->aie_timer.enabled = 0;
- }
}
+ if (err)
+ return err;
+
if (!rtc->ops)
err = -ENODEV;
else if (!rtc->ops->alarm_irq_enable)
@@ -235,12 +242,9 @@ int rtc_update_irq_enable(struct rtc_device *rtc, unsigned int enabled)
now = rtc_tm_to_ktime(tm);
rtc->uie_rtctimer.node.expires = ktime_add(now, onesec);
rtc->uie_rtctimer.period = ktime_set(1, 0);
- rtc->uie_rtctimer.enabled = 1;
- rtc_timer_enqueue(rtc, &rtc->uie_rtctimer);
- } else {
+ err = rtc_timer_enqueue(rtc, &rtc->uie_rtctimer);
+ } else
rtc_timer_remove(rtc, &rtc->uie_rtctimer);
- rtc->uie_rtctimer.enabled = 0;
- }
out:
mutex_unlock(&rtc->ops_lock);
@@ -488,10 +492,13 @@ EXPORT_SYMBOL_GPL(rtc_irq_set_freq);
* Enqueues a timer onto the rtc devices timerqueue and sets
* the next alarm event appropriately.
*
+ * Sets the enabled bit on the added timer.
+ *
* Must hold ops_lock for proper serialization of timerqueue
*/
-void rtc_timer_enqueue(struct rtc_device *rtc, struct rtc_timer *timer)
+static int rtc_timer_enqueue(struct rtc_device *rtc, struct rtc_timer *timer)
{
+ timer->enabled = 1;
timerqueue_add(&rtc->timerqueue, &timer->node);
if (&timer->node == timerqueue_getnext(&rtc->timerqueue)) {
struct rtc_wkalrm alarm;
@@ -501,7 +508,13 @@ void rtc_timer_enqueue(struct rtc_device *rtc, struct rtc_timer *timer)
err = __rtc_set_alarm(rtc, &alarm);
if (err == -ETIME)
schedule_work(&rtc->irqwork);
+ else if (err) {
+ timerqueue_del(&rtc->timerqueue, &timer->node);
+ timer->enabled = 0;
+ return err;
+ }
}
+ return 0;
}
/**
@@ -512,13 +525,15 @@ void rtc_timer_enqueue(struct rtc_device *rtc, struct rtc_timer *timer)
* Removes a timer onto the rtc devices timerqueue and sets
* the next alarm event appropriately.
*
+ * Clears the enabled bit on the removed timer.
+ *
* Must hold ops_lock for proper serialization of timerqueue
*/
-void rtc_timer_remove(struct rtc_device *rtc, struct rtc_timer *timer)
+static void rtc_timer_remove(struct rtc_device *rtc, struct rtc_timer *timer)
{
struct timerqueue_node *next = timerqueue_getnext(&rtc->timerqueue);
timerqueue_del(&rtc->timerqueue, &timer->node);
-
+ timer->enabled = 0;
if (next == &timer->node) {
struct rtc_wkalrm alarm;
int err;
@@ -626,8 +641,7 @@ int rtc_timer_start(struct rtc_device *rtc, struct rtc_timer* timer,
timer->node.expires = expires;
timer->period = period;
- timer->enabled = 1;
- rtc_timer_enqueue(rtc, timer);
+ ret = rtc_timer_enqueue(rtc, timer);
mutex_unlock(&rtc->ops_lock);
return ret;
@@ -645,7 +659,6 @@ int rtc_timer_cancel(struct rtc_device *rtc, struct rtc_timer* timer)
mutex_lock(&rtc->ops_lock);
if (timer->enabled)
rtc_timer_remove(rtc, timer);
- timer->enabled = 0;
mutex_unlock(&rtc->ops_lock);
return ret;
}
diff --git a/drivers/rtc/rtc-max8998.c b/drivers/rtc/rtc-max8998.c
index f22dee3..3f7bc6b 100644
--- a/drivers/rtc/rtc-max8998.c
+++ b/drivers/rtc/rtc-max8998.c
@@ -20,6 +20,7 @@
#include <linux/platform_device.h>
#include <linux/mfd/max8998.h>
#include <linux/mfd/max8998-private.h>
+#include <linux/delay.h>
#define MAX8998_RTC_SEC 0x00
#define MAX8998_RTC_MIN 0x01
@@ -73,6 +74,7 @@ struct max8998_rtc_info {
struct i2c_client *rtc;
struct rtc_device *rtc_dev;
int irq;
+ bool lp3974_bug_workaround;
};
static void max8998_data_to_tm(u8 *data, struct rtc_time *tm)
@@ -124,10 +126,16 @@ static int max8998_rtc_set_time(struct device *dev, struct rtc_time *tm)
{
struct max8998_rtc_info *info = dev_get_drvdata(dev);
u8 data[8];
+ int ret;
max8998_tm_to_data(tm, data);
- return max8998_bulk_write(info->rtc, MAX8998_RTC_SEC, 8, data);
+ ret = max8998_bulk_write(info->rtc, MAX8998_RTC_SEC, 8, data);
+
+ if (info->lp3974_bug_workaround)
+ msleep(2000);
+
+ return ret;
}
static int max8998_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
@@ -163,12 +171,29 @@ static int max8998_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
static int max8998_rtc_stop_alarm(struct max8998_rtc_info *info)
{
- return max8998_write_reg(info->rtc, MAX8998_ALARM0_CONF, 0);
+ int ret = max8998_write_reg(info->rtc, MAX8998_ALARM0_CONF, 0);
+
+ if (info->lp3974_bug_workaround)
+ msleep(2000);
+
+ return ret;
}
static int max8998_rtc_start_alarm(struct max8998_rtc_info *info)
{
- return max8998_write_reg(info->rtc, MAX8998_ALARM0_CONF, 0x77);
+ int ret;
+ u8 alarm0_conf = 0x77;
+
+ /* LP3974 with delay bug chips has rtc alarm bugs with "MONTH" field */
+ if (info->lp3974_bug_workaround)
+ alarm0_conf = 0x57;
+
+ ret = max8998_write_reg(info->rtc, MAX8998_ALARM0_CONF, alarm0_conf);
+
+ if (info->lp3974_bug_workaround)
+ msleep(2000);
+
+ return ret;
}
static int max8998_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
@@ -187,10 +212,13 @@ static int max8998_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
if (ret < 0)
return ret;
+ if (info->lp3974_bug_workaround)
+ msleep(2000);
+
if (alrm->enabled)
- return max8998_rtc_start_alarm(info);
+ ret = max8998_rtc_start_alarm(info);
- return 0;
+ return ret;
}
static int max8998_rtc_alarm_irq_enable(struct device *dev,
@@ -224,6 +252,7 @@ static const struct rtc_class_ops max8998_rtc_ops = {
static int __devinit max8998_rtc_probe(struct platform_device *pdev)
{
struct max8998_dev *max8998 = dev_get_drvdata(pdev->dev.parent);
+ struct max8998_platform_data *pdata = dev_get_platdata(max8998->dev);
struct max8998_rtc_info *info;
int ret;
@@ -249,10 +278,18 @@ static int __devinit max8998_rtc_probe(struct platform_device *pdev)
ret = request_threaded_irq(info->irq, NULL, max8998_rtc_alarm_irq, 0,
"rtc-alarm0", info);
+
if (ret < 0)
dev_err(&pdev->dev, "Failed to request alarm IRQ: %d: %d\n",
info->irq, ret);
+ dev_info(&pdev->dev, "RTC CHIP NAME: %s\n", pdev->id_entry->name);
+ if (pdata->rtc_delay) {
+ info->lp3974_bug_workaround = true;
+ dev_warn(&pdev->dev, "LP3974 with RTC REGERR option."
+ " RTC updates will be extremely slow.\n");
+ }
+
return 0;
out_rtc:
@@ -273,6 +310,12 @@ static int __devexit max8998_rtc_remove(struct platform_device *pdev)
return 0;
}
+static const struct platform_device_id max8998_rtc_id[] = {
+ { "max8998-rtc", TYPE_MAX8998 },
+ { "lp3974-rtc", TYPE_LP3974 },
+ { }
+};
+
static struct platform_driver max8998_rtc_driver = {
.driver = {
.name = "max8998-rtc",
@@ -280,6 +323,7 @@ static struct platform_driver max8998_rtc_driver = {
},
.probe = max8998_rtc_probe,
.remove = __devexit_p(max8998_rtc_remove),
+ .id_table = max8998_rtc_id,
};
static int __init max8998_rtc_init(void)
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c
index e8391b89..b7eaff9 100644
--- a/drivers/s390/cio/device.c
+++ b/drivers/s390/cio/device.c
@@ -1835,6 +1835,7 @@ static void __ccw_device_pm_restore(struct ccw_device *cdev)
* available again. Kick re-detection.
*/
cdev->private->flags.resuming = 1;
+ cdev->private->path_new_mask = LPM_ANYPATH;
css_schedule_eval(sch->schid);
spin_unlock_irq(sch->lock);
css_complete_work();
diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c
index 7a7a1b6..2ac8f6a 100644
--- a/drivers/s390/net/qeth_l2_main.c
+++ b/drivers/s390/net/qeth_l2_main.c
@@ -831,12 +831,14 @@ tx_drop:
return NETDEV_TX_OK;
}
-static int qeth_l2_open(struct net_device *dev)
+static int __qeth_l2_open(struct net_device *dev)
{
struct qeth_card *card = dev->ml_priv;
int rc = 0;
QETH_CARD_TEXT(card, 4, "qethopen");
+ if (card->state == CARD_STATE_UP)
+ return rc;
if (card->state != CARD_STATE_SOFTSETUP)
return -ENODEV;
@@ -857,6 +859,18 @@ static int qeth_l2_open(struct net_device *dev)
return rc;
}
+static int qeth_l2_open(struct net_device *dev)
+{
+ struct qeth_card *card = dev->ml_priv;
+
+ QETH_CARD_TEXT(card, 5, "qethope_");
+ if (qeth_wait_for_threads(card, QETH_RECOVER_THREAD)) {
+ QETH_CARD_TEXT(card, 3, "openREC");
+ return -ERESTARTSYS;
+ }
+ return __qeth_l2_open(dev);
+}
+
static int qeth_l2_stop(struct net_device *dev)
{
struct qeth_card *card = dev->ml_priv;
@@ -1046,7 +1060,7 @@ contin:
if (recover_flag == CARD_STATE_RECOVER) {
if (recovery_mode &&
card->info.type != QETH_CARD_TYPE_OSN) {
- qeth_l2_open(card->dev);
+ __qeth_l2_open(card->dev);
} else {
rtnl_lock();
dev_open(card->dev);
diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c
index e227e46..d09b0c4 100644
--- a/drivers/s390/net/qeth_l3_main.c
+++ b/drivers/s390/net/qeth_l3_main.c
@@ -2998,7 +2998,9 @@ static inline void qeth_l3_hdr_csum(struct qeth_card *card,
*/
if (iph->protocol == IPPROTO_UDP)
hdr->hdr.l3.ext_flags |= QETH_HDR_EXT_UDP;
- hdr->hdr.l3.ext_flags |= QETH_HDR_EXT_CSUM_TRANSP_REQ;
+ hdr->hdr.l3.ext_flags |= QETH_HDR_EXT_CSUM_TRANSP_REQ |
+ QETH_HDR_EXT_CSUM_HDR_REQ;
+ iph->check = 0;
if (card->options.performance_stats)
card->perf_stats.tx_csum++;
}
@@ -3240,12 +3242,14 @@ tx_drop:
return NETDEV_TX_OK;
}
-static int qeth_l3_open(struct net_device *dev)
+static int __qeth_l3_open(struct net_device *dev)
{
struct qeth_card *card = dev->ml_priv;
int rc = 0;
QETH_CARD_TEXT(card, 4, "qethopen");
+ if (card->state == CARD_STATE_UP)
+ return rc;
if (card->state != CARD_STATE_SOFTSETUP)
return -ENODEV;
card->data.state = CH_STATE_UP;
@@ -3260,6 +3264,18 @@ static int qeth_l3_open(struct net_device *dev)
return rc;
}
+static int qeth_l3_open(struct net_device *dev)
+{
+ struct qeth_card *card = dev->ml_priv;
+
+ QETH_CARD_TEXT(card, 5, "qethope_");
+ if (qeth_wait_for_threads(card, QETH_RECOVER_THREAD)) {
+ QETH_CARD_TEXT(card, 3, "openREC");
+ return -ERESTARTSYS;
+ }
+ return __qeth_l3_open(dev);
+}
+
static int qeth_l3_stop(struct net_device *dev)
{
struct qeth_card *card = dev->ml_priv;
@@ -3564,7 +3580,7 @@ contin:
netif_carrier_off(card->dev);
if (recover_flag == CARD_STATE_RECOVER) {
if (recovery_mode)
- qeth_l3_open(card->dev);
+ __qeth_l3_open(card->dev);
else {
rtnl_lock();
dev_open(card->dev);
diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c
index d3c5905..9c5c8be 100644
--- a/drivers/scsi/ipr.c
+++ b/drivers/scsi/ipr.c
@@ -7515,16 +7515,10 @@ static int ipr_reset_restore_cfg_space(struct ipr_cmnd *ipr_cmd)
{
struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
volatile u32 int_reg;
- int rc;
ENTER;
ioa_cfg->pdev->state_saved = true;
- rc = pci_restore_state(ioa_cfg->pdev);
-
- if (rc != PCIBIOS_SUCCESSFUL) {
- ipr_cmd->s.ioasa.hdr.ioasc = cpu_to_be32(IPR_IOASC_PCI_ACCESS_ERROR);
- return IPR_RC_JOB_CONTINUE;
- }
+ pci_restore_state(ioa_cfg->pdev);
if (ipr_set_pcix_cmd_reg(ioa_cfg)) {
ipr_cmd->s.ioasa.hdr.ioasc = cpu_to_be32(IPR_IOASC_PCI_ACCESS_ERROR);
diff --git a/drivers/scsi/pmcraid.c b/drivers/scsi/pmcraid.c
index 300d59f..321cf3a 100644
--- a/drivers/scsi/pmcraid.c
+++ b/drivers/scsi/pmcraid.c
@@ -2228,12 +2228,7 @@ static void pmcraid_ioa_reset(struct pmcraid_cmd *cmd)
/* Once either bist or pci reset is done, restore PCI config
* space. If this fails, proceed with hard reset again
*/
- if (pci_restore_state(pinstance->pdev)) {
- pmcraid_info("config-space error resetting again\n");
- pinstance->ioa_state = IOA_STATE_IN_RESET_ALERT;
- pmcraid_reset_alert(cmd);
- break;
- }
+ pci_restore_state(pinstance->pdev);
/* fail all pending commands */
pmcraid_fail_outstanding_cmds(pinstance);
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index b65e65a..e567302 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -990,30 +990,51 @@ out:
static void set_media_not_present(struct scsi_disk *sdkp)
{
- sdkp->media_present = 0;
- sdkp->capacity = 0;
- sdkp->device->changed = 1;
+ if (sdkp->media_present)
+ sdkp->device->changed = 1;
+
+ if (sdkp->device->removable) {
+ sdkp->media_present = 0;
+ sdkp->capacity = 0;
+ }
+}
+
+static int media_not_present(struct scsi_disk *sdkp,
+ struct scsi_sense_hdr *sshdr)
+{
+ if (!scsi_sense_valid(sshdr))
+ return 0;
+
+ /* not invoked for commands that could return deferred errors */
+ switch (sshdr->sense_key) {
+ case UNIT_ATTENTION:
+ case NOT_READY:
+ /* medium not present */
+ if (sshdr->asc == 0x3A) {
+ set_media_not_present(sdkp);
+ return 1;
+ }
+ }
+ return 0;
}
/**
- * sd_media_changed - check if our medium changed
- * @disk: kernel device descriptor
+ * sd_check_events - check media events
+ * @disk: kernel device descriptor
+ * @clearing: disk events currently being cleared
*
- * Returns 0 if not applicable or no change; 1 if change
+ * Returns mask of DISK_EVENT_*.
*
* Note: this function is invoked from the block subsystem.
**/
-static int sd_media_changed(struct gendisk *disk)
+static unsigned int sd_check_events(struct gendisk *disk, unsigned int clearing)
{
struct scsi_disk *sdkp = scsi_disk(disk);
struct scsi_device *sdp = sdkp->device;
struct scsi_sense_hdr *sshdr = NULL;
int retval;
- SCSI_LOG_HLQUEUE(3, sd_printk(KERN_INFO, sdkp, "sd_media_changed\n"));
-
- if (!sdp->removable)
- return 0;
+ SCSI_LOG_HLQUEUE(3, sd_printk(KERN_INFO, sdkp, "sd_check_events\n"));
/*
* If the device is offline, don't send any commands - just pretend as
@@ -1043,40 +1064,32 @@ static int sd_media_changed(struct gendisk *disk)
sshdr);
}
- if (retval) {
+ /* failed to execute TUR, assume media not present */
+ if (host_byte(retval)) {
set_media_not_present(sdkp);
goto out;
}
+ if (media_not_present(sdkp, sshdr))
+ goto out;
+
/*
* For removable scsi disk we have to recognise the presence
- * of a disk in the drive. This is kept in the struct scsi_disk
- * struct and tested at open ! Daniel Roche (dan@lectra.fr)
+ * of a disk in the drive.
*/
+ if (!sdkp->media_present)
+ sdp->changed = 1;
sdkp->media_present = 1;
-
out:
/*
- * Report a media change under the following conditions:
- *
- * Medium is present now and wasn't present before.
- * Medium wasn't present before and is present now.
- * Medium was present at all times, but it changed while
- * we weren't looking (sdp->changed is set).
+ * sdp->changed is set under the following conditions:
*
- * If there was no medium before and there is no medium now then
- * don't report a change, even if a medium was inserted and removed
- * while we weren't looking.
+ * Medium present state has changed in either direction.
+ * Device has indicated UNIT_ATTENTION.
*/
- retval = (sdkp->media_present != sdkp->previous_state ||
- (sdkp->media_present && sdp->changed));
- if (retval)
- sdev_evt_send_simple(sdp, SDEV_EVT_MEDIA_CHANGE, GFP_KERNEL);
- sdkp->previous_state = sdkp->media_present;
-
- /* sdp->changed indicates medium was changed or is not present */
- sdp->changed = !sdkp->media_present;
kfree(sshdr);
+ retval = sdp->changed ? DISK_EVENT_MEDIA_CHANGE : 0;
+ sdp->changed = 0;
return retval;
}
@@ -1169,7 +1182,7 @@ static const struct block_device_operations sd_fops = {
#ifdef CONFIG_COMPAT
.compat_ioctl = sd_compat_ioctl,
#endif
- .media_changed = sd_media_changed,
+ .check_events = sd_check_events,
.revalidate_disk = sd_revalidate_disk,
.unlock_native_capacity = sd_unlock_native_capacity,
};
@@ -1312,23 +1325,6 @@ static int sd_done(struct scsi_cmnd *SCpnt)
return good_bytes;
}
-static int media_not_present(struct scsi_disk *sdkp,
- struct scsi_sense_hdr *sshdr)
-{
-
- if (!scsi_sense_valid(sshdr))
- return 0;
- /* not invoked for commands that could return deferred errors */
- if (sshdr->sense_key != NOT_READY &&
- sshdr->sense_key != UNIT_ATTENTION)
- return 0;
- if (sshdr->asc != 0x3A) /* medium not present */
- return 0;
-
- set_media_not_present(sdkp);
- return 1;
-}
-
/*
* spinup disk - called only in sd_revalidate_disk()
*/
@@ -1503,7 +1499,7 @@ static void read_capacity_error(struct scsi_disk *sdkp, struct scsi_device *sdp,
*/
if (sdp->removable &&
sense_valid && sshdr->sense_key == NOT_READY)
- sdp->changed = 1;
+ set_media_not_present(sdkp);
/*
* We used to set media_present to 0 here to indicate no media
@@ -2389,8 +2385,10 @@ static void sd_probe_async(void *data, async_cookie_t cookie)
gd->driverfs_dev = &sdp->sdev_gendev;
gd->flags = GENHD_FL_EXT_DEVT;
- if (sdp->removable)
+ if (sdp->removable) {
gd->flags |= GENHD_FL_REMOVABLE;
+ gd->events |= DISK_EVENT_MEDIA_CHANGE;
+ }
add_disk(gd);
sd_dif_config_host(sdkp);
@@ -2472,7 +2470,6 @@ static int sd_probe(struct device *dev)
sdkp->disk = gd;
sdkp->index = index;
atomic_set(&sdkp->openers, 0);
- sdkp->previous_state = 1;
if (!sdp->request_queue->rq_timeout) {
if (sdp->type != TYPE_MOD)
diff --git a/drivers/scsi/sd.h b/drivers/scsi/sd.h
index 55488fa..c9d8f6c 100644
--- a/drivers/scsi/sd.h
+++ b/drivers/scsi/sd.h
@@ -55,7 +55,6 @@ struct scsi_disk {
u8 media_present;
u8 write_prot;
u8 protection_type;/* Data Integrity Field */
- unsigned previous_state : 1;
unsigned ATO : 1; /* state of disk ATO bit */
unsigned WCE : 1; /* state of disk WCE bit */
unsigned RCD : 1; /* state of disk RCD bit, unused */
diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c
index be6baf8..aefadc6 100644
--- a/drivers/scsi/sr.c
+++ b/drivers/scsi/sr.c
@@ -249,10 +249,6 @@ skip_tur:
cd->device->changed = 0;
}
- /* for backward compatibility */
- if (events & DISK_EVENT_MEDIA_CHANGE)
- sdev_evt_send_simple(cd->device, SDEV_EVT_MEDIA_CHANGE,
- GFP_KERNEL);
return events;
}
diff --git a/drivers/sfi/sfi_core.c b/drivers/sfi/sfi_core.c
index ceba593..04113e5 100644
--- a/drivers/sfi/sfi_core.c
+++ b/drivers/sfi/sfi_core.c
@@ -101,7 +101,7 @@ static void __iomem * __ref sfi_map_memory(u64 phys, u32 size)
return NULL;
if (sfi_use_ioremap)
- return ioremap(phys, size);
+ return ioremap_cache(phys, size);
else
return early_ioremap(phys, size);
}
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 1906840..bb233a9c 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -53,6 +53,14 @@ if SPI_MASTER
comment "SPI Master Controller Drivers"
+config SPI_ATH79
+ tristate "Atheros AR71XX/AR724X/AR913X SPI controller driver"
+ depends on ATH79 && GENERIC_GPIO
+ select SPI_BITBANG
+ help
+ This enables support for the SPI controller present on the
+ Atheros AR71XX/AR724X/AR913X SoCs.
+
config SPI_ATMEL
tristate "Atmel SPI Controller"
depends on (ARCH_AT91 || AVR32)
@@ -156,10 +164,10 @@ config SPI_IMX_VER_0_4
def_bool y if ARCH_MX31
config SPI_IMX_VER_0_7
- def_bool y if ARCH_MX25 || ARCH_MX35 || ARCH_MX51
+ def_bool y if ARCH_MX25 || ARCH_MX35 || ARCH_MX51 || ARCH_MX53
config SPI_IMX_VER_2_3
- def_bool y if ARCH_MX51
+ def_bool y if ARCH_MX51 || ARCH_MX53
config SPI_IMX
tristate "Freescale i.MX SPI controllers"
@@ -310,8 +318,8 @@ config SPI_S3C24XX_GPIO
config SPI_S3C64XX
tristate "Samsung S3C64XX series type SPI"
- depends on ARCH_S3C64XX && EXPERIMENTAL
- select S3C64XX_DMA
+ depends on (ARCH_S3C64XX || ARCH_S5P64X0)
+ select S3C64XX_DMA if ARCH_S3C64XX
help
SPI driver for Samsung S3C64XX and newer SoCs.
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index 3a42463..86d1b5f 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -10,6 +10,7 @@ obj-$(CONFIG_SPI_MASTER) += spi.o
# SPI master controller drivers (bus)
obj-$(CONFIG_SPI_ATMEL) += atmel_spi.o
+obj-$(CONFIG_SPI_ATH79) += ath79_spi.o
obj-$(CONFIG_SPI_BFIN) += spi_bfin5xx.o
obj-$(CONFIG_SPI_BITBANG) += spi_bitbang.o
obj-$(CONFIG_SPI_AU1550) += au1550_spi.o
diff --git a/drivers/spi/amba-pl022.c b/drivers/spi/amba-pl022.c
index a2a5921..71a1219 100644
--- a/drivers/spi/amba-pl022.c
+++ b/drivers/spi/amba-pl022.c
@@ -1795,7 +1795,7 @@ static int pl022_setup(struct spi_device *spi)
{
struct pl022_config_chip const *chip_info;
struct chip_data *chip;
- struct ssp_clock_params clk_freq;
+ struct ssp_clock_params clk_freq = {0, };
int status = 0;
struct pl022 *pl022 = spi_master_get_devdata(spi->master);
unsigned int bits = spi->bits_per_word;
diff --git a/drivers/spi/ath79_spi.c b/drivers/spi/ath79_spi.c
new file mode 100644
index 0000000..fcff810
--- /dev/null
+++ b/drivers/spi/ath79_spi.c
@@ -0,0 +1,292 @@
+/*
+ * SPI controller driver for the Atheros AR71XX/AR724X/AR913X SoCs
+ *
+ * Copyright (C) 2009-2011 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * This driver has been based on the spi-gpio.c:
+ * Copyright (C) 2006,2008 David Brownell
+ *
+ * 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/init.h>
+#include <linux/delay.h>
+#include <linux/spinlock.h>
+#include <linux/workqueue.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/spi_bitbang.h>
+#include <linux/bitops.h>
+#include <linux/gpio.h>
+
+#include <asm/mach-ath79/ar71xx_regs.h>
+#include <asm/mach-ath79/ath79_spi_platform.h>
+
+#define DRV_NAME "ath79-spi"
+
+struct ath79_spi {
+ struct spi_bitbang bitbang;
+ u32 ioc_base;
+ u32 reg_ctrl;
+ void __iomem *base;
+};
+
+static inline u32 ath79_spi_rr(struct ath79_spi *sp, unsigned reg)
+{
+ return ioread32(sp->base + reg);
+}
+
+static inline void ath79_spi_wr(struct ath79_spi *sp, unsigned reg, u32 val)
+{
+ iowrite32(val, sp->base + reg);
+}
+
+static inline struct ath79_spi *ath79_spidev_to_sp(struct spi_device *spi)
+{
+ return spi_master_get_devdata(spi->master);
+}
+
+static void ath79_spi_chipselect(struct spi_device *spi, int is_active)
+{
+ struct ath79_spi *sp = ath79_spidev_to_sp(spi);
+ int cs_high = (spi->mode & SPI_CS_HIGH) ? is_active : !is_active;
+
+ if (is_active) {
+ /* set initial clock polarity */
+ if (spi->mode & SPI_CPOL)
+ sp->ioc_base |= AR71XX_SPI_IOC_CLK;
+ else
+ sp->ioc_base &= ~AR71XX_SPI_IOC_CLK;
+
+ ath79_spi_wr(sp, AR71XX_SPI_REG_IOC, sp->ioc_base);
+ }
+
+ if (spi->chip_select) {
+ struct ath79_spi_controller_data *cdata = spi->controller_data;
+
+ /* SPI is normally active-low */
+ gpio_set_value(cdata->gpio, cs_high);
+ } else {
+ if (cs_high)
+ sp->ioc_base |= AR71XX_SPI_IOC_CS0;
+ else
+ sp->ioc_base &= ~AR71XX_SPI_IOC_CS0;
+
+ ath79_spi_wr(sp, AR71XX_SPI_REG_IOC, sp->ioc_base);
+ }
+
+}
+
+static int ath79_spi_setup_cs(struct spi_device *spi)
+{
+ struct ath79_spi *sp = ath79_spidev_to_sp(spi);
+ struct ath79_spi_controller_data *cdata;
+
+ cdata = spi->controller_data;
+ if (spi->chip_select && !cdata)
+ return -EINVAL;
+
+ /* enable GPIO mode */
+ ath79_spi_wr(sp, AR71XX_SPI_REG_FS, AR71XX_SPI_FS_GPIO);
+
+ /* save CTRL register */
+ sp->reg_ctrl = ath79_spi_rr(sp, AR71XX_SPI_REG_CTRL);
+ sp->ioc_base = ath79_spi_rr(sp, AR71XX_SPI_REG_IOC);
+
+ /* TODO: setup speed? */
+ ath79_spi_wr(sp, AR71XX_SPI_REG_CTRL, 0x43);
+
+ if (spi->chip_select) {
+ int status = 0;
+
+ status = gpio_request(cdata->gpio, dev_name(&spi->dev));
+ if (status)
+ return status;
+
+ status = gpio_direction_output(cdata->gpio,
+ spi->mode & SPI_CS_HIGH);
+ if (status) {
+ gpio_free(cdata->gpio);
+ return status;
+ }
+ } else {
+ if (spi->mode & SPI_CS_HIGH)
+ sp->ioc_base |= AR71XX_SPI_IOC_CS0;
+ else
+ sp->ioc_base &= ~AR71XX_SPI_IOC_CS0;
+ ath79_spi_wr(sp, AR71XX_SPI_REG_IOC, sp->ioc_base);
+ }
+
+ return 0;
+}
+
+static void ath79_spi_cleanup_cs(struct spi_device *spi)
+{
+ struct ath79_spi *sp = ath79_spidev_to_sp(spi);
+
+ if (spi->chip_select) {
+ struct ath79_spi_controller_data *cdata = spi->controller_data;
+ gpio_free(cdata->gpio);
+ }
+
+ /* restore CTRL register */
+ ath79_spi_wr(sp, AR71XX_SPI_REG_CTRL, sp->reg_ctrl);
+ /* disable GPIO mode */
+ ath79_spi_wr(sp, AR71XX_SPI_REG_FS, 0);
+}
+
+static int ath79_spi_setup(struct spi_device *spi)
+{
+ int status = 0;
+
+ if (spi->bits_per_word > 32)
+ return -EINVAL;
+
+ if (!spi->controller_state) {
+ status = ath79_spi_setup_cs(spi);
+ if (status)
+ return status;
+ }
+
+ status = spi_bitbang_setup(spi);
+ if (status && !spi->controller_state)
+ ath79_spi_cleanup_cs(spi);
+
+ return status;
+}
+
+static void ath79_spi_cleanup(struct spi_device *spi)
+{
+ ath79_spi_cleanup_cs(spi);
+ spi_bitbang_cleanup(spi);
+}
+
+static u32 ath79_spi_txrx_mode0(struct spi_device *spi, unsigned nsecs,
+ u32 word, u8 bits)
+{
+ struct ath79_spi *sp = ath79_spidev_to_sp(spi);
+ u32 ioc = sp->ioc_base;
+
+ /* clock starts at inactive polarity */
+ for (word <<= (32 - bits); likely(bits); bits--) {
+ u32 out;
+
+ if (word & (1 << 31))
+ out = ioc | AR71XX_SPI_IOC_DO;
+ else
+ out = ioc & ~AR71XX_SPI_IOC_DO;
+
+ /* setup MSB (to slave) on trailing edge */
+ ath79_spi_wr(sp, AR71XX_SPI_REG_IOC, out);
+ ath79_spi_wr(sp, AR71XX_SPI_REG_IOC, out | AR71XX_SPI_IOC_CLK);
+
+ word <<= 1;
+ }
+
+ return ath79_spi_rr(sp, AR71XX_SPI_REG_RDS);
+}
+
+static __devinit int ath79_spi_probe(struct platform_device *pdev)
+{
+ struct spi_master *master;
+ struct ath79_spi *sp;
+ struct ath79_spi_platform_data *pdata;
+ struct resource *r;
+ int ret;
+
+ master = spi_alloc_master(&pdev->dev, sizeof(*sp));
+ if (master == NULL) {
+ dev_err(&pdev->dev, "failed to allocate spi master\n");
+ return -ENOMEM;
+ }
+
+ sp = spi_master_get_devdata(master);
+ platform_set_drvdata(pdev, sp);
+
+ pdata = pdev->dev.platform_data;
+
+ master->setup = ath79_spi_setup;
+ master->cleanup = ath79_spi_cleanup;
+ if (pdata) {
+ master->bus_num = pdata->bus_num;
+ master->num_chipselect = pdata->num_chipselect;
+ } else {
+ master->bus_num = -1;
+ master->num_chipselect = 1;
+ }
+
+ sp->bitbang.master = spi_master_get(master);
+ sp->bitbang.chipselect = ath79_spi_chipselect;
+ sp->bitbang.txrx_word[SPI_MODE_0] = ath79_spi_txrx_mode0;
+ sp->bitbang.setup_transfer = spi_bitbang_setup_transfer;
+ sp->bitbang.flags = SPI_CS_HIGH;
+
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (r == NULL) {
+ ret = -ENOENT;
+ goto err_put_master;
+ }
+
+ sp->base = ioremap(r->start, r->end - r->start + 1);
+ if (!sp->base) {
+ ret = -ENXIO;
+ goto err_put_master;
+ }
+
+ ret = spi_bitbang_start(&sp->bitbang);
+ if (ret)
+ goto err_unmap;
+
+ return 0;
+
+err_unmap:
+ iounmap(sp->base);
+err_put_master:
+ platform_set_drvdata(pdev, NULL);
+ spi_master_put(sp->bitbang.master);
+
+ return ret;
+}
+
+static __devexit int ath79_spi_remove(struct platform_device *pdev)
+{
+ struct ath79_spi *sp = platform_get_drvdata(pdev);
+
+ spi_bitbang_stop(&sp->bitbang);
+ iounmap(sp->base);
+ platform_set_drvdata(pdev, NULL);
+ spi_master_put(sp->bitbang.master);
+
+ return 0;
+}
+
+static struct platform_driver ath79_spi_driver = {
+ .probe = ath79_spi_probe,
+ .remove = __devexit_p(ath79_spi_remove),
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ },
+};
+
+static __init int ath79_spi_init(void)
+{
+ return platform_driver_register(&ath79_spi_driver);
+}
+module_init(ath79_spi_init);
+
+static __exit void ath79_spi_exit(void)
+{
+ platform_driver_unregister(&ath79_spi_driver);
+}
+module_exit(ath79_spi_exit);
+
+MODULE_DESCRIPTION("SPI controller driver for Atheros AR71XX/AR724X/AR913X");
+MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/drivers/spi/dw_spi_mmio.c b/drivers/spi/dw_spi_mmio.c
index db35bd9..2fa012c1 100644
--- a/drivers/spi/dw_spi_mmio.c
+++ b/drivers/spi/dw_spi_mmio.c
@@ -9,6 +9,7 @@
*/
#include <linux/clk.h>
+#include <linux/err.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
@@ -68,8 +69,8 @@ static int __devinit dw_spi_mmio_probe(struct platform_device *pdev)
}
dwsmmio->clk = clk_get(&pdev->dev, NULL);
- if (!dwsmmio->clk) {
- ret = -ENODEV;
+ if (IS_ERR(dwsmmio->clk)) {
+ ret = PTR_ERR(dwsmmio->clk);
goto err_irq;
}
clk_enable(dwsmmio->clk);
diff --git a/drivers/spi/spi_imx.c b/drivers/spi/spi_imx.c
index 9469564..1cf9d5f 100644
--- a/drivers/spi/spi_imx.c
+++ b/drivers/spi/spi_imx.c
@@ -743,6 +743,12 @@ static struct platform_device_id spi_imx_devtype[] = {
.name = "imx51-ecspi",
.driver_data = SPI_IMX_VER_2_3,
}, {
+ .name = "imx53-cspi",
+ .driver_data = SPI_IMX_VER_0_7,
+ }, {
+ .name = "imx53-ecspi",
+ .driver_data = SPI_IMX_VER_2_3,
+ }, {
/* sentinel */
}
};
diff --git a/drivers/spi/spi_sh_msiof.c b/drivers/spi/spi_sh_msiof.c
index d93b667..56f60c8 100644
--- a/drivers/spi/spi_sh_msiof.c
+++ b/drivers/spi/spi_sh_msiof.c
@@ -635,7 +635,7 @@ static int sh_msiof_spi_remove(struct platform_device *pdev)
ret = spi_bitbang_stop(&p->bitbang);
if (!ret) {
pm_runtime_disable(&pdev->dev);
- free_irq(platform_get_irq(pdev, 0), sh_msiof_spi_irq);
+ free_irq(platform_get_irq(pdev, 0), p);
iounmap(p->mapbase);
clk_put(p->clk);
spi_master_put(p->bitbang.master);
diff --git a/drivers/spi/spi_tegra.c b/drivers/spi/spi_tegra.c
index bb7df02..891e590 100644
--- a/drivers/spi/spi_tegra.c
+++ b/drivers/spi/spi_tegra.c
@@ -513,7 +513,7 @@ static int __init spi_tegra_probe(struct platform_device *pdev)
}
tspi->clk = clk_get(&pdev->dev, NULL);
- if (IS_ERR_OR_NULL(tspi->clk)) {
+ if (IS_ERR(tspi->clk)) {
dev_err(&pdev->dev, "can not get clock\n");
ret = PTR_ERR(tspi->clk);
goto err2;
diff --git a/drivers/ssb/Kconfig b/drivers/ssb/Kconfig
index 2d8cc45..42cdaa9 100644
--- a/drivers/ssb/Kconfig
+++ b/drivers/ssb/Kconfig
@@ -82,7 +82,7 @@ config SSB_SDIOHOST
config SSB_SILENT
bool "No SSB kernel messages"
- depends on SSB && EMBEDDED
+ depends on SSB && EXPERT
help
This option turns off all Sonics Silicon Backplane printks.
Note that you won't be able to identify problems, once
diff --git a/drivers/ssb/scan.c b/drivers/ssb/scan.c
index 5a0985d..29884c0 100644
--- a/drivers/ssb/scan.c
+++ b/drivers/ssb/scan.c
@@ -420,6 +420,16 @@ int ssb_bus_scan(struct ssb_bus *bus,
bus->pcicore.dev = dev;
#endif /* CONFIG_SSB_DRIVER_PCICORE */
break;
+ case SSB_DEV_ETHERNET:
+ if (bus->bustype == SSB_BUSTYPE_PCI) {
+ if (bus->host_pci->vendor == PCI_VENDOR_ID_BROADCOM &&
+ (bus->host_pci->device & 0xFF00) == 0x4300) {
+ /* This is a dangling ethernet core on a
+ * wireless device. Ignore it. */
+ continue;
+ }
+ }
+ break;
default:
break;
}
diff --git a/drivers/staging/autofs/dirhash.c b/drivers/staging/autofs/dirhash.c
index d3f42c8..a08bd73 100644
--- a/drivers/staging/autofs/dirhash.c
+++ b/drivers/staging/autofs/dirhash.c
@@ -88,14 +88,13 @@ struct autofs_dir_ent *autofs_expire(struct super_block *sb,
}
path.mnt = mnt;
path_get(&path);
- if (!follow_down(&path)) {
+ if (!follow_down_one(&path)) {
path_put(&path);
DPRINTK(("autofs: not expirable\
(not a mounted directory): %s\n", ent->name));
continue;
}
- while (d_mountpoint(path.dentry) && follow_down(&path))
- ;
+ follow_down(&path, false); // TODO: need to check error
umount_ok = may_umount(path.mnt);
path_put(&path);
diff --git a/drivers/staging/bcm/Qos.c b/drivers/staging/bcm/Qos.c
index 8ce4536..feade94 100644
--- a/drivers/staging/bcm/Qos.c
+++ b/drivers/staging/bcm/Qos.c
@@ -359,12 +359,11 @@ static VOID PruneQueue(PMINI_ADAPTER Adapter, INT iIndex)
if(PacketToDrop)
{
- struct netdev_queue *txq = netdev_get_tx_queue(Adapter->dev, iIndex);
if (netif_msg_tx_err(Adapter))
pr_info(PFX "%s: tx queue %d overlimit\n",
Adapter->dev->name, iIndex);
- txq->tx_dropped++;
+ netstats->tx_dropped++;
DEQUEUEPACKET(Adapter->PackInfo[iIndex].FirstTxQueue,
Adapter->PackInfo[iIndex].LastTxQueue);
@@ -404,7 +403,7 @@ VOID flush_all_queues(PMINI_ADAPTER Adapter)
// down(&Adapter->data_packet_queue_lock);
for(iQIndex=LowPriority; iQIndex<HiPriority; iQIndex++)
{
- struct netdev_queue *txq = netdev_get_tx_queue(Adapter->dev, iQIndex);
+ struct net_device_stats *netstats = &Adapter->dev->stats;
spin_lock_bh(&Adapter->PackInfo[iQIndex].SFQueueLock);
while(Adapter->PackInfo[iQIndex].FirstTxQueue)
@@ -413,7 +412,7 @@ VOID flush_all_queues(PMINI_ADAPTER Adapter)
if(PacketToDrop)
{
uiTotalPacketLength = PacketToDrop->len;
- txq->tx_dropped++;
+ netstats->tx_dropped++;
}
else
uiTotalPacketLength = 0;
diff --git a/drivers/staging/bcm/Transmit.c b/drivers/staging/bcm/Transmit.c
index 0f70009..d5e4a74 100644
--- a/drivers/staging/bcm/Transmit.c
+++ b/drivers/staging/bcm/Transmit.c
@@ -157,11 +157,11 @@ INT SetupNextSend(PMINI_ADAPTER Adapter, struct sk_buff *Packet, USHORT Vcid)
}
else
{
- struct netdev_queue *txq = netdev_get_tx_queue(Adapter->dev, QueueIndex);
+ struct net_device_stats *netstats = &Adapter->dev->stats;
Adapter->PackInfo[QueueIndex].uiTotalTxBytes += Leader.PLength;
- txq->tx_bytes += Leader.PLength;
- ++txq->tx_packets;
+ netstats->tx_bytes += Leader.PLength;
+ ++netstats->tx_packets;
Adapter->PackInfo[QueueIndex].uiCurrentTokenCount -= Leader.PLength << 3;
Adapter->PackInfo[QueueIndex].uiSentBytes += (Packet->len);
diff --git a/drivers/staging/lirc/TODO.lirc_zilog b/drivers/staging/lirc/TODO.lirc_zilog
index 6aa312d..2d0263f 100644
--- a/drivers/staging/lirc/TODO.lirc_zilog
+++ b/drivers/staging/lirc/TODO.lirc_zilog
@@ -1,13 +1,37 @@
-The binding between hdpvr and lirc_zilog is currently disabled,
+1. Both ir-kbd-i2c and lirc_zilog provide support for RX events.
+The 'tx_only' lirc_zilog module parameter will allow ir-kbd-i2c
+and lirc_zilog to coexist in the kernel, if the user requires such a set-up.
+However the IR unit will not work well without coordination between the
+two modules. A shared mutex, for transceiver access locking, needs to be
+supplied by bridge drivers, in struct IR_i2_init_data, to both ir-kbd-i2c
+and lirc_zilog, before they will coexist usefully. This should be fixed
+before moving out of staging.
+
+2. References and locking need careful examination. For cx18 and ivtv PCI
+cards, which are not easily "hot unplugged", the imperfect state of reference
+counting and locking is acceptable if not correct. For USB connected units
+like HD PVR, PVR USB2, HVR-1900, and HVR1950, the likelyhood of an Ooops on
+unplug is probably great. Proper reference counting and locking needs to be
+implemented before this module is moved out of staging.
+
+3. The binding between hdpvr and lirc_zilog is currently disabled,
due to an OOPS reported a few years ago when both the hdpvr and cx18
drivers were loaded in his system. More details can be seen at:
http://www.mail-archive.com/linux-media@vger.kernel.org/msg09163.html
More tests need to be done, in order to fix the reported issue.
-There's a conflict between ir-kbd-i2c: Both provide support for RX events.
-Such conflict needs to be fixed, before moving it out of staging.
+4. In addition to providing a shared mutex for transceiver access
+locking, bridge drivers, if able, should provide a chip reset() callback
+to lirc_zilog via struct IR_i2c_init_data. cx18 and ivtv already have routines
+to perform Z8 chip resets via GPIO manipulations. This will allow lirc_zilog
+to bring the chip back to normal when it hangs, in the same places the
+original lirc_pvr150 driver code does. This is not strictly needed, so it
+is not required to move lirc_zilog out of staging.
+
+5. Both lirc_zilog and ir-kbd-i2c support the Zilog Z8 for IR, as programmed
+and installed on Hauppauge products. When working on either module, developers
+must consider at least the following bridge drivers which mention an IR Rx unit
+at address 0x71 (indicative of a Z8):
-The way I2C probe works, it will try to register the driver twice, one
-for RX and another for TX. The logic needs to be fixed to avoid such
-issue.
+ ivtv cx18 hdpvr pvrusb2 bt8xx cx88 saa7134
diff --git a/drivers/staging/lirc/lirc_imon.c b/drivers/staging/lirc/lirc_imon.c
index 0da6b95..235cab0 100644
--- a/drivers/staging/lirc/lirc_imon.c
+++ b/drivers/staging/lirc/lirc_imon.c
@@ -447,6 +447,7 @@ static ssize_t vfd_write(struct file *file, const char *buf,
exit:
mutex_unlock(&context->ctx_lock);
+ kfree(data_buf);
return (!retval) ? n_bytes : retval;
}
diff --git a/drivers/staging/lirc/lirc_it87.c b/drivers/staging/lirc/lirc_it87.c
index 929ae57..5938616 100644
--- a/drivers/staging/lirc/lirc_it87.c
+++ b/drivers/staging/lirc/lirc_it87.c
@@ -232,6 +232,7 @@ static ssize_t lirc_write(struct file *file, const char *buf,
i++;
}
terminate_send(tx_buf[i - 1]);
+ kfree(tx_buf);
return n;
}
diff --git a/drivers/staging/lirc/lirc_parallel.c b/drivers/staging/lirc/lirc_parallel.c
index dfd2c44..3a9c098 100644
--- a/drivers/staging/lirc/lirc_parallel.c
+++ b/drivers/staging/lirc/lirc_parallel.c
@@ -376,6 +376,7 @@ static ssize_t lirc_write(struct file *filep, const char *buf, size_t n,
unsigned long flags;
int counttimer;
int *wbuf;
+ ssize_t ret;
if (!is_claimed)
return -EBUSY;
@@ -393,8 +394,10 @@ static ssize_t lirc_write(struct file *filep, const char *buf, size_t n,
if (timer == 0) {
/* try again if device is ready */
timer = init_lirc_timer();
- if (timer == 0)
- return -EIO;
+ if (timer == 0) {
+ ret = -EIO;
+ goto out;
+ }
}
/* adjust values from usecs */
@@ -420,7 +423,8 @@ static ssize_t lirc_write(struct file *filep, const char *buf, size_t n,
if (check_pselecd && (in(1) & LP_PSELECD)) {
lirc_off();
local_irq_restore(flags);
- return -EIO;
+ ret = -EIO;
+ goto out;
}
} while (counttimer < wbuf[i]);
i++;
@@ -436,7 +440,8 @@ static ssize_t lirc_write(struct file *filep, const char *buf, size_t n,
level = newlevel;
if (check_pselecd && (in(1) & LP_PSELECD)) {
local_irq_restore(flags);
- return -EIO;
+ ret = -EIO;
+ goto out;
}
} while (counttimer < wbuf[i]);
i++;
@@ -445,7 +450,11 @@ static ssize_t lirc_write(struct file *filep, const char *buf, size_t n,
#else
/* place code that handles write without external timer here */
#endif
- return n;
+ ret = n;
+out:
+ kfree(wbuf);
+
+ return ret;
}
static unsigned int lirc_poll(struct file *file, poll_table *wait)
diff --git a/drivers/staging/lirc/lirc_sasem.c b/drivers/staging/lirc/lirc_sasem.c
index 998485e..925eabe 100644
--- a/drivers/staging/lirc/lirc_sasem.c
+++ b/drivers/staging/lirc/lirc_sasem.c
@@ -448,6 +448,7 @@ static ssize_t vfd_write(struct file *file, const char *buf,
exit:
mutex_unlock(&context->ctx_lock);
+ kfree(data_buf);
return (!retval) ? n_bytes : retval;
}
diff --git a/drivers/staging/lirc/lirc_serial.c b/drivers/staging/lirc/lirc_serial.c
index 9bcf149..1c3099b 100644
--- a/drivers/staging/lirc/lirc_serial.c
+++ b/drivers/staging/lirc/lirc_serial.c
@@ -966,7 +966,7 @@ static ssize_t lirc_write(struct file *file, const char *buf,
if (n % sizeof(int) || count % 2 == 0)
return -EINVAL;
wbuf = memdup_user(buf, n);
- if (PTR_ERR(wbuf))
+ if (IS_ERR(wbuf))
return PTR_ERR(wbuf);
spin_lock_irqsave(&hardware[type].lock, flags);
if (type == LIRC_IRDEO) {
@@ -981,6 +981,7 @@ static ssize_t lirc_write(struct file *file, const char *buf,
}
off();
spin_unlock_irqrestore(&hardware[type].lock, flags);
+ kfree(wbuf);
return n;
}
diff --git a/drivers/staging/lirc/lirc_sir.c b/drivers/staging/lirc/lirc_sir.c
index c553ab6..76be7b8 100644
--- a/drivers/staging/lirc/lirc_sir.c
+++ b/drivers/staging/lirc/lirc_sir.c
@@ -330,6 +330,7 @@ static ssize_t lirc_write(struct file *file, const char *buf, size_t n,
/* enable receiver */
Ser2UTCR3 = UTCR3_RXE|UTCR3_RIE;
#endif
+ kfree(tx_buf);
return count;
}
diff --git a/drivers/staging/lirc/lirc_zilog.c b/drivers/staging/lirc/lirc_zilog.c
index ad29bb1..3fe5f41 100644
--- a/drivers/staging/lirc/lirc_zilog.c
+++ b/drivers/staging/lirc/lirc_zilog.c
@@ -20,6 +20,9 @@
*
* parts are cut&pasted from the lirc_i2c.c driver
*
+ * Numerous changes updating lirc_zilog.c in kernel 2.6.38 and later are
+ * Copyright (C) 2011 Andy Walls <awalls@md.metrocast.net>
+ *
* 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
@@ -60,38 +63,44 @@
#include <media/lirc_dev.h>
#include <media/lirc.h>
-struct IR {
- struct lirc_driver l;
-
- /* Device info */
- struct mutex ir_lock;
- int open;
- bool is_hdpvr;
-
+struct IR_rx {
/* RX device */
- struct i2c_client c_rx;
- int have_rx;
+ struct i2c_client *c;
/* RX device buffer & lock */
struct lirc_buffer buf;
struct mutex buf_lock;
/* RX polling thread data */
- struct completion *t_notify;
- struct completion *t_notify2;
- int shutdown;
struct task_struct *task;
/* RX read data */
unsigned char b[3];
+ bool hdpvr_data_fmt;
+};
+struct IR_tx {
/* TX device */
- struct i2c_client c_tx;
+ struct i2c_client *c;
+
+ /* TX additional actions needed */
int need_boot;
- int have_tx;
+ bool post_tx_ready_poll;
+};
+
+struct IR {
+ struct lirc_driver l;
+
+ struct mutex ir_lock;
+ int open;
+
+ struct i2c_adapter *adapter;
+ struct IR_rx *rx;
+ struct IR_tx *tx;
};
/* Minor -> data mapping */
+static struct mutex ir_devices_lock;
static struct IR *ir_devices[MAX_IRCTL_DEVICES];
/* Block size for IR transmitter */
@@ -124,14 +133,11 @@ static struct mutex tx_data_lock;
#define zilog_notify(s, args...) printk(KERN_NOTICE KBUILD_MODNAME ": " s, \
## args)
#define zilog_error(s, args...) printk(KERN_ERR KBUILD_MODNAME ": " s, ## args)
-
-#define ZILOG_HAUPPAUGE_IR_RX_NAME "Zilog/Hauppauge IR RX"
-#define ZILOG_HAUPPAUGE_IR_TX_NAME "Zilog/Hauppauge IR TX"
+#define zilog_info(s, args...) printk(KERN_INFO KBUILD_MODNAME ": " s, ## args)
/* module parameters */
static int debug; /* debug output */
-static int disable_rx; /* disable RX device */
-static int disable_tx; /* disable TX device */
+static int tx_only; /* only handle the IR Tx function */
static int minor = -1; /* minor number */
#define dprintk(fmt, args...) \
@@ -150,8 +156,12 @@ static int add_to_buf(struct IR *ir)
int ret;
int failures = 0;
unsigned char sendbuf[1] = { 0 };
+ struct IR_rx *rx = ir->rx;
- if (lirc_buffer_full(&ir->buf)) {
+ if (rx == NULL)
+ return -ENXIO;
+
+ if (lirc_buffer_full(&rx->buf)) {
dprintk("buffer overflow\n");
return -EOVERFLOW;
}
@@ -161,17 +171,25 @@ static int add_to_buf(struct IR *ir)
* data and we have space
*/
do {
+ if (kthread_should_stop())
+ return -ENODATA;
+
/*
* Lock i2c bus for the duration. RX/TX chips interfere so
* this is worth it
*/
mutex_lock(&ir->ir_lock);
+ if (kthread_should_stop()) {
+ mutex_unlock(&ir->ir_lock);
+ return -ENODATA;
+ }
+
/*
* Send random "poll command" (?) Windows driver does this
* and it is a good point to detect chip failure.
*/
- ret = i2c_master_send(&ir->c_rx, sendbuf, 1);
+ ret = i2c_master_send(rx->c, sendbuf, 1);
if (ret != 1) {
zilog_error("i2c_master_send failed with %d\n", ret);
if (failures >= 3) {
@@ -186,45 +204,53 @@ static int add_to_buf(struct IR *ir)
"trying reset\n");
set_current_state(TASK_UNINTERRUPTIBLE);
+ if (kthread_should_stop()) {
+ mutex_unlock(&ir->ir_lock);
+ return -ENODATA;
+ }
schedule_timeout((100 * HZ + 999) / 1000);
- ir->need_boot = 1;
+ ir->tx->need_boot = 1;
++failures;
mutex_unlock(&ir->ir_lock);
continue;
}
- ret = i2c_master_recv(&ir->c_rx, keybuf, sizeof(keybuf));
+ if (kthread_should_stop()) {
+ mutex_unlock(&ir->ir_lock);
+ return -ENODATA;
+ }
+ ret = i2c_master_recv(rx->c, keybuf, sizeof(keybuf));
mutex_unlock(&ir->ir_lock);
if (ret != sizeof(keybuf)) {
zilog_error("i2c_master_recv failed with %d -- "
"keeping last read buffer\n", ret);
} else {
- ir->b[0] = keybuf[3];
- ir->b[1] = keybuf[4];
- ir->b[2] = keybuf[5];
- dprintk("key (0x%02x/0x%02x)\n", ir->b[0], ir->b[1]);
+ rx->b[0] = keybuf[3];
+ rx->b[1] = keybuf[4];
+ rx->b[2] = keybuf[5];
+ dprintk("key (0x%02x/0x%02x)\n", rx->b[0], rx->b[1]);
}
/* key pressed ? */
- if (ir->is_hdpvr) {
+ if (rx->hdpvr_data_fmt) {
if (got_data && (keybuf[0] == 0x80))
return 0;
else if (got_data && (keybuf[0] == 0x00))
return -ENODATA;
- } else if ((ir->b[0] & 0x80) == 0)
+ } else if ((rx->b[0] & 0x80) == 0)
return got_data ? 0 : -ENODATA;
/* look what we have */
- code = (((__u16)ir->b[0] & 0x7f) << 6) | (ir->b[1] >> 2);
+ code = (((__u16)rx->b[0] & 0x7f) << 6) | (rx->b[1] >> 2);
codes[0] = (code >> 8) & 0xff;
codes[1] = code & 0xff;
/* return it */
- lirc_buffer_write(&ir->buf, codes);
+ lirc_buffer_write(&rx->buf, codes);
++got_data;
- } while (!lirc_buffer_full(&ir->buf));
+ } while (!lirc_buffer_full(&rx->buf));
return 0;
}
@@ -242,46 +268,35 @@ static int add_to_buf(struct IR *ir)
static int lirc_thread(void *arg)
{
struct IR *ir = arg;
-
- if (ir->t_notify != NULL)
- complete(ir->t_notify);
+ struct IR_rx *rx = ir->rx;
dprintk("poll thread started\n");
- do {
- if (ir->open) {
- set_current_state(TASK_INTERRUPTIBLE);
+ while (!kthread_should_stop()) {
+ set_current_state(TASK_INTERRUPTIBLE);
- /*
- * This is ~113*2 + 24 + jitter (2*repeat gap +
- * code length). We use this interval as the chip
- * resets every time you poll it (bad!). This is
- * therefore just sufficient to catch all of the
- * button presses. It makes the remote much more
- * responsive. You can see the difference by
- * running irw and holding down a button. With
- * 100ms, the old polling interval, you'll notice
- * breaks in the repeat sequence corresponding to
- * lost keypresses.
- */
- schedule_timeout((260 * HZ) / 1000);
- if (ir->shutdown)
- break;
- if (!add_to_buf(ir))
- wake_up_interruptible(&ir->buf.wait_poll);
- } else {
- /* if device not opened so we can sleep half a second */
- set_current_state(TASK_INTERRUPTIBLE);
+ /* if device not opened, we can sleep half a second */
+ if (!ir->open) {
schedule_timeout(HZ/2);
+ continue;
}
- } while (!ir->shutdown);
-
- if (ir->t_notify2 != NULL)
- wait_for_completion(ir->t_notify2);
- ir->task = NULL;
- if (ir->t_notify != NULL)
- complete(ir->t_notify);
+ /*
+ * This is ~113*2 + 24 + jitter (2*repeat gap + code length).
+ * We use this interval as the chip resets every time you poll
+ * it (bad!). This is therefore just sufficient to catch all
+ * of the button presses. It makes the remote much more
+ * responsive. You can see the difference by running irw and
+ * holding down a button. With 100ms, the old polling
+ * interval, you'll notice breaks in the repeat sequence
+ * corresponding to lost keypresses.
+ */
+ schedule_timeout((260 * HZ) / 1000);
+ if (kthread_should_stop())
+ break;
+ if (!add_to_buf(ir))
+ wake_up_interruptible(&rx->buf.wait_poll);
+ }
dprintk("poll thread ended\n");
return 0;
@@ -299,10 +314,10 @@ static int set_use_inc(void *data)
* this is completely broken code. lirc_unregister_driver()
* must be possible even when the device is open
*/
- if (ir->c_rx.addr)
- i2c_use_client(&ir->c_rx);
- if (ir->c_tx.addr)
- i2c_use_client(&ir->c_tx);
+ if (ir->rx != NULL)
+ i2c_use_client(ir->rx->c);
+ if (ir->tx != NULL)
+ i2c_use_client(ir->tx->c);
return 0;
}
@@ -311,10 +326,10 @@ static void set_use_dec(void *data)
{
struct IR *ir = data;
- if (ir->c_rx.addr)
- i2c_release_client(&ir->c_rx);
- if (ir->c_tx.addr)
- i2c_release_client(&ir->c_tx);
+ if (ir->rx)
+ i2c_release_client(ir->rx->c);
+ if (ir->tx)
+ i2c_release_client(ir->tx->c);
if (ir->l.owner != NULL)
module_put(ir->l.owner);
}
@@ -453,7 +468,7 @@ corrupt:
}
/* send a block of data to the IR TX device */
-static int send_data_block(struct IR *ir, unsigned char *data_block)
+static int send_data_block(struct IR_tx *tx, unsigned char *data_block)
{
int i, j, ret;
unsigned char buf[5];
@@ -467,7 +482,7 @@ static int send_data_block(struct IR *ir, unsigned char *data_block)
buf[1 + j] = data_block[i + j];
dprintk("%02x %02x %02x %02x %02x",
buf[0], buf[1], buf[2], buf[3], buf[4]);
- ret = i2c_master_send(&ir->c_tx, buf, tosend + 1);
+ ret = i2c_master_send(tx->c, buf, tosend + 1);
if (ret != tosend + 1) {
zilog_error("i2c_master_send failed with %d\n", ret);
return ret < 0 ? ret : -EFAULT;
@@ -478,32 +493,32 @@ static int send_data_block(struct IR *ir, unsigned char *data_block)
}
/* send boot data to the IR TX device */
-static int send_boot_data(struct IR *ir)
+static int send_boot_data(struct IR_tx *tx)
{
int ret;
unsigned char buf[4];
/* send the boot block */
- ret = send_data_block(ir, tx_data->boot_data);
+ ret = send_data_block(tx, tx_data->boot_data);
if (ret != 0)
return ret;
/* kick it off? */
buf[0] = 0x00;
buf[1] = 0x20;
- ret = i2c_master_send(&ir->c_tx, buf, 2);
+ ret = i2c_master_send(tx->c, buf, 2);
if (ret != 2) {
zilog_error("i2c_master_send failed with %d\n", ret);
return ret < 0 ? ret : -EFAULT;
}
- ret = i2c_master_send(&ir->c_tx, buf, 1);
+ ret = i2c_master_send(tx->c, buf, 1);
if (ret != 1) {
zilog_error("i2c_master_send failed with %d\n", ret);
return ret < 0 ? ret : -EFAULT;
}
/* Here comes the firmware version... (hopefully) */
- ret = i2c_master_recv(&ir->c_tx, buf, 4);
+ ret = i2c_master_recv(tx->c, buf, 4);
if (ret != 4) {
zilog_error("i2c_master_recv failed with %d\n", ret);
return 0;
@@ -543,7 +558,7 @@ static void fw_unload(void)
}
/* load "firmware" for the IR TX device */
-static int fw_load(struct IR *ir)
+static int fw_load(struct IR_tx *tx)
{
int ret;
unsigned int i;
@@ -558,7 +573,7 @@ static int fw_load(struct IR *ir)
}
/* Request codeset data file */
- ret = request_firmware(&fw_entry, "haup-ir-blaster.bin", &ir->c_tx.dev);
+ ret = request_firmware(&fw_entry, "haup-ir-blaster.bin", &tx->c->dev);
if (ret != 0) {
zilog_error("firmware haup-ir-blaster.bin not available "
"(%d)\n", ret);
@@ -685,20 +700,20 @@ out:
}
/* initialise the IR TX device */
-static int tx_init(struct IR *ir)
+static int tx_init(struct IR_tx *tx)
{
int ret;
/* Load 'firmware' */
- ret = fw_load(ir);
+ ret = fw_load(tx);
if (ret != 0)
return ret;
/* Send boot block */
- ret = send_boot_data(ir);
+ ret = send_boot_data(tx);
if (ret != 0)
return ret;
- ir->need_boot = 0;
+ tx->need_boot = 0;
/* Looks good */
return 0;
@@ -714,20 +729,20 @@ static loff_t lseek(struct file *filep, loff_t offset, int orig)
static ssize_t read(struct file *filep, char *outbuf, size_t n, loff_t *ppos)
{
struct IR *ir = filep->private_data;
- unsigned char buf[ir->buf.chunk_size];
+ struct IR_rx *rx = ir->rx;
int ret = 0, written = 0;
DECLARE_WAITQUEUE(wait, current);
dprintk("read called\n");
- if (ir->c_rx.addr == 0)
+ if (rx == NULL)
return -ENODEV;
- if (mutex_lock_interruptible(&ir->buf_lock))
+ if (mutex_lock_interruptible(&rx->buf_lock))
return -ERESTARTSYS;
- if (n % ir->buf.chunk_size) {
+ if (n % rx->buf.chunk_size) {
dprintk("read result = -EINVAL\n");
- mutex_unlock(&ir->buf_lock);
+ mutex_unlock(&rx->buf_lock);
return -EINVAL;
}
@@ -736,7 +751,7 @@ static ssize_t read(struct file *filep, char *outbuf, size_t n, loff_t *ppos)
* to avoid losing scan code (in case when queue is awaken somewhere
* between while condition checking and scheduling)
*/
- add_wait_queue(&ir->buf.wait_poll, &wait);
+ add_wait_queue(&rx->buf.wait_poll, &wait);
set_current_state(TASK_INTERRUPTIBLE);
/*
@@ -744,7 +759,7 @@ static ssize_t read(struct file *filep, char *outbuf, size_t n, loff_t *ppos)
* mode and 'copy_to_user' is happy, wait for data.
*/
while (written < n && ret == 0) {
- if (lirc_buffer_empty(&ir->buf)) {
+ if (lirc_buffer_empty(&rx->buf)) {
/*
* According to the read(2) man page, 'written' can be
* returned as less than 'n', instead of blocking
@@ -764,16 +779,17 @@ static ssize_t read(struct file *filep, char *outbuf, size_t n, loff_t *ppos)
schedule();
set_current_state(TASK_INTERRUPTIBLE);
} else {
- lirc_buffer_read(&ir->buf, buf);
+ unsigned char buf[rx->buf.chunk_size];
+ lirc_buffer_read(&rx->buf, buf);
ret = copy_to_user((void *)outbuf+written, buf,
- ir->buf.chunk_size);
- written += ir->buf.chunk_size;
+ rx->buf.chunk_size);
+ written += rx->buf.chunk_size;
}
}
- remove_wait_queue(&ir->buf.wait_poll, &wait);
+ remove_wait_queue(&rx->buf.wait_poll, &wait);
set_current_state(TASK_RUNNING);
- mutex_unlock(&ir->buf_lock);
+ mutex_unlock(&rx->buf_lock);
dprintk("read result = %s (%d)\n",
ret ? "-EFAULT" : "OK", ret);
@@ -782,7 +798,7 @@ static ssize_t read(struct file *filep, char *outbuf, size_t n, loff_t *ppos)
}
/* send a keypress to the IR TX device */
-static int send_code(struct IR *ir, unsigned int code, unsigned int key)
+static int send_code(struct IR_tx *tx, unsigned int code, unsigned int key)
{
unsigned char data_block[TX_BLOCK_SIZE];
unsigned char buf[2];
@@ -799,26 +815,26 @@ static int send_code(struct IR *ir, unsigned int code, unsigned int key)
return ret;
/* Send the data block */
- ret = send_data_block(ir, data_block);
+ ret = send_data_block(tx, data_block);
if (ret != 0)
return ret;
/* Send data block length? */
buf[0] = 0x00;
buf[1] = 0x40;
- ret = i2c_master_send(&ir->c_tx, buf, 2);
+ ret = i2c_master_send(tx->c, buf, 2);
if (ret != 2) {
zilog_error("i2c_master_send failed with %d\n", ret);
return ret < 0 ? ret : -EFAULT;
}
- ret = i2c_master_send(&ir->c_tx, buf, 1);
+ ret = i2c_master_send(tx->c, buf, 1);
if (ret != 1) {
zilog_error("i2c_master_send failed with %d\n", ret);
return ret < 0 ? ret : -EFAULT;
}
/* Send finished download? */
- ret = i2c_master_recv(&ir->c_tx, buf, 1);
+ ret = i2c_master_recv(tx->c, buf, 1);
if (ret != 1) {
zilog_error("i2c_master_recv failed with %d\n", ret);
return ret < 0 ? ret : -EFAULT;
@@ -832,7 +848,7 @@ static int send_code(struct IR *ir, unsigned int code, unsigned int key)
/* Send prepare command? */
buf[0] = 0x00;
buf[1] = 0x80;
- ret = i2c_master_send(&ir->c_tx, buf, 2);
+ ret = i2c_master_send(tx->c, buf, 2);
if (ret != 2) {
zilog_error("i2c_master_send failed with %d\n", ret);
return ret < 0 ? ret : -EFAULT;
@@ -843,7 +859,7 @@ static int send_code(struct IR *ir, unsigned int code, unsigned int key)
* last i2c_master_recv always fails with a -5, so for now, we're
* going to skip this whole mess and say we're done on the HD PVR
*/
- if (ir->is_hdpvr) {
+ if (!tx->post_tx_ready_poll) {
dprintk("sent code %u, key %u\n", code, key);
return 0;
}
@@ -857,7 +873,7 @@ static int send_code(struct IR *ir, unsigned int code, unsigned int key)
for (i = 0; i < 20; ++i) {
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout((50 * HZ + 999) / 1000);
- ret = i2c_master_send(&ir->c_tx, buf, 1);
+ ret = i2c_master_send(tx->c, buf, 1);
if (ret == 1)
break;
dprintk("NAK expected: i2c_master_send "
@@ -870,7 +886,7 @@ static int send_code(struct IR *ir, unsigned int code, unsigned int key)
}
/* Seems to be an 'ok' response */
- i = i2c_master_recv(&ir->c_tx, buf, 1);
+ i = i2c_master_recv(tx->c, buf, 1);
if (i != 1) {
zilog_error("i2c_master_recv failed with %d\n", ret);
return -EFAULT;
@@ -895,10 +911,11 @@ static ssize_t write(struct file *filep, const char *buf, size_t n,
loff_t *ppos)
{
struct IR *ir = filep->private_data;
+ struct IR_tx *tx = ir->tx;
size_t i;
int failures = 0;
- if (ir->c_tx.addr == 0)
+ if (tx == NULL)
return -ENODEV;
/* Validate user parameters */
@@ -919,15 +936,15 @@ static ssize_t write(struct file *filep, const char *buf, size_t n,
}
/* Send boot data first if required */
- if (ir->need_boot == 1) {
- ret = send_boot_data(ir);
+ if (tx->need_boot == 1) {
+ ret = send_boot_data(tx);
if (ret == 0)
- ir->need_boot = 0;
+ tx->need_boot = 0;
}
/* Send the code */
if (ret == 0) {
- ret = send_code(ir, (unsigned)command >> 16,
+ ret = send_code(tx, (unsigned)command >> 16,
(unsigned)command & 0xFFFF);
if (ret == -EPROTO) {
mutex_unlock(&ir->ir_lock);
@@ -952,7 +969,7 @@ static ssize_t write(struct file *filep, const char *buf, size_t n,
}
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout((100 * HZ + 999) / 1000);
- ir->need_boot = 1;
+ tx->need_boot = 1;
++failures;
} else
i += sizeof(int);
@@ -969,22 +986,23 @@ static ssize_t write(struct file *filep, const char *buf, size_t n,
static unsigned int poll(struct file *filep, poll_table *wait)
{
struct IR *ir = filep->private_data;
+ struct IR_rx *rx = ir->rx;
unsigned int ret;
dprintk("poll called\n");
- if (ir->c_rx.addr == 0)
+ if (rx == NULL)
return -ENODEV;
- mutex_lock(&ir->buf_lock);
+ mutex_lock(&rx->buf_lock);
- poll_wait(filep, &ir->buf.wait_poll, wait);
+ poll_wait(filep, &rx->buf.wait_poll, wait);
dprintk("poll result = %s\n",
- lirc_buffer_empty(&ir->buf) ? "0" : "POLLIN|POLLRDNORM");
+ lirc_buffer_empty(&rx->buf) ? "0" : "POLLIN|POLLRDNORM");
- ret = lirc_buffer_empty(&ir->buf) ? 0 : (POLLIN|POLLRDNORM);
+ ret = lirc_buffer_empty(&rx->buf) ? 0 : (POLLIN|POLLRDNORM);
- mutex_unlock(&ir->buf_lock);
+ mutex_unlock(&rx->buf_lock);
return ret;
}
@@ -994,10 +1012,9 @@ static long ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
int result;
unsigned long mode, features = 0;
- if (ir->c_rx.addr != 0)
+ features |= LIRC_CAN_SEND_PULSE;
+ if (ir->rx != NULL)
features |= LIRC_CAN_REC_LIRCCODE;
- if (ir->c_tx.addr != 0)
- features |= LIRC_CAN_SEND_PULSE;
switch (cmd) {
case LIRC_GET_LENGTH:
@@ -1024,15 +1041,9 @@ static long ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
result = -EINVAL;
break;
case LIRC_GET_SEND_MODE:
- if (!(features&LIRC_CAN_SEND_MASK))
- return -ENOSYS;
-
result = put_user(LIRC_MODE_PULSE, (unsigned long *) arg);
break;
case LIRC_SET_SEND_MODE:
- if (!(features&LIRC_CAN_SEND_MASK))
- return -ENOSYS;
-
result = get_user(mode, (unsigned long *) arg);
if (!result && mode != LIRC_MODE_PULSE)
return -EINVAL;
@@ -1043,6 +1054,15 @@ static long ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
return result;
}
+/* ir_devices_lock must be held */
+static struct IR *find_ir_device_by_minor(unsigned int minor)
+{
+ if (minor >= MAX_IRCTL_DEVICES)
+ return NULL;
+
+ return ir_devices[minor];
+}
+
/*
* Open the IR device. Get hold of our IR structure and
* stash it in private_data for the file
@@ -1051,15 +1071,15 @@ static int open(struct inode *node, struct file *filep)
{
struct IR *ir;
int ret;
+ unsigned int minor = MINOR(node->i_rdev);
/* find our IR struct */
- unsigned minor = MINOR(node->i_rdev);
- if (minor >= MAX_IRCTL_DEVICES) {
- dprintk("minor %d: open result = -ENODEV\n",
- minor);
+ mutex_lock(&ir_devices_lock);
+ ir = find_ir_device_by_minor(minor);
+ mutex_unlock(&ir_devices_lock);
+
+ if (ir == NULL)
return -ENODEV;
- }
- ir = ir_devices[minor];
/* increment in use count */
mutex_lock(&ir->ir_lock);
@@ -1106,7 +1126,6 @@ static struct lirc_driver lirc_template = {
static int ir_remove(struct i2c_client *client);
static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id);
-static int ir_command(struct i2c_client *client, unsigned int cmd, void *arg);
#define ID_FLAG_TX 0x01
#define ID_FLAG_HDPVR 0x02
@@ -1126,7 +1145,6 @@ static struct i2c_driver driver = {
},
.probe = ir_probe,
.remove = ir_remove,
- .command = ir_command,
.id_table = ir_transceiver_id,
};
@@ -1144,214 +1162,253 @@ static const struct file_operations lirc_fops = {
.release = close
};
-static int ir_remove(struct i2c_client *client)
+static void destroy_rx_kthread(struct IR_rx *rx)
{
- struct IR *ir = i2c_get_clientdata(client);
+ /* end up polling thread */
+ if (rx != NULL && !IS_ERR_OR_NULL(rx->task)) {
+ kthread_stop(rx->task);
+ rx->task = NULL;
+ }
+}
- mutex_lock(&ir->ir_lock);
+/* ir_devices_lock must be held */
+static int add_ir_device(struct IR *ir)
+{
+ int i;
- if (ir->have_rx || ir->have_tx) {
- DECLARE_COMPLETION(tn);
- DECLARE_COMPLETION(tn2);
-
- /* end up polling thread */
- if (ir->task && !IS_ERR(ir->task)) {
- ir->t_notify = &tn;
- ir->t_notify2 = &tn2;
- ir->shutdown = 1;
- wake_up_process(ir->task);
- complete(&tn2);
- wait_for_completion(&tn);
- ir->t_notify = NULL;
- ir->t_notify2 = NULL;
+ for (i = 0; i < MAX_IRCTL_DEVICES; i++)
+ if (ir_devices[i] == NULL) {
+ ir_devices[i] = ir;
+ break;
}
- } else {
- mutex_unlock(&ir->ir_lock);
- zilog_error("%s: detached from something we didn't "
- "attach to\n", __func__);
- return -ENODEV;
+ return i == MAX_IRCTL_DEVICES ? -ENOMEM : i;
+}
+
+/* ir_devices_lock must be held */
+static void del_ir_device(struct IR *ir)
+{
+ int i;
+
+ for (i = 0; i < MAX_IRCTL_DEVICES; i++)
+ if (ir_devices[i] == ir) {
+ ir_devices[i] = NULL;
+ break;
+ }
+}
+
+static int ir_remove(struct i2c_client *client)
+{
+ struct IR *ir = i2c_get_clientdata(client);
+
+ mutex_lock(&ir_devices_lock);
+
+ if (ir == NULL) {
+ /* We destroyed everything when the first client came through */
+ mutex_unlock(&ir_devices_lock);
+ return 0;
}
- /* unregister lirc driver */
- if (ir->l.minor >= 0 && ir->l.minor < MAX_IRCTL_DEVICES) {
- lirc_unregister_driver(ir->l.minor);
- ir_devices[ir->l.minor] = NULL;
+ /* Good-bye LIRC */
+ lirc_unregister_driver(ir->l.minor);
+
+ /* Good-bye Rx */
+ destroy_rx_kthread(ir->rx);
+ if (ir->rx != NULL) {
+ if (ir->rx->buf.fifo_initialized)
+ lirc_buffer_free(&ir->rx->buf);
+ i2c_set_clientdata(ir->rx->c, NULL);
+ kfree(ir->rx);
}
- /* free memory */
- lirc_buffer_free(&ir->buf);
- mutex_unlock(&ir->ir_lock);
+ /* Good-bye Tx */
+ i2c_set_clientdata(ir->tx->c, NULL);
+ kfree(ir->tx);
+
+ /* Good-bye IR */
+ del_ir_device(ir);
kfree(ir);
+ mutex_unlock(&ir_devices_lock);
return 0;
}
-static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
+
+/* ir_devices_lock must be held */
+static struct IR *find_ir_device_by_adapter(struct i2c_adapter *adapter)
{
+ int i;
struct IR *ir = NULL;
+
+ for (i = 0; i < MAX_IRCTL_DEVICES; i++)
+ if (ir_devices[i] != NULL &&
+ ir_devices[i]->adapter == adapter) {
+ ir = ir_devices[i];
+ break;
+ }
+
+ return ir;
+}
+
+static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
+{
+ struct IR *ir;
struct i2c_adapter *adap = client->adapter;
- char buf;
int ret;
- int have_rx = 0, have_tx = 0;
+ bool tx_probe = false;
- dprintk("%s: adapter name (%s) nr %d, i2c_device_id name (%s), "
- "client addr=0x%02x\n",
- __func__, adap->name, adap->nr, id->name, client->addr);
+ dprintk("%s: %s on i2c-%d (%s), client addr=0x%02x\n",
+ __func__, id->name, adap->nr, adap->name, client->addr);
/*
- * FIXME - This probe function probes both the Tx and Rx
- * addresses of the IR microcontroller.
- *
- * However, the I2C subsystem is passing along one I2C client at a
- * time, based on matches to the ir_transceiver_id[] table above.
- * The expectation is that each i2c_client address will be probed
- * individually by drivers so the I2C subsystem can mark all client
- * addresses as claimed or not.
- *
- * This probe routine causes only one of the client addresses, TX or RX,
- * to be claimed. This will cause a problem if the I2C subsystem is
- * subsequently triggered to probe unclaimed clients again.
+ * The IR receiver is at i2c address 0x71.
+ * The IR transmitter is at i2c address 0x70.
*/
- /*
- * The external IR receiver is at i2c address 0x71.
- * The IR transmitter is at 0x70.
- */
- client->addr = 0x70;
- if (!disable_tx) {
- if (i2c_master_recv(client, &buf, 1) == 1)
- have_tx = 1;
- dprintk("probe 0x70 @ %s: %s\n",
- adap->name, have_tx ? "success" : "failed");
- }
+ if (id->driver_data & ID_FLAG_TX)
+ tx_probe = true;
+ else if (tx_only) /* module option */
+ return -ENXIO;
- if (!disable_rx) {
- client->addr = 0x71;
- if (i2c_master_recv(client, &buf, 1) == 1)
- have_rx = 1;
- dprintk("probe 0x71 @ %s: %s\n",
- adap->name, have_rx ? "success" : "failed");
- }
+ zilog_info("probing IR %s on %s (i2c-%d)\n",
+ tx_probe ? "Tx" : "Rx", adap->name, adap->nr);
- if (!(have_rx || have_tx)) {
- zilog_error("%s: no devices found\n", adap->name);
- goto out_nodev;
- }
+ mutex_lock(&ir_devices_lock);
- printk(KERN_INFO "lirc_zilog: chip found with %s\n",
- have_rx && have_tx ? "RX and TX" :
- have_rx ? "RX only" : "TX only");
+ /* Use a single struct IR instance for both the Rx and Tx functions */
+ ir = find_ir_device_by_adapter(adap);
+ if (ir == NULL) {
+ ir = kzalloc(sizeof(struct IR), GFP_KERNEL);
+ if (ir == NULL) {
+ ret = -ENOMEM;
+ goto out_no_ir;
+ }
+ /* store for use in ir_probe() again, and open() later on */
+ ret = add_ir_device(ir);
+ if (ret)
+ goto out_free_ir;
+
+ ir->adapter = adap;
+ mutex_init(&ir->ir_lock);
+
+ /* set lirc_dev stuff */
+ memcpy(&ir->l, &lirc_template, sizeof(struct lirc_driver));
+ ir->l.minor = minor; /* module option */
+ ir->l.code_length = 13;
+ ir->l.rbuf = NULL;
+ ir->l.fops = &lirc_fops;
+ ir->l.data = ir;
+ ir->l.dev = &adap->dev;
+ ir->l.sample_rate = 0;
+ }
- ir = kzalloc(sizeof(struct IR), GFP_KERNEL);
+ if (tx_probe) {
+ /* Set up a struct IR_tx instance */
+ ir->tx = kzalloc(sizeof(struct IR_tx), GFP_KERNEL);
+ if (ir->tx == NULL) {
+ ret = -ENOMEM;
+ goto out_free_xx;
+ }
- if (!ir)
- goto out_nomem;
+ ir->tx->c = client;
+ ir->tx->need_boot = 1;
+ ir->tx->post_tx_ready_poll =
+ (id->driver_data & ID_FLAG_HDPVR) ? false : true;
+ } else {
+ /* Set up a struct IR_rx instance */
+ ir->rx = kzalloc(sizeof(struct IR_rx), GFP_KERNEL);
+ if (ir->rx == NULL) {
+ ret = -ENOMEM;
+ goto out_free_xx;
+ }
- ret = lirc_buffer_init(&ir->buf, 2, BUFLEN / 2);
- if (ret)
- goto out_nomem;
+ ret = lirc_buffer_init(&ir->rx->buf, 2, BUFLEN / 2);
+ if (ret)
+ goto out_free_xx;
- mutex_init(&ir->ir_lock);
- mutex_init(&ir->buf_lock);
- ir->need_boot = 1;
- ir->is_hdpvr = (id->driver_data & ID_FLAG_HDPVR) ? true : false;
+ mutex_init(&ir->rx->buf_lock);
+ ir->rx->c = client;
+ ir->rx->hdpvr_data_fmt =
+ (id->driver_data & ID_FLAG_HDPVR) ? true : false;
- memcpy(&ir->l, &lirc_template, sizeof(struct lirc_driver));
- ir->l.minor = -1;
+ /* set lirc_dev stuff */
+ ir->l.rbuf = &ir->rx->buf;
+ }
- /* I2C attach to device */
i2c_set_clientdata(client, ir);
- /* initialise RX device */
- if (have_rx) {
- DECLARE_COMPLETION(tn);
- memcpy(&ir->c_rx, client, sizeof(struct i2c_client));
-
- ir->c_rx.addr = 0x71;
- strlcpy(ir->c_rx.name, ZILOG_HAUPPAUGE_IR_RX_NAME,
- I2C_NAME_SIZE);
+ /* Proceed only if we have the required Tx and Rx clients ready to go */
+ if (ir->tx == NULL ||
+ (ir->rx == NULL && !tx_only)) {
+ zilog_info("probe of IR %s on %s (i2c-%d) done. Waiting on "
+ "IR %s.\n", tx_probe ? "Tx" : "Rx", adap->name,
+ adap->nr, tx_probe ? "Rx" : "Tx");
+ goto out_ok;
+ }
+ /* initialise RX device */
+ if (ir->rx != NULL) {
/* try to fire up polling thread */
- ir->t_notify = &tn;
- ir->task = kthread_run(lirc_thread, ir, "lirc_zilog");
- if (IS_ERR(ir->task)) {
- ret = PTR_ERR(ir->task);
- zilog_error("lirc_register_driver: cannot run "
- "poll thread %d\n", ret);
- goto err;
+ ir->rx->task = kthread_run(lirc_thread, ir,
+ "zilog-rx-i2c-%d", adap->nr);
+ if (IS_ERR(ir->rx->task)) {
+ ret = PTR_ERR(ir->rx->task);
+ zilog_error("%s: could not start IR Rx polling thread"
+ "\n", __func__);
+ goto out_free_xx;
}
- wait_for_completion(&tn);
- ir->t_notify = NULL;
- ir->have_rx = 1;
- }
-
- /* initialise TX device */
- if (have_tx) {
- memcpy(&ir->c_tx, client, sizeof(struct i2c_client));
- ir->c_tx.addr = 0x70;
- strlcpy(ir->c_tx.name, ZILOG_HAUPPAUGE_IR_TX_NAME,
- I2C_NAME_SIZE);
- ir->have_tx = 1;
}
- /* set lirc_dev stuff */
- ir->l.code_length = 13;
- ir->l.rbuf = &ir->buf;
- ir->l.fops = &lirc_fops;
- ir->l.data = ir;
- ir->l.minor = minor;
- ir->l.dev = &adap->dev;
- ir->l.sample_rate = 0;
-
/* register with lirc */
ir->l.minor = lirc_register_driver(&ir->l);
if (ir->l.minor < 0 || ir->l.minor >= MAX_IRCTL_DEVICES) {
- zilog_error("ir_attach: \"minor\" must be between 0 and %d "
- "(%d)!\n", MAX_IRCTL_DEVICES-1, ir->l.minor);
+ zilog_error("%s: \"minor\" must be between 0 and %d (%d)!\n",
+ __func__, MAX_IRCTL_DEVICES-1, ir->l.minor);
ret = -EBADRQC;
- goto err;
+ goto out_free_thread;
}
- /* store this for getting back in open() later on */
- ir_devices[ir->l.minor] = ir;
-
/*
* if we have the tx device, load the 'firmware'. We do this
* after registering with lirc as otherwise hotplug seems to take
* 10s to create the lirc device.
*/
- if (have_tx) {
- /* Special TX init */
- ret = tx_init(ir);
- if (ret != 0)
- goto err;
- }
+ ret = tx_init(ir->tx);
+ if (ret != 0)
+ goto out_unregister;
+ zilog_info("probe of IR %s on %s (i2c-%d) done. IR unit ready.\n",
+ tx_probe ? "Tx" : "Rx", adap->name, adap->nr);
+out_ok:
+ mutex_unlock(&ir_devices_lock);
return 0;
-err:
- /* undo everything, hopefully... */
- if (ir->c_rx.addr)
- ir_remove(&ir->c_rx);
- if (ir->c_tx.addr)
- ir_remove(&ir->c_tx);
- return ret;
-
-out_nodev:
- zilog_error("no device found\n");
- return -ENODEV;
-
-out_nomem:
- zilog_error("memory allocation failure\n");
+out_unregister:
+ lirc_unregister_driver(ir->l.minor);
+out_free_thread:
+ destroy_rx_kthread(ir->rx);
+out_free_xx:
+ if (ir->rx != NULL) {
+ if (ir->rx->buf.fifo_initialized)
+ lirc_buffer_free(&ir->rx->buf);
+ if (ir->rx->c != NULL)
+ i2c_set_clientdata(ir->rx->c, NULL);
+ kfree(ir->rx);
+ }
+ if (ir->tx != NULL) {
+ if (ir->tx->c != NULL)
+ i2c_set_clientdata(ir->tx->c, NULL);
+ kfree(ir->tx);
+ }
+out_free_ir:
+ del_ir_device(ir);
kfree(ir);
- return -ENOMEM;
-}
-
-static int ir_command(struct i2c_client *client, unsigned int cmd, void *arg)
-{
- /* nothing */
- return 0;
+out_no_ir:
+ zilog_error("%s: probing IR %s on %s (i2c-%d) failed with %d\n",
+ __func__, tx_probe ? "Tx" : "Rx", adap->name, adap->nr,
+ ret);
+ mutex_unlock(&ir_devices_lock);
+ return ret;
}
static int __init zilog_init(void)
@@ -1361,6 +1418,7 @@ static int __init zilog_init(void)
zilog_notify("Zilog/Hauppauge IR driver initializing\n");
mutex_init(&tx_data_lock);
+ mutex_init(&ir_devices_lock);
request_module("firmware_class");
@@ -1386,7 +1444,8 @@ module_exit(zilog_exit);
MODULE_DESCRIPTION("Zilog/Hauppauge infrared transmitter driver (i2c stack)");
MODULE_AUTHOR("Gerd Knorr, Michal Kochanowicz, Christoph Bartelmus, "
- "Ulrich Mueller, Stefan Jahn, Jerome Brock, Mark Weaver");
+ "Ulrich Mueller, Stefan Jahn, Jerome Brock, Mark Weaver, "
+ "Andy Walls");
MODULE_LICENSE("GPL");
/* for compat with old name, which isn't all that accurate anymore */
MODULE_ALIAS("lirc_pvr150");
@@ -1397,8 +1456,5 @@ MODULE_PARM_DESC(minor, "Preferred minor device number");
module_param(debug, bool, 0644);
MODULE_PARM_DESC(debug, "Enable debugging messages");
-module_param(disable_rx, bool, 0644);
-MODULE_PARM_DESC(disable_rx, "Disable the IR receiver device");
-
-module_param(disable_tx, bool, 0644);
-MODULE_PARM_DESC(disable_tx, "Disable the IR transmitter device");
+module_param(tx_only, bool, 0644);
+MODULE_PARM_DESC(tx_only, "Only handle the IR transmit function");
diff --git a/drivers/staging/sm7xx/smtcfb.c b/drivers/staging/sm7xx/smtcfb.c
index f4b163f..0bc113c 100644
--- a/drivers/staging/sm7xx/smtcfb.c
+++ b/drivers/staging/sm7xx/smtcfb.c
@@ -1071,7 +1071,7 @@ static int __maybe_unused smtcfb_resume(struct pci_dev *pdev)
/* when resuming, restore pci data and fb cursor */
if (pdev->dev.power.power_state.event != PM_EVENT_FREEZE) {
retv = pci_set_power_state(pdev, PCI_D0);
- retv = pci_restore_state(pdev);
+ pci_restore_state(pdev);
if (pci_enable_device(pdev))
return -1;
pci_set_master(pdev);
diff --git a/drivers/staging/smbfs/dir.c b/drivers/staging/smbfs/dir.c
index 87a3a9b..f204d33 100644
--- a/drivers/staging/smbfs/dir.c
+++ b/drivers/staging/smbfs/dir.c
@@ -283,7 +283,7 @@ static int smb_compare_dentry(const struct dentry *,
unsigned int, const char *, const struct qstr *);
static int smb_delete_dentry(const struct dentry *);
-static const struct dentry_operations smbfs_dentry_operations =
+const struct dentry_operations smbfs_dentry_operations =
{
.d_revalidate = smb_lookup_validate,
.d_hash = smb_hash_dentry,
@@ -291,7 +291,7 @@ static const struct dentry_operations smbfs_dentry_operations =
.d_delete = smb_delete_dentry,
};
-static const struct dentry_operations smbfs_dentry_operations_case =
+const struct dentry_operations smbfs_dentry_operations_case =
{
.d_revalidate = smb_lookup_validate,
.d_delete = smb_delete_dentry,
diff --git a/drivers/staging/tm6000/tm6000-video.c b/drivers/staging/tm6000/tm6000-video.c
index 8fe017c..eb9b9f1 100644
--- a/drivers/staging/tm6000/tm6000-video.c
+++ b/drivers/staging/tm6000/tm6000-video.c
@@ -1450,29 +1450,55 @@ static struct video_device tm6000_template = {
* ------------------------------------------------------------------
*/
-int tm6000_v4l2_register(struct tm6000_core *dev)
+static struct video_device *vdev_init(struct tm6000_core *dev,
+ const struct video_device
+ *template, const char *type_name)
{
- int ret = -1;
struct video_device *vfd;
vfd = video_device_alloc();
- if(!vfd) {
+ if (NULL == vfd)
+ return NULL;
+
+ *vfd = *template;
+ vfd->v4l2_dev = &dev->v4l2_dev;
+ vfd->release = video_device_release;
+ vfd->debug = tm6000_debug;
+ vfd->lock = &dev->lock;
+
+ snprintf(vfd->name, sizeof(vfd->name), "%s %s", dev->name, type_name);
+
+ video_set_drvdata(vfd, dev);
+ return vfd;
+}
+
+int tm6000_v4l2_register(struct tm6000_core *dev)
+{
+ int ret = -1;
+
+ dev->vfd = vdev_init(dev, &tm6000_template, "video");
+
+ if (!dev->vfd) {
+ printk(KERN_INFO "%s: can't register video device\n",
+ dev->name);
return -ENOMEM;
}
- dev->vfd = vfd;
/* init video dma queues */
INIT_LIST_HEAD(&dev->vidq.active);
INIT_LIST_HEAD(&dev->vidq.queued);
- memcpy(dev->vfd, &tm6000_template, sizeof(*(dev->vfd)));
- dev->vfd->debug = tm6000_debug;
- dev->vfd->lock = &dev->lock;
+ ret = video_register_device(dev->vfd, VFL_TYPE_GRABBER, video_nr);
- vfd->v4l2_dev = &dev->v4l2_dev;
- video_set_drvdata(vfd, dev);
+ if (ret < 0) {
+ printk(KERN_INFO "%s: can't register video device\n",
+ dev->name);
+ return ret;
+ }
+
+ printk(KERN_INFO "%s: registered device %s\n",
+ dev->name, video_device_node_name(dev->vfd));
- ret = video_register_device(dev->vfd, VFL_TYPE_GRABBER, video_nr);
printk(KERN_INFO "Trident TVMaster TM5600/TM6000/TM6010 USB2 board (Load status: %d)\n", ret);
return ret;
}
diff --git a/drivers/target/Kconfig b/drivers/target/Kconfig
new file mode 100644
index 0000000..2fac3be
--- /dev/null
+++ b/drivers/target/Kconfig
@@ -0,0 +1,32 @@
+
+menuconfig TARGET_CORE
+ tristate "Generic Target Core Mod (TCM) and ConfigFS Infrastructure"
+ depends on SCSI && BLOCK
+ select CONFIGFS_FS
+ default n
+ help
+ Say Y or M here to enable the TCM Storage Engine and ConfigFS enabled
+ control path for target_core_mod. This includes built-in TCM RAMDISK
+ subsystem logic for virtual LUN 0 access
+
+if TARGET_CORE
+
+config TCM_IBLOCK
+ tristate "TCM/IBLOCK Subsystem Plugin for Linux/BLOCK"
+ help
+ Say Y here to enable the TCM/IBLOCK subsystem plugin for non-buffered
+ access to Linux/Block devices using BIO
+
+config TCM_FILEIO
+ tristate "TCM/FILEIO Subsystem Plugin for Linux/VFS"
+ help
+ Say Y here to enable the TCM/FILEIO subsystem plugin for buffered
+ access to Linux/VFS struct file or struct block_device
+
+config TCM_PSCSI
+ tristate "TCM/pSCSI Subsystem Plugin for Linux/SCSI"
+ help
+ Say Y here to enable the TCM/pSCSI subsystem plugin for non-buffered
+ passthrough access to Linux/SCSI device
+
+endif
diff --git a/drivers/target/Makefile b/drivers/target/Makefile
new file mode 100644
index 0000000..5cfd708
--- /dev/null
+++ b/drivers/target/Makefile
@@ -0,0 +1,24 @@
+EXTRA_CFLAGS += -I$(srctree)/drivers/target/ -I$(srctree)/drivers/scsi/
+
+target_core_mod-y := target_core_configfs.o \
+ target_core_device.o \
+ target_core_fabric_configfs.o \
+ target_core_fabric_lib.o \
+ target_core_hba.o \
+ target_core_pr.o \
+ target_core_alua.o \
+ target_core_scdb.o \
+ target_core_tmr.o \
+ target_core_tpg.o \
+ target_core_transport.o \
+ target_core_cdb.o \
+ target_core_ua.o \
+ target_core_rd.o \
+ target_core_mib.o
+
+obj-$(CONFIG_TARGET_CORE) += target_core_mod.o
+
+# Subsystem modules
+obj-$(CONFIG_TCM_IBLOCK) += target_core_iblock.o
+obj-$(CONFIG_TCM_FILEIO) += target_core_file.o
+obj-$(CONFIG_TCM_PSCSI) += target_core_pscsi.o
diff --git a/drivers/target/target_core_alua.c b/drivers/target/target_core_alua.c
new file mode 100644
index 0000000..2c5fcfe
--- /dev/null
+++ b/drivers/target/target_core_alua.c
@@ -0,0 +1,1991 @@
+/*******************************************************************************
+ * Filename: target_core_alua.c
+ *
+ * This file contains SPC-3 compliant asymmetric logical unit assigntment (ALUA)
+ *
+ * Copyright (c) 2009-2010 Rising Tide Systems
+ * Copyright (c) 2009-2010 Linux-iSCSI.org
+ *
+ * Nicholas A. Bellinger <nab@kernel.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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ ******************************************************************************/
+
+#include <linux/version.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/configfs.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+
+#include <target/target_core_base.h>
+#include <target/target_core_device.h>
+#include <target/target_core_transport.h>
+#include <target/target_core_fabric_ops.h>
+#include <target/target_core_configfs.h>
+
+#include "target_core_alua.h"
+#include "target_core_hba.h"
+#include "target_core_ua.h"
+
+static int core_alua_check_transition(int state, int *primary);
+static int core_alua_set_tg_pt_secondary_state(
+ struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem,
+ struct se_port *port, int explict, int offline);
+
+/*
+ * REPORT_TARGET_PORT_GROUPS
+ *
+ * See spc4r17 section 6.27
+ */
+int core_emulate_report_target_port_groups(struct se_cmd *cmd)
+{
+ struct se_subsystem_dev *su_dev = SE_DEV(cmd)->se_sub_dev;
+ struct se_port *port;
+ struct t10_alua_tg_pt_gp *tg_pt_gp;
+ struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem;
+ unsigned char *buf = (unsigned char *)T_TASK(cmd)->t_task_buf;
+ u32 rd_len = 0, off = 4; /* Skip over RESERVED area to first
+ Target port group descriptor */
+
+ spin_lock(&T10_ALUA(su_dev)->tg_pt_gps_lock);
+ list_for_each_entry(tg_pt_gp, &T10_ALUA(su_dev)->tg_pt_gps_list,
+ tg_pt_gp_list) {
+ /*
+ * PREF: Preferred target port bit, determine if this
+ * bit should be set for port group.
+ */
+ if (tg_pt_gp->tg_pt_gp_pref)
+ buf[off] = 0x80;
+ /*
+ * Set the ASYMMETRIC ACCESS State
+ */
+ buf[off++] |= (atomic_read(
+ &tg_pt_gp->tg_pt_gp_alua_access_state) & 0xff);
+ /*
+ * Set supported ASYMMETRIC ACCESS State bits
+ */
+ buf[off] = 0x80; /* T_SUP */
+ buf[off] |= 0x40; /* O_SUP */
+ buf[off] |= 0x8; /* U_SUP */
+ buf[off] |= 0x4; /* S_SUP */
+ buf[off] |= 0x2; /* AN_SUP */
+ buf[off++] |= 0x1; /* AO_SUP */
+ /*
+ * TARGET PORT GROUP
+ */
+ buf[off++] = ((tg_pt_gp->tg_pt_gp_id >> 8) & 0xff);
+ buf[off++] = (tg_pt_gp->tg_pt_gp_id & 0xff);
+
+ off++; /* Skip over Reserved */
+ /*
+ * STATUS CODE
+ */
+ buf[off++] = (tg_pt_gp->tg_pt_gp_alua_access_status & 0xff);
+ /*
+ * Vendor Specific field
+ */
+ buf[off++] = 0x00;
+ /*
+ * TARGET PORT COUNT
+ */
+ buf[off++] = (tg_pt_gp->tg_pt_gp_members & 0xff);
+ rd_len += 8;
+
+ spin_lock(&tg_pt_gp->tg_pt_gp_lock);
+ list_for_each_entry(tg_pt_gp_mem, &tg_pt_gp->tg_pt_gp_mem_list,
+ tg_pt_gp_mem_list) {
+ port = tg_pt_gp_mem->tg_pt;
+ /*
+ * Start Target Port descriptor format
+ *
+ * See spc4r17 section 6.2.7 Table 247
+ */
+ off += 2; /* Skip over Obsolete */
+ /*
+ * Set RELATIVE TARGET PORT IDENTIFIER
+ */
+ buf[off++] = ((port->sep_rtpi >> 8) & 0xff);
+ buf[off++] = (port->sep_rtpi & 0xff);
+ rd_len += 4;
+ }
+ spin_unlock(&tg_pt_gp->tg_pt_gp_lock);
+ }
+ spin_unlock(&T10_ALUA(su_dev)->tg_pt_gps_lock);
+ /*
+ * Set the RETURN DATA LENGTH set in the header of the DataIN Payload
+ */
+ buf[0] = ((rd_len >> 24) & 0xff);
+ buf[1] = ((rd_len >> 16) & 0xff);
+ buf[2] = ((rd_len >> 8) & 0xff);
+ buf[3] = (rd_len & 0xff);
+
+ return 0;
+}
+
+/*
+ * SET_TARGET_PORT_GROUPS for explict ALUA operation.
+ *
+ * See spc4r17 section 6.35
+ */
+int core_emulate_set_target_port_groups(struct se_cmd *cmd)
+{
+ struct se_device *dev = SE_DEV(cmd);
+ struct se_subsystem_dev *su_dev = SE_DEV(cmd)->se_sub_dev;
+ struct se_port *port, *l_port = SE_LUN(cmd)->lun_sep;
+ struct se_node_acl *nacl = SE_SESS(cmd)->se_node_acl;
+ struct t10_alua_tg_pt_gp *tg_pt_gp = NULL, *l_tg_pt_gp;
+ struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem, *l_tg_pt_gp_mem;
+ unsigned char *buf = (unsigned char *)T_TASK(cmd)->t_task_buf;
+ unsigned char *ptr = &buf[4]; /* Skip over RESERVED area in header */
+ u32 len = 4; /* Skip over RESERVED area in header */
+ int alua_access_state, primary = 0, rc;
+ u16 tg_pt_id, rtpi;
+
+ if (!(l_port))
+ return PYX_TRANSPORT_LU_COMM_FAILURE;
+ /*
+ * Determine if explict ALUA via SET_TARGET_PORT_GROUPS is allowed
+ * for the local tg_pt_gp.
+ */
+ l_tg_pt_gp_mem = l_port->sep_alua_tg_pt_gp_mem;
+ if (!(l_tg_pt_gp_mem)) {
+ printk(KERN_ERR "Unable to access l_port->sep_alua_tg_pt_gp_mem\n");
+ return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE;
+ }
+ spin_lock(&l_tg_pt_gp_mem->tg_pt_gp_mem_lock);
+ l_tg_pt_gp = l_tg_pt_gp_mem->tg_pt_gp;
+ if (!(l_tg_pt_gp)) {
+ spin_unlock(&l_tg_pt_gp_mem->tg_pt_gp_mem_lock);
+ printk(KERN_ERR "Unable to access *l_tg_pt_gp_mem->tg_pt_gp\n");
+ return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE;
+ }
+ rc = (l_tg_pt_gp->tg_pt_gp_alua_access_type & TPGS_EXPLICT_ALUA);
+ spin_unlock(&l_tg_pt_gp_mem->tg_pt_gp_mem_lock);
+
+ if (!(rc)) {
+ printk(KERN_INFO "Unable to process SET_TARGET_PORT_GROUPS"
+ " while TPGS_EXPLICT_ALUA is disabled\n");
+ return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE;
+ }
+
+ while (len < cmd->data_length) {
+ alua_access_state = (ptr[0] & 0x0f);
+ /*
+ * Check the received ALUA access state, and determine if
+ * the state is a primary or secondary target port asymmetric
+ * access state.
+ */
+ rc = core_alua_check_transition(alua_access_state, &primary);
+ if (rc != 0) {
+ /*
+ * If the SET TARGET PORT GROUPS attempts to establish
+ * an invalid combination of target port asymmetric
+ * access states or attempts to establish an
+ * unsupported target port asymmetric access state,
+ * then the command shall be terminated with CHECK
+ * CONDITION status, with the sense key set to ILLEGAL
+ * REQUEST, and the additional sense code set to INVALID
+ * FIELD IN PARAMETER LIST.
+ */
+ return PYX_TRANSPORT_INVALID_PARAMETER_LIST;
+ }
+ rc = -1;
+ /*
+ * If the ASYMMETRIC ACCESS STATE field (see table 267)
+ * specifies a primary target port asymmetric access state,
+ * then the TARGET PORT GROUP OR TARGET PORT field specifies
+ * a primary target port group for which the primary target
+ * port asymmetric access state shall be changed. If the
+ * ASYMMETRIC ACCESS STATE field specifies a secondary target
+ * port asymmetric access state, then the TARGET PORT GROUP OR
+ * TARGET PORT field specifies the relative target port
+ * identifier (see 3.1.120) of the target port for which the
+ * secondary target port asymmetric access state shall be
+ * changed.
+ */
+ if (primary) {
+ tg_pt_id = ((ptr[2] << 8) & 0xff);
+ tg_pt_id |= (ptr[3] & 0xff);
+ /*
+ * Locate the matching target port group ID from
+ * the global tg_pt_gp list
+ */
+ spin_lock(&T10_ALUA(su_dev)->tg_pt_gps_lock);
+ list_for_each_entry(tg_pt_gp,
+ &T10_ALUA(su_dev)->tg_pt_gps_list,
+ tg_pt_gp_list) {
+ if (!(tg_pt_gp->tg_pt_gp_valid_id))
+ continue;
+
+ if (tg_pt_id != tg_pt_gp->tg_pt_gp_id)
+ continue;
+
+ atomic_inc(&tg_pt_gp->tg_pt_gp_ref_cnt);
+ smp_mb__after_atomic_inc();
+ spin_unlock(&T10_ALUA(su_dev)->tg_pt_gps_lock);
+
+ rc = core_alua_do_port_transition(tg_pt_gp,
+ dev, l_port, nacl,
+ alua_access_state, 1);
+
+ spin_lock(&T10_ALUA(su_dev)->tg_pt_gps_lock);
+ atomic_dec(&tg_pt_gp->tg_pt_gp_ref_cnt);
+ smp_mb__after_atomic_dec();
+ break;
+ }
+ spin_unlock(&T10_ALUA(su_dev)->tg_pt_gps_lock);
+ /*
+ * If not matching target port group ID can be located
+ * throw an exception with ASCQ: INVALID_PARAMETER_LIST
+ */
+ if (rc != 0)
+ return PYX_TRANSPORT_INVALID_PARAMETER_LIST;
+ } else {
+ /*
+ * Extact the RELATIVE TARGET PORT IDENTIFIER to identify
+ * the Target Port in question for the the incoming
+ * SET_TARGET_PORT_GROUPS op.
+ */
+ rtpi = ((ptr[2] << 8) & 0xff);
+ rtpi |= (ptr[3] & 0xff);
+ /*
+ * Locate the matching relative target port identifer
+ * for the struct se_device storage object.
+ */
+ spin_lock(&dev->se_port_lock);
+ list_for_each_entry(port, &dev->dev_sep_list,
+ sep_list) {
+ if (port->sep_rtpi != rtpi)
+ continue;
+
+ tg_pt_gp_mem = port->sep_alua_tg_pt_gp_mem;
+ spin_unlock(&dev->se_port_lock);
+
+ rc = core_alua_set_tg_pt_secondary_state(
+ tg_pt_gp_mem, port, 1, 1);
+
+ spin_lock(&dev->se_port_lock);
+ break;
+ }
+ spin_unlock(&dev->se_port_lock);
+ /*
+ * If not matching relative target port identifier can
+ * be located, throw an exception with ASCQ:
+ * INVALID_PARAMETER_LIST
+ */
+ if (rc != 0)
+ return PYX_TRANSPORT_INVALID_PARAMETER_LIST;
+ }
+
+ ptr += 4;
+ len += 4;
+ }
+
+ return 0;
+}
+
+static inline int core_alua_state_nonoptimized(
+ struct se_cmd *cmd,
+ unsigned char *cdb,
+ int nonop_delay_msecs,
+ u8 *alua_ascq)
+{
+ /*
+ * Set SCF_ALUA_NON_OPTIMIZED here, this value will be checked
+ * later to determine if processing of this cmd needs to be
+ * temporarily delayed for the Active/NonOptimized primary access state.
+ */
+ cmd->se_cmd_flags |= SCF_ALUA_NON_OPTIMIZED;
+ cmd->alua_nonop_delay = nonop_delay_msecs;
+ return 0;
+}
+
+static inline int core_alua_state_standby(
+ struct se_cmd *cmd,
+ unsigned char *cdb,
+ u8 *alua_ascq)
+{
+ /*
+ * Allowed CDBs for ALUA_ACCESS_STATE_STANDBY as defined by
+ * spc4r17 section 5.9.2.4.4
+ */
+ switch (cdb[0]) {
+ case INQUIRY:
+ case LOG_SELECT:
+ case LOG_SENSE:
+ case MODE_SELECT:
+ case MODE_SENSE:
+ case REPORT_LUNS:
+ case RECEIVE_DIAGNOSTIC:
+ case SEND_DIAGNOSTIC:
+ case MAINTENANCE_IN:
+ switch (cdb[1]) {
+ case MI_REPORT_TARGET_PGS:
+ return 0;
+ default:
+ *alua_ascq = ASCQ_04H_ALUA_TG_PT_STANDBY;
+ return 1;
+ }
+ case MAINTENANCE_OUT:
+ switch (cdb[1]) {
+ case MO_SET_TARGET_PGS:
+ return 0;
+ default:
+ *alua_ascq = ASCQ_04H_ALUA_TG_PT_STANDBY;
+ return 1;
+ }
+ case REQUEST_SENSE:
+ case PERSISTENT_RESERVE_IN:
+ case PERSISTENT_RESERVE_OUT:
+ case READ_BUFFER:
+ case WRITE_BUFFER:
+ return 0;
+ default:
+ *alua_ascq = ASCQ_04H_ALUA_TG_PT_STANDBY;
+ return 1;
+ }
+
+ return 0;
+}
+
+static inline int core_alua_state_unavailable(
+ struct se_cmd *cmd,
+ unsigned char *cdb,
+ u8 *alua_ascq)
+{
+ /*
+ * Allowed CDBs for ALUA_ACCESS_STATE_UNAVAILABLE as defined by
+ * spc4r17 section 5.9.2.4.5
+ */
+ switch (cdb[0]) {
+ case INQUIRY:
+ case REPORT_LUNS:
+ case MAINTENANCE_IN:
+ switch (cdb[1]) {
+ case MI_REPORT_TARGET_PGS:
+ return 0;
+ default:
+ *alua_ascq = ASCQ_04H_ALUA_TG_PT_UNAVAILABLE;
+ return 1;
+ }
+ case MAINTENANCE_OUT:
+ switch (cdb[1]) {
+ case MO_SET_TARGET_PGS:
+ return 0;
+ default:
+ *alua_ascq = ASCQ_04H_ALUA_TG_PT_UNAVAILABLE;
+ return 1;
+ }
+ case REQUEST_SENSE:
+ case READ_BUFFER:
+ case WRITE_BUFFER:
+ return 0;
+ default:
+ *alua_ascq = ASCQ_04H_ALUA_TG_PT_UNAVAILABLE;
+ return 1;
+ }
+
+ return 0;
+}
+
+static inline int core_alua_state_transition(
+ struct se_cmd *cmd,
+ unsigned char *cdb,
+ u8 *alua_ascq)
+{
+ /*
+ * Allowed CDBs for ALUA_ACCESS_STATE_TRANSITIO as defined by
+ * spc4r17 section 5.9.2.5
+ */
+ switch (cdb[0]) {
+ case INQUIRY:
+ case REPORT_LUNS:
+ case MAINTENANCE_IN:
+ switch (cdb[1]) {
+ case MI_REPORT_TARGET_PGS:
+ return 0;
+ default:
+ *alua_ascq = ASCQ_04H_ALUA_STATE_TRANSITION;
+ return 1;
+ }
+ case REQUEST_SENSE:
+ case READ_BUFFER:
+ case WRITE_BUFFER:
+ return 0;
+ default:
+ *alua_ascq = ASCQ_04H_ALUA_STATE_TRANSITION;
+ return 1;
+ }
+
+ return 0;
+}
+
+/*
+ * Used for alua_type SPC_ALUA_PASSTHROUGH and SPC2_ALUA_DISABLED
+ * in transport_cmd_sequencer(). This function is assigned to
+ * struct t10_alua *->state_check() in core_setup_alua()
+ */
+static int core_alua_state_check_nop(
+ struct se_cmd *cmd,
+ unsigned char *cdb,
+ u8 *alua_ascq)
+{
+ return 0;
+}
+
+/*
+ * Used for alua_type SPC3_ALUA_EMULATED in transport_cmd_sequencer().
+ * This function is assigned to struct t10_alua *->state_check() in
+ * core_setup_alua()
+ *
+ * Also, this function can return three different return codes to
+ * signal transport_generic_cmd_sequencer()
+ *
+ * return 1: Is used to signal LUN not accecsable, and check condition/not ready
+ * return 0: Used to signal success
+ * reutrn -1: Used to signal failure, and invalid cdb field
+ */
+static int core_alua_state_check(
+ struct se_cmd *cmd,
+ unsigned char *cdb,
+ u8 *alua_ascq)
+{
+ struct se_lun *lun = SE_LUN(cmd);
+ struct se_port *port = lun->lun_sep;
+ struct t10_alua_tg_pt_gp *tg_pt_gp;
+ struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem;
+ int out_alua_state, nonop_delay_msecs;
+
+ if (!(port))
+ return 0;
+ /*
+ * First, check for a struct se_port specific secondary ALUA target port
+ * access state: OFFLINE
+ */
+ if (atomic_read(&port->sep_tg_pt_secondary_offline)) {
+ *alua_ascq = ASCQ_04H_ALUA_OFFLINE;
+ printk(KERN_INFO "ALUA: Got secondary offline status for local"
+ " target port\n");
+ *alua_ascq = ASCQ_04H_ALUA_OFFLINE;
+ return 1;
+ }
+ /*
+ * Second, obtain the struct t10_alua_tg_pt_gp_member pointer to the
+ * ALUA target port group, to obtain current ALUA access state.
+ * Otherwise look for the underlying struct se_device association with
+ * a ALUA logical unit group.
+ */
+ tg_pt_gp_mem = port->sep_alua_tg_pt_gp_mem;
+ spin_lock(&tg_pt_gp_mem->tg_pt_gp_mem_lock);
+ tg_pt_gp = tg_pt_gp_mem->tg_pt_gp;
+ out_alua_state = atomic_read(&tg_pt_gp->tg_pt_gp_alua_access_state);
+ nonop_delay_msecs = tg_pt_gp->tg_pt_gp_nonop_delay_msecs;
+ spin_unlock(&tg_pt_gp_mem->tg_pt_gp_mem_lock);
+ /*
+ * Process ALUA_ACCESS_STATE_ACTIVE_OPTMIZED in a seperate conditional
+ * statement so the complier knows explictly to check this case first.
+ * For the Optimized ALUA access state case, we want to process the
+ * incoming fabric cmd ASAP..
+ */
+ if (out_alua_state == ALUA_ACCESS_STATE_ACTIVE_OPTMIZED)
+ return 0;
+
+ switch (out_alua_state) {
+ case ALUA_ACCESS_STATE_ACTIVE_NON_OPTIMIZED:
+ return core_alua_state_nonoptimized(cmd, cdb,
+ nonop_delay_msecs, alua_ascq);
+ case ALUA_ACCESS_STATE_STANDBY:
+ return core_alua_state_standby(cmd, cdb, alua_ascq);
+ case ALUA_ACCESS_STATE_UNAVAILABLE:
+ return core_alua_state_unavailable(cmd, cdb, alua_ascq);
+ case ALUA_ACCESS_STATE_TRANSITION:
+ return core_alua_state_transition(cmd, cdb, alua_ascq);
+ /*
+ * OFFLINE is a secondary ALUA target port group access state, that is
+ * handled above with struct se_port->sep_tg_pt_secondary_offline=1
+ */
+ case ALUA_ACCESS_STATE_OFFLINE:
+ default:
+ printk(KERN_ERR "Unknown ALUA access state: 0x%02x\n",
+ out_alua_state);
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * Check implict and explict ALUA state change request.
+ */
+static int core_alua_check_transition(int state, int *primary)
+{
+ switch (state) {
+ case ALUA_ACCESS_STATE_ACTIVE_OPTMIZED:
+ case ALUA_ACCESS_STATE_ACTIVE_NON_OPTIMIZED:
+ case ALUA_ACCESS_STATE_STANDBY:
+ case ALUA_ACCESS_STATE_UNAVAILABLE:
+ /*
+ * OPTIMIZED, NON-OPTIMIZED, STANDBY and UNAVAILABLE are
+ * defined as primary target port asymmetric access states.
+ */
+ *primary = 1;
+ break;
+ case ALUA_ACCESS_STATE_OFFLINE:
+ /*
+ * OFFLINE state is defined as a secondary target port
+ * asymmetric access state.
+ */
+ *primary = 0;
+ break;
+ default:
+ printk(KERN_ERR "Unknown ALUA access state: 0x%02x\n", state);
+ return -1;
+ }
+
+ return 0;
+}
+
+static char *core_alua_dump_state(int state)
+{
+ switch (state) {
+ case ALUA_ACCESS_STATE_ACTIVE_OPTMIZED:
+ return "Active/Optimized";
+ case ALUA_ACCESS_STATE_ACTIVE_NON_OPTIMIZED:
+ return "Active/NonOptimized";
+ case ALUA_ACCESS_STATE_STANDBY:
+ return "Standby";
+ case ALUA_ACCESS_STATE_UNAVAILABLE:
+ return "Unavailable";
+ case ALUA_ACCESS_STATE_OFFLINE:
+ return "Offline";
+ default:
+ return "Unknown";
+ }
+
+ return NULL;
+}
+
+char *core_alua_dump_status(int status)
+{
+ switch (status) {
+ case ALUA_STATUS_NONE:
+ return "None";
+ case ALUA_STATUS_ALTERED_BY_EXPLICT_STPG:
+ return "Altered by Explict STPG";
+ case ALUA_STATUS_ALTERED_BY_IMPLICT_ALUA:
+ return "Altered by Implict ALUA";
+ default:
+ return "Unknown";
+ }
+
+ return NULL;
+}
+
+/*
+ * Used by fabric modules to determine when we need to delay processing
+ * for the Active/NonOptimized paths..
+ */
+int core_alua_check_nonop_delay(
+ struct se_cmd *cmd)
+{
+ if (!(cmd->se_cmd_flags & SCF_ALUA_NON_OPTIMIZED))
+ return 0;
+ if (in_interrupt())
+ return 0;
+ /*
+ * The ALUA Active/NonOptimized access state delay can be disabled
+ * in via configfs with a value of zero
+ */
+ if (!(cmd->alua_nonop_delay))
+ return 0;
+ /*
+ * struct se_cmd->alua_nonop_delay gets set by a target port group
+ * defined interval in core_alua_state_nonoptimized()
+ */
+ msleep_interruptible(cmd->alua_nonop_delay);
+ return 0;
+}
+EXPORT_SYMBOL(core_alua_check_nonop_delay);
+
+/*
+ * Called with tg_pt_gp->tg_pt_gp_md_mutex or tg_pt_gp_mem->sep_tg_pt_md_mutex
+ *
+ */
+static int core_alua_write_tpg_metadata(
+ const char *path,
+ unsigned char *md_buf,
+ u32 md_buf_len)
+{
+ mm_segment_t old_fs;
+ struct file *file;
+ struct iovec iov[1];
+ int flags = O_RDWR | O_CREAT | O_TRUNC, ret;
+
+ memset(iov, 0, sizeof(struct iovec));
+
+ file = filp_open(path, flags, 0600);
+ if (IS_ERR(file) || !file || !file->f_dentry) {
+ printk(KERN_ERR "filp_open(%s) for ALUA metadata failed\n",
+ path);
+ return -ENODEV;
+ }
+
+ iov[0].iov_base = &md_buf[0];
+ iov[0].iov_len = md_buf_len;
+
+ old_fs = get_fs();
+ set_fs(get_ds());
+ ret = vfs_writev(file, &iov[0], 1, &file->f_pos);
+ set_fs(old_fs);
+
+ if (ret < 0) {
+ printk(KERN_ERR "Error writing ALUA metadata file: %s\n", path);
+ filp_close(file, NULL);
+ return -EIO;
+ }
+ filp_close(file, NULL);
+
+ return 0;
+}
+
+/*
+ * Called with tg_pt_gp->tg_pt_gp_md_mutex held
+ */
+static int core_alua_update_tpg_primary_metadata(
+ struct t10_alua_tg_pt_gp *tg_pt_gp,
+ int primary_state,
+ unsigned char *md_buf)
+{
+ struct se_subsystem_dev *su_dev = tg_pt_gp->tg_pt_gp_su_dev;
+ struct t10_wwn *wwn = &su_dev->t10_wwn;
+ char path[ALUA_METADATA_PATH_LEN];
+ int len;
+
+ memset(path, 0, ALUA_METADATA_PATH_LEN);
+
+ len = snprintf(md_buf, tg_pt_gp->tg_pt_gp_md_buf_len,
+ "tg_pt_gp_id=%hu\n"
+ "alua_access_state=0x%02x\n"
+ "alua_access_status=0x%02x\n",
+ tg_pt_gp->tg_pt_gp_id, primary_state,
+ tg_pt_gp->tg_pt_gp_alua_access_status);
+
+ snprintf(path, ALUA_METADATA_PATH_LEN,
+ "/var/target/alua/tpgs_%s/%s", &wwn->unit_serial[0],
+ config_item_name(&tg_pt_gp->tg_pt_gp_group.cg_item));
+
+ return core_alua_write_tpg_metadata(path, md_buf, len);
+}
+
+static int core_alua_do_transition_tg_pt(
+ struct t10_alua_tg_pt_gp *tg_pt_gp,
+ struct se_port *l_port,
+ struct se_node_acl *nacl,
+ unsigned char *md_buf,
+ int new_state,
+ int explict)
+{
+ struct se_dev_entry *se_deve;
+ struct se_lun_acl *lacl;
+ struct se_port *port;
+ struct t10_alua_tg_pt_gp_member *mem;
+ int old_state = 0;
+ /*
+ * Save the old primary ALUA access state, and set the current state
+ * to ALUA_ACCESS_STATE_TRANSITION.
+ */
+ old_state = atomic_read(&tg_pt_gp->tg_pt_gp_alua_access_state);
+ atomic_set(&tg_pt_gp->tg_pt_gp_alua_access_state,
+ ALUA_ACCESS_STATE_TRANSITION);
+ tg_pt_gp->tg_pt_gp_alua_access_status = (explict) ?
+ ALUA_STATUS_ALTERED_BY_EXPLICT_STPG :
+ ALUA_STATUS_ALTERED_BY_IMPLICT_ALUA;
+ /*
+ * Check for the optional ALUA primary state transition delay
+ */
+ if (tg_pt_gp->tg_pt_gp_trans_delay_msecs != 0)
+ msleep_interruptible(tg_pt_gp->tg_pt_gp_trans_delay_msecs);
+
+ spin_lock(&tg_pt_gp->tg_pt_gp_lock);
+ list_for_each_entry(mem, &tg_pt_gp->tg_pt_gp_mem_list,
+ tg_pt_gp_mem_list) {
+ port = mem->tg_pt;
+ /*
+ * After an implicit target port asymmetric access state
+ * change, a device server shall establish a unit attention
+ * condition for the initiator port associated with every I_T
+ * nexus with the additional sense code set to ASYMMETRIC
+ * ACCESS STATE CHAGED.
+ *
+ * After an explicit target port asymmetric access state
+ * change, a device server shall establish a unit attention
+ * condition with the additional sense code set to ASYMMETRIC
+ * ACCESS STATE CHANGED for the initiator port associated with
+ * every I_T nexus other than the I_T nexus on which the SET
+ * TARGET PORT GROUPS command
+ */
+ atomic_inc(&mem->tg_pt_gp_mem_ref_cnt);
+ smp_mb__after_atomic_inc();
+ spin_unlock(&tg_pt_gp->tg_pt_gp_lock);
+
+ spin_lock_bh(&port->sep_alua_lock);
+ list_for_each_entry(se_deve, &port->sep_alua_list,
+ alua_port_list) {
+ lacl = se_deve->se_lun_acl;
+ /*
+ * se_deve->se_lun_acl pointer may be NULL for a
+ * entry created without explict Node+MappedLUN ACLs
+ */
+ if (!(lacl))
+ continue;
+
+ if (explict &&
+ (nacl != NULL) && (nacl == lacl->se_lun_nacl) &&
+ (l_port != NULL) && (l_port == port))
+ continue;
+
+ core_scsi3_ua_allocate(lacl->se_lun_nacl,
+ se_deve->mapped_lun, 0x2A,
+ ASCQ_2AH_ASYMMETRIC_ACCESS_STATE_CHANGED);
+ }
+ spin_unlock_bh(&port->sep_alua_lock);
+
+ spin_lock(&tg_pt_gp->tg_pt_gp_lock);
+ atomic_dec(&mem->tg_pt_gp_mem_ref_cnt);
+ smp_mb__after_atomic_dec();
+ }
+ spin_unlock(&tg_pt_gp->tg_pt_gp_lock);
+ /*
+ * Update the ALUA metadata buf that has been allocated in
+ * core_alua_do_port_transition(), this metadata will be written
+ * to struct file.
+ *
+ * Note that there is the case where we do not want to update the
+ * metadata when the saved metadata is being parsed in userspace
+ * when setting the existing port access state and access status.
+ *
+ * Also note that the failure to write out the ALUA metadata to
+ * struct file does NOT affect the actual ALUA transition.
+ */
+ if (tg_pt_gp->tg_pt_gp_write_metadata) {
+ mutex_lock(&tg_pt_gp->tg_pt_gp_md_mutex);
+ core_alua_update_tpg_primary_metadata(tg_pt_gp,
+ new_state, md_buf);
+ mutex_unlock(&tg_pt_gp->tg_pt_gp_md_mutex);
+ }
+ /*
+ * Set the current primary ALUA access state to the requested new state
+ */
+ atomic_set(&tg_pt_gp->tg_pt_gp_alua_access_state, new_state);
+
+ printk(KERN_INFO "Successful %s ALUA transition TG PT Group: %s ID: %hu"
+ " from primary access state %s to %s\n", (explict) ? "explict" :
+ "implict", config_item_name(&tg_pt_gp->tg_pt_gp_group.cg_item),
+ tg_pt_gp->tg_pt_gp_id, core_alua_dump_state(old_state),
+ core_alua_dump_state(new_state));
+
+ return 0;
+}
+
+int core_alua_do_port_transition(
+ struct t10_alua_tg_pt_gp *l_tg_pt_gp,
+ struct se_device *l_dev,
+ struct se_port *l_port,
+ struct se_node_acl *l_nacl,
+ int new_state,
+ int explict)
+{
+ struct se_device *dev;
+ struct se_port *port;
+ struct se_subsystem_dev *su_dev;
+ struct se_node_acl *nacl;
+ struct t10_alua_lu_gp *lu_gp;
+ struct t10_alua_lu_gp_member *lu_gp_mem, *local_lu_gp_mem;
+ struct t10_alua_tg_pt_gp *tg_pt_gp;
+ unsigned char *md_buf;
+ int primary;
+
+ if (core_alua_check_transition(new_state, &primary) != 0)
+ return -EINVAL;
+
+ md_buf = kzalloc(l_tg_pt_gp->tg_pt_gp_md_buf_len, GFP_KERNEL);
+ if (!(md_buf)) {
+ printk("Unable to allocate buf for ALUA metadata\n");
+ return -ENOMEM;
+ }
+
+ local_lu_gp_mem = l_dev->dev_alua_lu_gp_mem;
+ spin_lock(&local_lu_gp_mem->lu_gp_mem_lock);
+ lu_gp = local_lu_gp_mem->lu_gp;
+ atomic_inc(&lu_gp->lu_gp_ref_cnt);
+ smp_mb__after_atomic_inc();
+ spin_unlock(&local_lu_gp_mem->lu_gp_mem_lock);
+ /*
+ * For storage objects that are members of the 'default_lu_gp',
+ * we only do transition on the passed *l_tp_pt_gp, and not
+ * on all of the matching target port groups IDs in default_lu_gp.
+ */
+ if (!(lu_gp->lu_gp_id)) {
+ /*
+ * core_alua_do_transition_tg_pt() will always return
+ * success.
+ */
+ core_alua_do_transition_tg_pt(l_tg_pt_gp, l_port, l_nacl,
+ md_buf, new_state, explict);
+ atomic_dec(&lu_gp->lu_gp_ref_cnt);
+ smp_mb__after_atomic_dec();
+ kfree(md_buf);
+ return 0;
+ }
+ /*
+ * For all other LU groups aside from 'default_lu_gp', walk all of
+ * the associated storage objects looking for a matching target port
+ * group ID from the local target port group.
+ */
+ spin_lock(&lu_gp->lu_gp_lock);
+ list_for_each_entry(lu_gp_mem, &lu_gp->lu_gp_mem_list,
+ lu_gp_mem_list) {
+
+ dev = lu_gp_mem->lu_gp_mem_dev;
+ su_dev = dev->se_sub_dev;
+ atomic_inc(&lu_gp_mem->lu_gp_mem_ref_cnt);
+ smp_mb__after_atomic_inc();
+ spin_unlock(&lu_gp->lu_gp_lock);
+
+ spin_lock(&T10_ALUA(su_dev)->tg_pt_gps_lock);
+ list_for_each_entry(tg_pt_gp,
+ &T10_ALUA(su_dev)->tg_pt_gps_list,
+ tg_pt_gp_list) {
+
+ if (!(tg_pt_gp->tg_pt_gp_valid_id))
+ continue;
+ /*
+ * If the target behavior port asymmetric access state
+ * is changed for any target port group accessiable via
+ * a logical unit within a LU group, the target port
+ * behavior group asymmetric access states for the same
+ * target port group accessible via other logical units
+ * in that LU group will also change.
+ */
+ if (l_tg_pt_gp->tg_pt_gp_id != tg_pt_gp->tg_pt_gp_id)
+ continue;
+
+ if (l_tg_pt_gp == tg_pt_gp) {
+ port = l_port;
+ nacl = l_nacl;
+ } else {
+ port = NULL;
+ nacl = NULL;
+ }
+ atomic_inc(&tg_pt_gp->tg_pt_gp_ref_cnt);
+ smp_mb__after_atomic_inc();
+ spin_unlock(&T10_ALUA(su_dev)->tg_pt_gps_lock);
+ /*
+ * core_alua_do_transition_tg_pt() will always return
+ * success.
+ */
+ core_alua_do_transition_tg_pt(tg_pt_gp, port,
+ nacl, md_buf, new_state, explict);
+
+ spin_lock(&T10_ALUA(su_dev)->tg_pt_gps_lock);
+ atomic_dec(&tg_pt_gp->tg_pt_gp_ref_cnt);
+ smp_mb__after_atomic_dec();
+ }
+ spin_unlock(&T10_ALUA(su_dev)->tg_pt_gps_lock);
+
+ spin_lock(&lu_gp->lu_gp_lock);
+ atomic_dec(&lu_gp_mem->lu_gp_mem_ref_cnt);
+ smp_mb__after_atomic_dec();
+ }
+ spin_unlock(&lu_gp->lu_gp_lock);
+
+ printk(KERN_INFO "Successfully processed LU Group: %s all ALUA TG PT"
+ " Group IDs: %hu %s transition to primary state: %s\n",
+ config_item_name(&lu_gp->lu_gp_group.cg_item),
+ l_tg_pt_gp->tg_pt_gp_id, (explict) ? "explict" : "implict",
+ core_alua_dump_state(new_state));
+
+ atomic_dec(&lu_gp->lu_gp_ref_cnt);
+ smp_mb__after_atomic_dec();
+ kfree(md_buf);
+ return 0;
+}
+
+/*
+ * Called with tg_pt_gp_mem->sep_tg_pt_md_mutex held
+ */
+static int core_alua_update_tpg_secondary_metadata(
+ struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem,
+ struct se_port *port,
+ unsigned char *md_buf,
+ u32 md_buf_len)
+{
+ struct se_portal_group *se_tpg = port->sep_tpg;
+ char path[ALUA_METADATA_PATH_LEN], wwn[ALUA_SECONDARY_METADATA_WWN_LEN];
+ int len;
+
+ memset(path, 0, ALUA_METADATA_PATH_LEN);
+ memset(wwn, 0, ALUA_SECONDARY_METADATA_WWN_LEN);
+
+ len = snprintf(wwn, ALUA_SECONDARY_METADATA_WWN_LEN, "%s",
+ TPG_TFO(se_tpg)->tpg_get_wwn(se_tpg));
+
+ if (TPG_TFO(se_tpg)->tpg_get_tag != NULL)
+ snprintf(wwn+len, ALUA_SECONDARY_METADATA_WWN_LEN-len, "+%hu",
+ TPG_TFO(se_tpg)->tpg_get_tag(se_tpg));
+
+ len = snprintf(md_buf, md_buf_len, "alua_tg_pt_offline=%d\n"
+ "alua_tg_pt_status=0x%02x\n",
+ atomic_read(&port->sep_tg_pt_secondary_offline),
+ port->sep_tg_pt_secondary_stat);
+
+ snprintf(path, ALUA_METADATA_PATH_LEN, "/var/target/alua/%s/%s/lun_%u",
+ TPG_TFO(se_tpg)->get_fabric_name(), wwn,
+ port->sep_lun->unpacked_lun);
+
+ return core_alua_write_tpg_metadata(path, md_buf, len);
+}
+
+static int core_alua_set_tg_pt_secondary_state(
+ struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem,
+ struct se_port *port,
+ int explict,
+ int offline)
+{
+ struct t10_alua_tg_pt_gp *tg_pt_gp;
+ unsigned char *md_buf;
+ u32 md_buf_len;
+ int trans_delay_msecs;
+
+ spin_lock(&tg_pt_gp_mem->tg_pt_gp_mem_lock);
+ tg_pt_gp = tg_pt_gp_mem->tg_pt_gp;
+ if (!(tg_pt_gp)) {
+ spin_unlock(&tg_pt_gp_mem->tg_pt_gp_mem_lock);
+ printk(KERN_ERR "Unable to complete secondary state"
+ " transition\n");
+ return -1;
+ }
+ trans_delay_msecs = tg_pt_gp->tg_pt_gp_trans_delay_msecs;
+ /*
+ * Set the secondary ALUA target port access state to OFFLINE
+ * or release the previously secondary state for struct se_port
+ */
+ if (offline)
+ atomic_set(&port->sep_tg_pt_secondary_offline, 1);
+ else
+ atomic_set(&port->sep_tg_pt_secondary_offline, 0);
+
+ md_buf_len = tg_pt_gp->tg_pt_gp_md_buf_len;
+ port->sep_tg_pt_secondary_stat = (explict) ?
+ ALUA_STATUS_ALTERED_BY_EXPLICT_STPG :
+ ALUA_STATUS_ALTERED_BY_IMPLICT_ALUA;
+
+ printk(KERN_INFO "Successful %s ALUA transition TG PT Group: %s ID: %hu"
+ " to secondary access state: %s\n", (explict) ? "explict" :
+ "implict", config_item_name(&tg_pt_gp->tg_pt_gp_group.cg_item),
+ tg_pt_gp->tg_pt_gp_id, (offline) ? "OFFLINE" : "ONLINE");
+
+ spin_unlock(&tg_pt_gp_mem->tg_pt_gp_mem_lock);
+ /*
+ * Do the optional transition delay after we set the secondary
+ * ALUA access state.
+ */
+ if (trans_delay_msecs != 0)
+ msleep_interruptible(trans_delay_msecs);
+ /*
+ * See if we need to update the ALUA fabric port metadata for
+ * secondary state and status
+ */
+ if (port->sep_tg_pt_secondary_write_md) {
+ md_buf = kzalloc(md_buf_len, GFP_KERNEL);
+ if (!(md_buf)) {
+ printk(KERN_ERR "Unable to allocate md_buf for"
+ " secondary ALUA access metadata\n");
+ return -1;
+ }
+ mutex_lock(&port->sep_tg_pt_md_mutex);
+ core_alua_update_tpg_secondary_metadata(tg_pt_gp_mem, port,
+ md_buf, md_buf_len);
+ mutex_unlock(&port->sep_tg_pt_md_mutex);
+
+ kfree(md_buf);
+ }
+
+ return 0;
+}
+
+struct t10_alua_lu_gp *
+core_alua_allocate_lu_gp(const char *name, int def_group)
+{
+ struct t10_alua_lu_gp *lu_gp;
+
+ lu_gp = kmem_cache_zalloc(t10_alua_lu_gp_cache, GFP_KERNEL);
+ if (!(lu_gp)) {
+ printk(KERN_ERR "Unable to allocate struct t10_alua_lu_gp\n");
+ return ERR_PTR(-ENOMEM);;
+ }
+ INIT_LIST_HEAD(&lu_gp->lu_gp_list);
+ INIT_LIST_HEAD(&lu_gp->lu_gp_mem_list);
+ spin_lock_init(&lu_gp->lu_gp_lock);
+ atomic_set(&lu_gp->lu_gp_ref_cnt, 0);
+
+ if (def_group) {
+ lu_gp->lu_gp_id = se_global->alua_lu_gps_counter++;;
+ lu_gp->lu_gp_valid_id = 1;
+ se_global->alua_lu_gps_count++;
+ }
+
+ return lu_gp;
+}
+
+int core_alua_set_lu_gp_id(struct t10_alua_lu_gp *lu_gp, u16 lu_gp_id)
+{
+ struct t10_alua_lu_gp *lu_gp_tmp;
+ u16 lu_gp_id_tmp;
+ /*
+ * The lu_gp->lu_gp_id may only be set once..
+ */
+ if (lu_gp->lu_gp_valid_id) {
+ printk(KERN_WARNING "ALUA LU Group already has a valid ID,"
+ " ignoring request\n");
+ return -1;
+ }
+
+ spin_lock(&se_global->lu_gps_lock);
+ if (se_global->alua_lu_gps_count == 0x0000ffff) {
+ printk(KERN_ERR "Maximum ALUA se_global->alua_lu_gps_count:"
+ " 0x0000ffff reached\n");
+ spin_unlock(&se_global->lu_gps_lock);
+ kmem_cache_free(t10_alua_lu_gp_cache, lu_gp);
+ return -1;
+ }
+again:
+ lu_gp_id_tmp = (lu_gp_id != 0) ? lu_gp_id :
+ se_global->alua_lu_gps_counter++;
+
+ list_for_each_entry(lu_gp_tmp, &se_global->g_lu_gps_list, lu_gp_list) {
+ if (lu_gp_tmp->lu_gp_id == lu_gp_id_tmp) {
+ if (!(lu_gp_id))
+ goto again;
+
+ printk(KERN_WARNING "ALUA Logical Unit Group ID: %hu"
+ " already exists, ignoring request\n",
+ lu_gp_id);
+ spin_unlock(&se_global->lu_gps_lock);
+ return -1;
+ }
+ }
+
+ lu_gp->lu_gp_id = lu_gp_id_tmp;
+ lu_gp->lu_gp_valid_id = 1;
+ list_add_tail(&lu_gp->lu_gp_list, &se_global->g_lu_gps_list);
+ se_global->alua_lu_gps_count++;
+ spin_unlock(&se_global->lu_gps_lock);
+
+ return 0;
+}
+
+static struct t10_alua_lu_gp_member *
+core_alua_allocate_lu_gp_mem(struct se_device *dev)
+{
+ struct t10_alua_lu_gp_member *lu_gp_mem;
+
+ lu_gp_mem = kmem_cache_zalloc(t10_alua_lu_gp_mem_cache, GFP_KERNEL);
+ if (!(lu_gp_mem)) {
+ printk(KERN_ERR "Unable to allocate struct t10_alua_lu_gp_member\n");
+ return ERR_PTR(-ENOMEM);
+ }
+ INIT_LIST_HEAD(&lu_gp_mem->lu_gp_mem_list);
+ spin_lock_init(&lu_gp_mem->lu_gp_mem_lock);
+ atomic_set(&lu_gp_mem->lu_gp_mem_ref_cnt, 0);
+
+ lu_gp_mem->lu_gp_mem_dev = dev;
+ dev->dev_alua_lu_gp_mem = lu_gp_mem;
+
+ return lu_gp_mem;
+}
+
+void core_alua_free_lu_gp(struct t10_alua_lu_gp *lu_gp)
+{
+ struct t10_alua_lu_gp_member *lu_gp_mem, *lu_gp_mem_tmp;
+ /*
+ * Once we have reached this point, config_item_put() has
+ * already been called from target_core_alua_drop_lu_gp().
+ *
+ * Here, we remove the *lu_gp from the global list so that
+ * no associations can be made while we are releasing
+ * struct t10_alua_lu_gp.
+ */
+ spin_lock(&se_global->lu_gps_lock);
+ atomic_set(&lu_gp->lu_gp_shutdown, 1);
+ list_del(&lu_gp->lu_gp_list);
+ se_global->alua_lu_gps_count--;
+ spin_unlock(&se_global->lu_gps_lock);
+ /*
+ * Allow struct t10_alua_lu_gp * referenced by core_alua_get_lu_gp_by_name()
+ * in target_core_configfs.c:target_core_store_alua_lu_gp() to be
+ * released with core_alua_put_lu_gp_from_name()
+ */
+ while (atomic_read(&lu_gp->lu_gp_ref_cnt))
+ cpu_relax();
+ /*
+ * Release reference to struct t10_alua_lu_gp * from all associated
+ * struct se_device.
+ */
+ spin_lock(&lu_gp->lu_gp_lock);
+ list_for_each_entry_safe(lu_gp_mem, lu_gp_mem_tmp,
+ &lu_gp->lu_gp_mem_list, lu_gp_mem_list) {
+ if (lu_gp_mem->lu_gp_assoc) {
+ list_del(&lu_gp_mem->lu_gp_mem_list);
+ lu_gp->lu_gp_members--;
+ lu_gp_mem->lu_gp_assoc = 0;
+ }
+ spin_unlock(&lu_gp->lu_gp_lock);
+ /*
+ *
+ * lu_gp_mem is assoicated with a single
+ * struct se_device->dev_alua_lu_gp_mem, and is released when
+ * struct se_device is released via core_alua_free_lu_gp_mem().
+ *
+ * If the passed lu_gp does NOT match the default_lu_gp, assume
+ * we want to re-assocate a given lu_gp_mem with default_lu_gp.
+ */
+ spin_lock(&lu_gp_mem->lu_gp_mem_lock);
+ if (lu_gp != se_global->default_lu_gp)
+ __core_alua_attach_lu_gp_mem(lu_gp_mem,
+ se_global->default_lu_gp);
+ else
+ lu_gp_mem->lu_gp = NULL;
+ spin_unlock(&lu_gp_mem->lu_gp_mem_lock);
+
+ spin_lock(&lu_gp->lu_gp_lock);
+ }
+ spin_unlock(&lu_gp->lu_gp_lock);
+
+ kmem_cache_free(t10_alua_lu_gp_cache, lu_gp);
+}
+
+void core_alua_free_lu_gp_mem(struct se_device *dev)
+{
+ struct se_subsystem_dev *su_dev = dev->se_sub_dev;
+ struct t10_alua *alua = T10_ALUA(su_dev);
+ struct t10_alua_lu_gp *lu_gp;
+ struct t10_alua_lu_gp_member *lu_gp_mem;
+
+ if (alua->alua_type != SPC3_ALUA_EMULATED)
+ return;
+
+ lu_gp_mem = dev->dev_alua_lu_gp_mem;
+ if (!(lu_gp_mem))
+ return;
+
+ while (atomic_read(&lu_gp_mem->lu_gp_mem_ref_cnt))
+ cpu_relax();
+
+ spin_lock(&lu_gp_mem->lu_gp_mem_lock);
+ lu_gp = lu_gp_mem->lu_gp;
+ if ((lu_gp)) {
+ spin_lock(&lu_gp->lu_gp_lock);
+ if (lu_gp_mem->lu_gp_assoc) {
+ list_del(&lu_gp_mem->lu_gp_mem_list);
+ lu_gp->lu_gp_members--;
+ lu_gp_mem->lu_gp_assoc = 0;
+ }
+ spin_unlock(&lu_gp->lu_gp_lock);
+ lu_gp_mem->lu_gp = NULL;
+ }
+ spin_unlock(&lu_gp_mem->lu_gp_mem_lock);
+
+ kmem_cache_free(t10_alua_lu_gp_mem_cache, lu_gp_mem);
+}
+
+struct t10_alua_lu_gp *core_alua_get_lu_gp_by_name(const char *name)
+{
+ struct t10_alua_lu_gp *lu_gp;
+ struct config_item *ci;
+
+ spin_lock(&se_global->lu_gps_lock);
+ list_for_each_entry(lu_gp, &se_global->g_lu_gps_list, lu_gp_list) {
+ if (!(lu_gp->lu_gp_valid_id))
+ continue;
+ ci = &lu_gp->lu_gp_group.cg_item;
+ if (!(strcmp(config_item_name(ci), name))) {
+ atomic_inc(&lu_gp->lu_gp_ref_cnt);
+ spin_unlock(&se_global->lu_gps_lock);
+ return lu_gp;
+ }
+ }
+ spin_unlock(&se_global->lu_gps_lock);
+
+ return NULL;
+}
+
+void core_alua_put_lu_gp_from_name(struct t10_alua_lu_gp *lu_gp)
+{
+ spin_lock(&se_global->lu_gps_lock);
+ atomic_dec(&lu_gp->lu_gp_ref_cnt);
+ spin_unlock(&se_global->lu_gps_lock);
+}
+
+/*
+ * Called with struct t10_alua_lu_gp_member->lu_gp_mem_lock
+ */
+void __core_alua_attach_lu_gp_mem(
+ struct t10_alua_lu_gp_member *lu_gp_mem,
+ struct t10_alua_lu_gp *lu_gp)
+{
+ spin_lock(&lu_gp->lu_gp_lock);
+ lu_gp_mem->lu_gp = lu_gp;
+ lu_gp_mem->lu_gp_assoc = 1;
+ list_add_tail(&lu_gp_mem->lu_gp_mem_list, &lu_gp->lu_gp_mem_list);
+ lu_gp->lu_gp_members++;
+ spin_unlock(&lu_gp->lu_gp_lock);
+}
+
+/*
+ * Called with struct t10_alua_lu_gp_member->lu_gp_mem_lock
+ */
+void __core_alua_drop_lu_gp_mem(
+ struct t10_alua_lu_gp_member *lu_gp_mem,
+ struct t10_alua_lu_gp *lu_gp)
+{
+ spin_lock(&lu_gp->lu_gp_lock);
+ list_del(&lu_gp_mem->lu_gp_mem_list);
+ lu_gp_mem->lu_gp = NULL;
+ lu_gp_mem->lu_gp_assoc = 0;
+ lu_gp->lu_gp_members--;
+ spin_unlock(&lu_gp->lu_gp_lock);
+}
+
+struct t10_alua_tg_pt_gp *core_alua_allocate_tg_pt_gp(
+ struct se_subsystem_dev *su_dev,
+ const char *name,
+ int def_group)
+{
+ struct t10_alua_tg_pt_gp *tg_pt_gp;
+
+ tg_pt_gp = kmem_cache_zalloc(t10_alua_tg_pt_gp_cache, GFP_KERNEL);
+ if (!(tg_pt_gp)) {
+ printk(KERN_ERR "Unable to allocate struct t10_alua_tg_pt_gp\n");
+ return NULL;
+ }
+ INIT_LIST_HEAD(&tg_pt_gp->tg_pt_gp_list);
+ INIT_LIST_HEAD(&tg_pt_gp->tg_pt_gp_mem_list);
+ mutex_init(&tg_pt_gp->tg_pt_gp_md_mutex);
+ spin_lock_init(&tg_pt_gp->tg_pt_gp_lock);
+ atomic_set(&tg_pt_gp->tg_pt_gp_ref_cnt, 0);
+ tg_pt_gp->tg_pt_gp_su_dev = su_dev;
+ tg_pt_gp->tg_pt_gp_md_buf_len = ALUA_MD_BUF_LEN;
+ atomic_set(&tg_pt_gp->tg_pt_gp_alua_access_state,
+ ALUA_ACCESS_STATE_ACTIVE_OPTMIZED);
+ /*
+ * Enable both explict and implict ALUA support by default
+ */
+ tg_pt_gp->tg_pt_gp_alua_access_type =
+ TPGS_EXPLICT_ALUA | TPGS_IMPLICT_ALUA;
+ /*
+ * Set the default Active/NonOptimized Delay in milliseconds
+ */
+ tg_pt_gp->tg_pt_gp_nonop_delay_msecs = ALUA_DEFAULT_NONOP_DELAY_MSECS;
+ tg_pt_gp->tg_pt_gp_trans_delay_msecs = ALUA_DEFAULT_TRANS_DELAY_MSECS;
+
+ if (def_group) {
+ spin_lock(&T10_ALUA(su_dev)->tg_pt_gps_lock);
+ tg_pt_gp->tg_pt_gp_id =
+ T10_ALUA(su_dev)->alua_tg_pt_gps_counter++;
+ tg_pt_gp->tg_pt_gp_valid_id = 1;
+ T10_ALUA(su_dev)->alua_tg_pt_gps_count++;
+ list_add_tail(&tg_pt_gp->tg_pt_gp_list,
+ &T10_ALUA(su_dev)->tg_pt_gps_list);
+ spin_unlock(&T10_ALUA(su_dev)->tg_pt_gps_lock);
+ }
+
+ return tg_pt_gp;
+}
+
+int core_alua_set_tg_pt_gp_id(
+ struct t10_alua_tg_pt_gp *tg_pt_gp,
+ u16 tg_pt_gp_id)
+{
+ struct se_subsystem_dev *su_dev = tg_pt_gp->tg_pt_gp_su_dev;
+ struct t10_alua_tg_pt_gp *tg_pt_gp_tmp;
+ u16 tg_pt_gp_id_tmp;
+ /*
+ * The tg_pt_gp->tg_pt_gp_id may only be set once..
+ */
+ if (tg_pt_gp->tg_pt_gp_valid_id) {
+ printk(KERN_WARNING "ALUA TG PT Group already has a valid ID,"
+ " ignoring request\n");
+ return -1;
+ }
+
+ spin_lock(&T10_ALUA(su_dev)->tg_pt_gps_lock);
+ if (T10_ALUA(su_dev)->alua_tg_pt_gps_count == 0x0000ffff) {
+ printk(KERN_ERR "Maximum ALUA alua_tg_pt_gps_count:"
+ " 0x0000ffff reached\n");
+ spin_unlock(&T10_ALUA(su_dev)->tg_pt_gps_lock);
+ kmem_cache_free(t10_alua_tg_pt_gp_cache, tg_pt_gp);
+ return -1;
+ }
+again:
+ tg_pt_gp_id_tmp = (tg_pt_gp_id != 0) ? tg_pt_gp_id :
+ T10_ALUA(su_dev)->alua_tg_pt_gps_counter++;
+
+ list_for_each_entry(tg_pt_gp_tmp, &T10_ALUA(su_dev)->tg_pt_gps_list,
+ tg_pt_gp_list) {
+ if (tg_pt_gp_tmp->tg_pt_gp_id == tg_pt_gp_id_tmp) {
+ if (!(tg_pt_gp_id))
+ goto again;
+
+ printk(KERN_ERR "ALUA Target Port Group ID: %hu already"
+ " exists, ignoring request\n", tg_pt_gp_id);
+ spin_unlock(&T10_ALUA(su_dev)->tg_pt_gps_lock);
+ return -1;
+ }
+ }
+
+ tg_pt_gp->tg_pt_gp_id = tg_pt_gp_id_tmp;
+ tg_pt_gp->tg_pt_gp_valid_id = 1;
+ list_add_tail(&tg_pt_gp->tg_pt_gp_list,
+ &T10_ALUA(su_dev)->tg_pt_gps_list);
+ T10_ALUA(su_dev)->alua_tg_pt_gps_count++;
+ spin_unlock(&T10_ALUA(su_dev)->tg_pt_gps_lock);
+
+ return 0;
+}
+
+struct t10_alua_tg_pt_gp_member *core_alua_allocate_tg_pt_gp_mem(
+ struct se_port *port)
+{
+ struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem;
+
+ tg_pt_gp_mem = kmem_cache_zalloc(t10_alua_tg_pt_gp_mem_cache,
+ GFP_KERNEL);
+ if (!(tg_pt_gp_mem)) {
+ printk(KERN_ERR "Unable to allocate struct t10_alua_tg_pt_gp_member\n");
+ return ERR_PTR(-ENOMEM);
+ }
+ INIT_LIST_HEAD(&tg_pt_gp_mem->tg_pt_gp_mem_list);
+ spin_lock_init(&tg_pt_gp_mem->tg_pt_gp_mem_lock);
+ atomic_set(&tg_pt_gp_mem->tg_pt_gp_mem_ref_cnt, 0);
+
+ tg_pt_gp_mem->tg_pt = port;
+ port->sep_alua_tg_pt_gp_mem = tg_pt_gp_mem;
+ atomic_set(&port->sep_tg_pt_gp_active, 1);
+
+ return tg_pt_gp_mem;
+}
+
+void core_alua_free_tg_pt_gp(
+ struct t10_alua_tg_pt_gp *tg_pt_gp)
+{
+ struct se_subsystem_dev *su_dev = tg_pt_gp->tg_pt_gp_su_dev;
+ struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem, *tg_pt_gp_mem_tmp;
+ /*
+ * Once we have reached this point, config_item_put() has already
+ * been called from target_core_alua_drop_tg_pt_gp().
+ *
+ * Here we remove *tg_pt_gp from the global list so that
+ * no assications *OR* explict ALUA via SET_TARGET_PORT_GROUPS
+ * can be made while we are releasing struct t10_alua_tg_pt_gp.
+ */
+ spin_lock(&T10_ALUA(su_dev)->tg_pt_gps_lock);
+ list_del(&tg_pt_gp->tg_pt_gp_list);
+ T10_ALUA(su_dev)->alua_tg_pt_gps_counter--;
+ spin_unlock(&T10_ALUA(su_dev)->tg_pt_gps_lock);
+ /*
+ * Allow a struct t10_alua_tg_pt_gp_member * referenced by
+ * core_alua_get_tg_pt_gp_by_name() in
+ * target_core_configfs.c:target_core_store_alua_tg_pt_gp()
+ * to be released with core_alua_put_tg_pt_gp_from_name().
+ */
+ while (atomic_read(&tg_pt_gp->tg_pt_gp_ref_cnt))
+ cpu_relax();
+ /*
+ * Release reference to struct t10_alua_tg_pt_gp from all associated
+ * struct se_port.
+ */
+ spin_lock(&tg_pt_gp->tg_pt_gp_lock);
+ list_for_each_entry_safe(tg_pt_gp_mem, tg_pt_gp_mem_tmp,
+ &tg_pt_gp->tg_pt_gp_mem_list, tg_pt_gp_mem_list) {
+ if (tg_pt_gp_mem->tg_pt_gp_assoc) {
+ list_del(&tg_pt_gp_mem->tg_pt_gp_mem_list);
+ tg_pt_gp->tg_pt_gp_members--;
+ tg_pt_gp_mem->tg_pt_gp_assoc = 0;
+ }
+ spin_unlock(&tg_pt_gp->tg_pt_gp_lock);
+ /*
+ * tg_pt_gp_mem is assoicated with a single
+ * se_port->sep_alua_tg_pt_gp_mem, and is released via
+ * core_alua_free_tg_pt_gp_mem().
+ *
+ * If the passed tg_pt_gp does NOT match the default_tg_pt_gp,
+ * assume we want to re-assocate a given tg_pt_gp_mem with
+ * default_tg_pt_gp.
+ */
+ spin_lock(&tg_pt_gp_mem->tg_pt_gp_mem_lock);
+ if (tg_pt_gp != T10_ALUA(su_dev)->default_tg_pt_gp) {
+ __core_alua_attach_tg_pt_gp_mem(tg_pt_gp_mem,
+ T10_ALUA(su_dev)->default_tg_pt_gp);
+ } else
+ tg_pt_gp_mem->tg_pt_gp = NULL;
+ spin_unlock(&tg_pt_gp_mem->tg_pt_gp_mem_lock);
+
+ spin_lock(&tg_pt_gp->tg_pt_gp_lock);
+ }
+ spin_unlock(&tg_pt_gp->tg_pt_gp_lock);
+
+ kmem_cache_free(t10_alua_tg_pt_gp_cache, tg_pt_gp);
+}
+
+void core_alua_free_tg_pt_gp_mem(struct se_port *port)
+{
+ struct se_subsystem_dev *su_dev = port->sep_lun->lun_se_dev->se_sub_dev;
+ struct t10_alua *alua = T10_ALUA(su_dev);
+ struct t10_alua_tg_pt_gp *tg_pt_gp;
+ struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem;
+
+ if (alua->alua_type != SPC3_ALUA_EMULATED)
+ return;
+
+ tg_pt_gp_mem = port->sep_alua_tg_pt_gp_mem;
+ if (!(tg_pt_gp_mem))
+ return;
+
+ while (atomic_read(&tg_pt_gp_mem->tg_pt_gp_mem_ref_cnt))
+ cpu_relax();
+
+ spin_lock(&tg_pt_gp_mem->tg_pt_gp_mem_lock);
+ tg_pt_gp = tg_pt_gp_mem->tg_pt_gp;
+ if ((tg_pt_gp)) {
+ spin_lock(&tg_pt_gp->tg_pt_gp_lock);
+ if (tg_pt_gp_mem->tg_pt_gp_assoc) {
+ list_del(&tg_pt_gp_mem->tg_pt_gp_mem_list);
+ tg_pt_gp->tg_pt_gp_members--;
+ tg_pt_gp_mem->tg_pt_gp_assoc = 0;
+ }
+ spin_unlock(&tg_pt_gp->tg_pt_gp_lock);
+ tg_pt_gp_mem->tg_pt_gp = NULL;
+ }
+ spin_unlock(&tg_pt_gp_mem->tg_pt_gp_mem_lock);
+
+ kmem_cache_free(t10_alua_tg_pt_gp_mem_cache, tg_pt_gp_mem);
+}
+
+static struct t10_alua_tg_pt_gp *core_alua_get_tg_pt_gp_by_name(
+ struct se_subsystem_dev *su_dev,
+ const char *name)
+{
+ struct t10_alua_tg_pt_gp *tg_pt_gp;
+ struct config_item *ci;
+
+ spin_lock(&T10_ALUA(su_dev)->tg_pt_gps_lock);
+ list_for_each_entry(tg_pt_gp, &T10_ALUA(su_dev)->tg_pt_gps_list,
+ tg_pt_gp_list) {
+ if (!(tg_pt_gp->tg_pt_gp_valid_id))
+ continue;
+ ci = &tg_pt_gp->tg_pt_gp_group.cg_item;
+ if (!(strcmp(config_item_name(ci), name))) {
+ atomic_inc(&tg_pt_gp->tg_pt_gp_ref_cnt);
+ spin_unlock(&T10_ALUA(su_dev)->tg_pt_gps_lock);
+ return tg_pt_gp;
+ }
+ }
+ spin_unlock(&T10_ALUA(su_dev)->tg_pt_gps_lock);
+
+ return NULL;
+}
+
+static void core_alua_put_tg_pt_gp_from_name(
+ struct t10_alua_tg_pt_gp *tg_pt_gp)
+{
+ struct se_subsystem_dev *su_dev = tg_pt_gp->tg_pt_gp_su_dev;
+
+ spin_lock(&T10_ALUA(su_dev)->tg_pt_gps_lock);
+ atomic_dec(&tg_pt_gp->tg_pt_gp_ref_cnt);
+ spin_unlock(&T10_ALUA(su_dev)->tg_pt_gps_lock);
+}
+
+/*
+ * Called with struct t10_alua_tg_pt_gp_member->tg_pt_gp_mem_lock held
+ */
+void __core_alua_attach_tg_pt_gp_mem(
+ struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem,
+ struct t10_alua_tg_pt_gp *tg_pt_gp)
+{
+ spin_lock(&tg_pt_gp->tg_pt_gp_lock);
+ tg_pt_gp_mem->tg_pt_gp = tg_pt_gp;
+ tg_pt_gp_mem->tg_pt_gp_assoc = 1;
+ list_add_tail(&tg_pt_gp_mem->tg_pt_gp_mem_list,
+ &tg_pt_gp->tg_pt_gp_mem_list);
+ tg_pt_gp->tg_pt_gp_members++;
+ spin_unlock(&tg_pt_gp->tg_pt_gp_lock);
+}
+
+/*
+ * Called with struct t10_alua_tg_pt_gp_member->tg_pt_gp_mem_lock held
+ */
+static void __core_alua_drop_tg_pt_gp_mem(
+ struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem,
+ struct t10_alua_tg_pt_gp *tg_pt_gp)
+{
+ spin_lock(&tg_pt_gp->tg_pt_gp_lock);
+ list_del(&tg_pt_gp_mem->tg_pt_gp_mem_list);
+ tg_pt_gp_mem->tg_pt_gp = NULL;
+ tg_pt_gp_mem->tg_pt_gp_assoc = 0;
+ tg_pt_gp->tg_pt_gp_members--;
+ spin_unlock(&tg_pt_gp->tg_pt_gp_lock);
+}
+
+ssize_t core_alua_show_tg_pt_gp_info(struct se_port *port, char *page)
+{
+ struct se_subsystem_dev *su_dev = port->sep_lun->lun_se_dev->se_sub_dev;
+ struct config_item *tg_pt_ci;
+ struct t10_alua *alua = T10_ALUA(su_dev);
+ struct t10_alua_tg_pt_gp *tg_pt_gp;
+ struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem;
+ ssize_t len = 0;
+
+ if (alua->alua_type != SPC3_ALUA_EMULATED)
+ return len;
+
+ tg_pt_gp_mem = port->sep_alua_tg_pt_gp_mem;
+ if (!(tg_pt_gp_mem))
+ return len;
+
+ spin_lock(&tg_pt_gp_mem->tg_pt_gp_mem_lock);
+ tg_pt_gp = tg_pt_gp_mem->tg_pt_gp;
+ if ((tg_pt_gp)) {
+ tg_pt_ci = &tg_pt_gp->tg_pt_gp_group.cg_item;
+ len += sprintf(page, "TG Port Alias: %s\nTG Port Group ID:"
+ " %hu\nTG Port Primary Access State: %s\nTG Port "
+ "Primary Access Status: %s\nTG Port Secondary Access"
+ " State: %s\nTG Port Secondary Access Status: %s\n",
+ config_item_name(tg_pt_ci), tg_pt_gp->tg_pt_gp_id,
+ core_alua_dump_state(atomic_read(
+ &tg_pt_gp->tg_pt_gp_alua_access_state)),
+ core_alua_dump_status(
+ tg_pt_gp->tg_pt_gp_alua_access_status),
+ (atomic_read(&port->sep_tg_pt_secondary_offline)) ?
+ "Offline" : "None",
+ core_alua_dump_status(port->sep_tg_pt_secondary_stat));
+ }
+ spin_unlock(&tg_pt_gp_mem->tg_pt_gp_mem_lock);
+
+ return len;
+}
+
+ssize_t core_alua_store_tg_pt_gp_info(
+ struct se_port *port,
+ const char *page,
+ size_t count)
+{
+ struct se_portal_group *tpg;
+ struct se_lun *lun;
+ struct se_subsystem_dev *su_dev = port->sep_lun->lun_se_dev->se_sub_dev;
+ struct t10_alua_tg_pt_gp *tg_pt_gp = NULL, *tg_pt_gp_new = NULL;
+ struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem;
+ unsigned char buf[TG_PT_GROUP_NAME_BUF];
+ int move = 0;
+
+ tpg = port->sep_tpg;
+ lun = port->sep_lun;
+
+ if (T10_ALUA(su_dev)->alua_type != SPC3_ALUA_EMULATED) {
+ printk(KERN_WARNING "SPC3_ALUA_EMULATED not enabled for"
+ " %s/tpgt_%hu/%s\n", TPG_TFO(tpg)->tpg_get_wwn(tpg),
+ TPG_TFO(tpg)->tpg_get_tag(tpg),
+ config_item_name(&lun->lun_group.cg_item));
+ return -EINVAL;
+ }
+
+ if (count > TG_PT_GROUP_NAME_BUF) {
+ printk(KERN_ERR "ALUA Target Port Group alias too large!\n");
+ return -EINVAL;
+ }
+ memset(buf, 0, TG_PT_GROUP_NAME_BUF);
+ memcpy(buf, page, count);
+ /*
+ * Any ALUA target port group alias besides "NULL" means we will be
+ * making a new group association.
+ */
+ if (strcmp(strstrip(buf), "NULL")) {
+ /*
+ * core_alua_get_tg_pt_gp_by_name() will increment reference to
+ * struct t10_alua_tg_pt_gp. This reference is released with
+ * core_alua_put_tg_pt_gp_from_name() below.
+ */
+ tg_pt_gp_new = core_alua_get_tg_pt_gp_by_name(su_dev,
+ strstrip(buf));
+ if (!(tg_pt_gp_new))
+ return -ENODEV;
+ }
+ tg_pt_gp_mem = port->sep_alua_tg_pt_gp_mem;
+ if (!(tg_pt_gp_mem)) {
+ if (tg_pt_gp_new)
+ core_alua_put_tg_pt_gp_from_name(tg_pt_gp_new);
+ printk(KERN_ERR "NULL struct se_port->sep_alua_tg_pt_gp_mem pointer\n");
+ return -EINVAL;
+ }
+
+ spin_lock(&tg_pt_gp_mem->tg_pt_gp_mem_lock);
+ tg_pt_gp = tg_pt_gp_mem->tg_pt_gp;
+ if ((tg_pt_gp)) {
+ /*
+ * Clearing an existing tg_pt_gp association, and replacing
+ * with the default_tg_pt_gp.
+ */
+ if (!(tg_pt_gp_new)) {
+ printk(KERN_INFO "Target_Core_ConfigFS: Moving"
+ " %s/tpgt_%hu/%s from ALUA Target Port Group:"
+ " alua/%s, ID: %hu back to"
+ " default_tg_pt_gp\n",
+ TPG_TFO(tpg)->tpg_get_wwn(tpg),
+ TPG_TFO(tpg)->tpg_get_tag(tpg),
+ config_item_name(&lun->lun_group.cg_item),
+ config_item_name(
+ &tg_pt_gp->tg_pt_gp_group.cg_item),
+ tg_pt_gp->tg_pt_gp_id);
+
+ __core_alua_drop_tg_pt_gp_mem(tg_pt_gp_mem, tg_pt_gp);
+ __core_alua_attach_tg_pt_gp_mem(tg_pt_gp_mem,
+ T10_ALUA(su_dev)->default_tg_pt_gp);
+ spin_unlock(&tg_pt_gp_mem->tg_pt_gp_mem_lock);
+
+ return count;
+ }
+ /*
+ * Removing existing association of tg_pt_gp_mem with tg_pt_gp
+ */
+ __core_alua_drop_tg_pt_gp_mem(tg_pt_gp_mem, tg_pt_gp);
+ move = 1;
+ }
+ /*
+ * Associate tg_pt_gp_mem with tg_pt_gp_new.
+ */
+ __core_alua_attach_tg_pt_gp_mem(tg_pt_gp_mem, tg_pt_gp_new);
+ spin_unlock(&tg_pt_gp_mem->tg_pt_gp_mem_lock);
+ printk(KERN_INFO "Target_Core_ConfigFS: %s %s/tpgt_%hu/%s to ALUA"
+ " Target Port Group: alua/%s, ID: %hu\n", (move) ?
+ "Moving" : "Adding", TPG_TFO(tpg)->tpg_get_wwn(tpg),
+ TPG_TFO(tpg)->tpg_get_tag(tpg),
+ config_item_name(&lun->lun_group.cg_item),
+ config_item_name(&tg_pt_gp_new->tg_pt_gp_group.cg_item),
+ tg_pt_gp_new->tg_pt_gp_id);
+
+ core_alua_put_tg_pt_gp_from_name(tg_pt_gp_new);
+ return count;
+}
+
+ssize_t core_alua_show_access_type(
+ struct t10_alua_tg_pt_gp *tg_pt_gp,
+ char *page)
+{
+ if ((tg_pt_gp->tg_pt_gp_alua_access_type & TPGS_EXPLICT_ALUA) &&
+ (tg_pt_gp->tg_pt_gp_alua_access_type & TPGS_IMPLICT_ALUA))
+ return sprintf(page, "Implict and Explict\n");
+ else if (tg_pt_gp->tg_pt_gp_alua_access_type & TPGS_IMPLICT_ALUA)
+ return sprintf(page, "Implict\n");
+ else if (tg_pt_gp->tg_pt_gp_alua_access_type & TPGS_EXPLICT_ALUA)
+ return sprintf(page, "Explict\n");
+ else
+ return sprintf(page, "None\n");
+}
+
+ssize_t core_alua_store_access_type(
+ struct t10_alua_tg_pt_gp *tg_pt_gp,
+ const char *page,
+ size_t count)
+{
+ unsigned long tmp;
+ int ret;
+
+ ret = strict_strtoul(page, 0, &tmp);
+ if (ret < 0) {
+ printk(KERN_ERR "Unable to extract alua_access_type\n");
+ return -EINVAL;
+ }
+ if ((tmp != 0) && (tmp != 1) && (tmp != 2) && (tmp != 3)) {
+ printk(KERN_ERR "Illegal value for alua_access_type:"
+ " %lu\n", tmp);
+ return -EINVAL;
+ }
+ if (tmp == 3)
+ tg_pt_gp->tg_pt_gp_alua_access_type =
+ TPGS_IMPLICT_ALUA | TPGS_EXPLICT_ALUA;
+ else if (tmp == 2)
+ tg_pt_gp->tg_pt_gp_alua_access_type = TPGS_EXPLICT_ALUA;
+ else if (tmp == 1)
+ tg_pt_gp->tg_pt_gp_alua_access_type = TPGS_IMPLICT_ALUA;
+ else
+ tg_pt_gp->tg_pt_gp_alua_access_type = 0;
+
+ return count;
+}
+
+ssize_t core_alua_show_nonop_delay_msecs(
+ struct t10_alua_tg_pt_gp *tg_pt_gp,
+ char *page)
+{
+ return sprintf(page, "%d\n", tg_pt_gp->tg_pt_gp_nonop_delay_msecs);
+}
+
+ssize_t core_alua_store_nonop_delay_msecs(
+ struct t10_alua_tg_pt_gp *tg_pt_gp,
+ const char *page,
+ size_t count)
+{
+ unsigned long tmp;
+ int ret;
+
+ ret = strict_strtoul(page, 0, &tmp);
+ if (ret < 0) {
+ printk(KERN_ERR "Unable to extract nonop_delay_msecs\n");
+ return -EINVAL;
+ }
+ if (tmp > ALUA_MAX_NONOP_DELAY_MSECS) {
+ printk(KERN_ERR "Passed nonop_delay_msecs: %lu, exceeds"
+ " ALUA_MAX_NONOP_DELAY_MSECS: %d\n", tmp,
+ ALUA_MAX_NONOP_DELAY_MSECS);
+ return -EINVAL;
+ }
+ tg_pt_gp->tg_pt_gp_nonop_delay_msecs = (int)tmp;
+
+ return count;
+}
+
+ssize_t core_alua_show_trans_delay_msecs(
+ struct t10_alua_tg_pt_gp *tg_pt_gp,
+ char *page)
+{
+ return sprintf(page, "%d\n", tg_pt_gp->tg_pt_gp_trans_delay_msecs);
+}
+
+ssize_t core_alua_store_trans_delay_msecs(
+ struct t10_alua_tg_pt_gp *tg_pt_gp,
+ const char *page,
+ size_t count)
+{
+ unsigned long tmp;
+ int ret;
+
+ ret = strict_strtoul(page, 0, &tmp);
+ if (ret < 0) {
+ printk(KERN_ERR "Unable to extract trans_delay_msecs\n");
+ return -EINVAL;
+ }
+ if (tmp > ALUA_MAX_TRANS_DELAY_MSECS) {
+ printk(KERN_ERR "Passed trans_delay_msecs: %lu, exceeds"
+ " ALUA_MAX_TRANS_DELAY_MSECS: %d\n", tmp,
+ ALUA_MAX_TRANS_DELAY_MSECS);
+ return -EINVAL;
+ }
+ tg_pt_gp->tg_pt_gp_trans_delay_msecs = (int)tmp;
+
+ return count;
+}
+
+ssize_t core_alua_show_preferred_bit(
+ struct t10_alua_tg_pt_gp *tg_pt_gp,
+ char *page)
+{
+ return sprintf(page, "%d\n", tg_pt_gp->tg_pt_gp_pref);
+}
+
+ssize_t core_alua_store_preferred_bit(
+ struct t10_alua_tg_pt_gp *tg_pt_gp,
+ const char *page,
+ size_t count)
+{
+ unsigned long tmp;
+ int ret;
+
+ ret = strict_strtoul(page, 0, &tmp);
+ if (ret < 0) {
+ printk(KERN_ERR "Unable to extract preferred ALUA value\n");
+ return -EINVAL;
+ }
+ if ((tmp != 0) && (tmp != 1)) {
+ printk(KERN_ERR "Illegal value for preferred ALUA: %lu\n", tmp);
+ return -EINVAL;
+ }
+ tg_pt_gp->tg_pt_gp_pref = (int)tmp;
+
+ return count;
+}
+
+ssize_t core_alua_show_offline_bit(struct se_lun *lun, char *page)
+{
+ if (!(lun->lun_sep))
+ return -ENODEV;
+
+ return sprintf(page, "%d\n",
+ atomic_read(&lun->lun_sep->sep_tg_pt_secondary_offline));
+}
+
+ssize_t core_alua_store_offline_bit(
+ struct se_lun *lun,
+ const char *page,
+ size_t count)
+{
+ struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem;
+ unsigned long tmp;
+ int ret;
+
+ if (!(lun->lun_sep))
+ return -ENODEV;
+
+ ret = strict_strtoul(page, 0, &tmp);
+ if (ret < 0) {
+ printk(KERN_ERR "Unable to extract alua_tg_pt_offline value\n");
+ return -EINVAL;
+ }
+ if ((tmp != 0) && (tmp != 1)) {
+ printk(KERN_ERR "Illegal value for alua_tg_pt_offline: %lu\n",
+ tmp);
+ return -EINVAL;
+ }
+ tg_pt_gp_mem = lun->lun_sep->sep_alua_tg_pt_gp_mem;
+ if (!(tg_pt_gp_mem)) {
+ printk(KERN_ERR "Unable to locate *tg_pt_gp_mem\n");
+ return -EINVAL;
+ }
+
+ ret = core_alua_set_tg_pt_secondary_state(tg_pt_gp_mem,
+ lun->lun_sep, 0, (int)tmp);
+ if (ret < 0)
+ return -EINVAL;
+
+ return count;
+}
+
+ssize_t core_alua_show_secondary_status(
+ struct se_lun *lun,
+ char *page)
+{
+ return sprintf(page, "%d\n", lun->lun_sep->sep_tg_pt_secondary_stat);
+}
+
+ssize_t core_alua_store_secondary_status(
+ struct se_lun *lun,
+ const char *page,
+ size_t count)
+{
+ unsigned long tmp;
+ int ret;
+
+ ret = strict_strtoul(page, 0, &tmp);
+ if (ret < 0) {
+ printk(KERN_ERR "Unable to extract alua_tg_pt_status\n");
+ return -EINVAL;
+ }
+ if ((tmp != ALUA_STATUS_NONE) &&
+ (tmp != ALUA_STATUS_ALTERED_BY_EXPLICT_STPG) &&
+ (tmp != ALUA_STATUS_ALTERED_BY_IMPLICT_ALUA)) {
+ printk(KERN_ERR "Illegal value for alua_tg_pt_status: %lu\n",
+ tmp);
+ return -EINVAL;
+ }
+ lun->lun_sep->sep_tg_pt_secondary_stat = (int)tmp;
+
+ return count;
+}
+
+ssize_t core_alua_show_secondary_write_metadata(
+ struct se_lun *lun,
+ char *page)
+{
+ return sprintf(page, "%d\n",
+ lun->lun_sep->sep_tg_pt_secondary_write_md);
+}
+
+ssize_t core_alua_store_secondary_write_metadata(
+ struct se_lun *lun,
+ const char *page,
+ size_t count)
+{
+ unsigned long tmp;
+ int ret;
+
+ ret = strict_strtoul(page, 0, &tmp);
+ if (ret < 0) {
+ printk(KERN_ERR "Unable to extract alua_tg_pt_write_md\n");
+ return -EINVAL;
+ }
+ if ((tmp != 0) && (tmp != 1)) {
+ printk(KERN_ERR "Illegal value for alua_tg_pt_write_md:"
+ " %lu\n", tmp);
+ return -EINVAL;
+ }
+ lun->lun_sep->sep_tg_pt_secondary_write_md = (int)tmp;
+
+ return count;
+}
+
+int core_setup_alua(struct se_device *dev, int force_pt)
+{
+ struct se_subsystem_dev *su_dev = dev->se_sub_dev;
+ struct t10_alua *alua = T10_ALUA(su_dev);
+ struct t10_alua_lu_gp_member *lu_gp_mem;
+ /*
+ * If this device is from Target_Core_Mod/pSCSI, use the ALUA logic
+ * of the Underlying SCSI hardware. In Linux/SCSI terms, this can
+ * cause a problem because libata and some SATA RAID HBAs appear
+ * under Linux/SCSI, but emulate SCSI logic themselves.
+ */
+ if (((TRANSPORT(dev)->transport_type == TRANSPORT_PLUGIN_PHBA_PDEV) &&
+ !(DEV_ATTRIB(dev)->emulate_alua)) || force_pt) {
+ alua->alua_type = SPC_ALUA_PASSTHROUGH;
+ alua->alua_state_check = &core_alua_state_check_nop;
+ printk(KERN_INFO "%s: Using SPC_ALUA_PASSTHROUGH, no ALUA"
+ " emulation\n", TRANSPORT(dev)->name);
+ return 0;
+ }
+ /*
+ * If SPC-3 or above is reported by real or emulated struct se_device,
+ * use emulated ALUA.
+ */
+ if (TRANSPORT(dev)->get_device_rev(dev) >= SCSI_3) {
+ printk(KERN_INFO "%s: Enabling ALUA Emulation for SPC-3"
+ " device\n", TRANSPORT(dev)->name);
+ /*
+ * Assoicate this struct se_device with the default ALUA
+ * LUN Group.
+ */
+ lu_gp_mem = core_alua_allocate_lu_gp_mem(dev);
+ if (IS_ERR(lu_gp_mem) || !lu_gp_mem)
+ return -1;
+
+ alua->alua_type = SPC3_ALUA_EMULATED;
+ alua->alua_state_check = &core_alua_state_check;
+ spin_lock(&lu_gp_mem->lu_gp_mem_lock);
+ __core_alua_attach_lu_gp_mem(lu_gp_mem,
+ se_global->default_lu_gp);
+ spin_unlock(&lu_gp_mem->lu_gp_mem_lock);
+
+ printk(KERN_INFO "%s: Adding to default ALUA LU Group:"
+ " core/alua/lu_gps/default_lu_gp\n",
+ TRANSPORT(dev)->name);
+ } else {
+ alua->alua_type = SPC2_ALUA_DISABLED;
+ alua->alua_state_check = &core_alua_state_check_nop;
+ printk(KERN_INFO "%s: Disabling ALUA Emulation for SPC-2"
+ " device\n", TRANSPORT(dev)->name);
+ }
+
+ return 0;
+}
diff --git a/drivers/target/target_core_alua.h b/drivers/target/target_core_alua.h
new file mode 100644
index 0000000..c86f97a
--- /dev/null
+++ b/drivers/target/target_core_alua.h
@@ -0,0 +1,126 @@
+#ifndef TARGET_CORE_ALUA_H
+#define TARGET_CORE_ALUA_H
+
+/*
+ * INQUIRY response data, TPGS Field
+ *
+ * from spc4r17 section 6.4.2 Table 135
+ */
+#define TPGS_NO_ALUA 0x00
+#define TPGS_IMPLICT_ALUA 0x10
+#define TPGS_EXPLICT_ALUA 0x20
+
+/*
+ * ASYMMETRIC ACCESS STATE field
+ *
+ * from spc4r17 section 6.27 Table 245
+ */
+#define ALUA_ACCESS_STATE_ACTIVE_OPTMIZED 0x0
+#define ALUA_ACCESS_STATE_ACTIVE_NON_OPTIMIZED 0x1
+#define ALUA_ACCESS_STATE_STANDBY 0x2
+#define ALUA_ACCESS_STATE_UNAVAILABLE 0x3
+#define ALUA_ACCESS_STATE_OFFLINE 0xe
+#define ALUA_ACCESS_STATE_TRANSITION 0xf
+
+/*
+ * REPORT_TARGET_PORT_GROUP STATUS CODE
+ *
+ * from spc4r17 section 6.27 Table 246
+ */
+#define ALUA_STATUS_NONE 0x00
+#define ALUA_STATUS_ALTERED_BY_EXPLICT_STPG 0x01
+#define ALUA_STATUS_ALTERED_BY_IMPLICT_ALUA 0x02
+
+/*
+ * From spc4r17, Table D.1: ASC and ASCQ Assignement
+ */
+#define ASCQ_04H_ALUA_STATE_TRANSITION 0x0a
+#define ASCQ_04H_ALUA_TG_PT_STANDBY 0x0b
+#define ASCQ_04H_ALUA_TG_PT_UNAVAILABLE 0x0c
+#define ASCQ_04H_ALUA_OFFLINE 0x12
+
+/*
+ * Used as the default for Active/NonOptimized delay (in milliseconds)
+ * This can also be changed via configfs on a per target port group basis..
+ */
+#define ALUA_DEFAULT_NONOP_DELAY_MSECS 100
+#define ALUA_MAX_NONOP_DELAY_MSECS 10000 /* 10 seconds */
+/*
+ * Used for implict and explict ALUA transitional delay, that is disabled
+ * by default, and is intended to be used for debugging client side ALUA code.
+ */
+#define ALUA_DEFAULT_TRANS_DELAY_MSECS 0
+#define ALUA_MAX_TRANS_DELAY_MSECS 30000 /* 30 seconds */
+/*
+ * Used by core_alua_update_tpg_primary_metadata() and
+ * core_alua_update_tpg_secondary_metadata()
+ */
+#define ALUA_METADATA_PATH_LEN 512
+/*
+ * Used by core_alua_update_tpg_secondary_metadata()
+ */
+#define ALUA_SECONDARY_METADATA_WWN_LEN 256
+
+extern struct kmem_cache *t10_alua_lu_gp_cache;
+extern struct kmem_cache *t10_alua_lu_gp_mem_cache;
+extern struct kmem_cache *t10_alua_tg_pt_gp_cache;
+extern struct kmem_cache *t10_alua_tg_pt_gp_mem_cache;
+
+extern int core_emulate_report_target_port_groups(struct se_cmd *);
+extern int core_emulate_set_target_port_groups(struct se_cmd *);
+extern int core_alua_check_nonop_delay(struct se_cmd *);
+extern int core_alua_do_port_transition(struct t10_alua_tg_pt_gp *,
+ struct se_device *, struct se_port *,
+ struct se_node_acl *, int, int);
+extern char *core_alua_dump_status(int);
+extern struct t10_alua_lu_gp *core_alua_allocate_lu_gp(const char *, int);
+extern int core_alua_set_lu_gp_id(struct t10_alua_lu_gp *, u16);
+extern void core_alua_free_lu_gp(struct t10_alua_lu_gp *);
+extern void core_alua_free_lu_gp_mem(struct se_device *);
+extern struct t10_alua_lu_gp *core_alua_get_lu_gp_by_name(const char *);
+extern void core_alua_put_lu_gp_from_name(struct t10_alua_lu_gp *);
+extern void __core_alua_attach_lu_gp_mem(struct t10_alua_lu_gp_member *,
+ struct t10_alua_lu_gp *);
+extern void __core_alua_drop_lu_gp_mem(struct t10_alua_lu_gp_member *,
+ struct t10_alua_lu_gp *);
+extern void core_alua_drop_lu_gp_dev(struct se_device *);
+extern struct t10_alua_tg_pt_gp *core_alua_allocate_tg_pt_gp(
+ struct se_subsystem_dev *, const char *, int);
+extern int core_alua_set_tg_pt_gp_id(struct t10_alua_tg_pt_gp *, u16);
+extern struct t10_alua_tg_pt_gp_member *core_alua_allocate_tg_pt_gp_mem(
+ struct se_port *);
+extern void core_alua_free_tg_pt_gp(struct t10_alua_tg_pt_gp *);
+extern void core_alua_free_tg_pt_gp_mem(struct se_port *);
+extern void __core_alua_attach_tg_pt_gp_mem(struct t10_alua_tg_pt_gp_member *,
+ struct t10_alua_tg_pt_gp *);
+extern ssize_t core_alua_show_tg_pt_gp_info(struct se_port *, char *);
+extern ssize_t core_alua_store_tg_pt_gp_info(struct se_port *, const char *,
+ size_t);
+extern ssize_t core_alua_show_access_type(struct t10_alua_tg_pt_gp *, char *);
+extern ssize_t core_alua_store_access_type(struct t10_alua_tg_pt_gp *,
+ const char *, size_t);
+extern ssize_t core_alua_show_nonop_delay_msecs(struct t10_alua_tg_pt_gp *,
+ char *);
+extern ssize_t core_alua_store_nonop_delay_msecs(struct t10_alua_tg_pt_gp *,
+ const char *, size_t);
+extern ssize_t core_alua_show_trans_delay_msecs(struct t10_alua_tg_pt_gp *,
+ char *);
+extern ssize_t core_alua_store_trans_delay_msecs(struct t10_alua_tg_pt_gp *,
+ const char *, size_t);
+extern ssize_t core_alua_show_preferred_bit(struct t10_alua_tg_pt_gp *,
+ char *);
+extern ssize_t core_alua_store_preferred_bit(struct t10_alua_tg_pt_gp *,
+ const char *, size_t);
+extern ssize_t core_alua_show_offline_bit(struct se_lun *, char *);
+extern ssize_t core_alua_store_offline_bit(struct se_lun *, const char *,
+ size_t);
+extern ssize_t core_alua_show_secondary_status(struct se_lun *, char *);
+extern ssize_t core_alua_store_secondary_status(struct se_lun *,
+ const char *, size_t);
+extern ssize_t core_alua_show_secondary_write_metadata(struct se_lun *,
+ char *);
+extern ssize_t core_alua_store_secondary_write_metadata(struct se_lun *,
+ const char *, size_t);
+extern int core_setup_alua(struct se_device *, int);
+
+#endif /* TARGET_CORE_ALUA_H */
diff --git a/drivers/target/target_core_cdb.c b/drivers/target/target_core_cdb.c
new file mode 100644
index 0000000..366080b
--- /dev/null
+++ b/drivers/target/target_core_cdb.c
@@ -0,0 +1,1131 @@
+/*
+ * CDB emulation for non-READ/WRITE commands.
+ *
+ * Copyright (c) 2002, 2003, 2004, 2005 PyX Technologies, Inc.
+ * Copyright (c) 2005, 2006, 2007 SBE, Inc.
+ * Copyright (c) 2007-2010 Rising Tide Systems
+ * Copyright (c) 2008-2010 Linux-iSCSI.org
+ *
+ * Nicholas A. Bellinger <nab@kernel.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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <asm/unaligned.h>
+#include <scsi/scsi.h>
+
+#include <target/target_core_base.h>
+#include <target/target_core_transport.h>
+#include <target/target_core_fabric_ops.h>
+#include "target_core_ua.h"
+
+static void
+target_fill_alua_data(struct se_port *port, unsigned char *buf)
+{
+ struct t10_alua_tg_pt_gp *tg_pt_gp;
+ struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem;
+
+ /*
+ * Set SCCS for MAINTENANCE_IN + REPORT_TARGET_PORT_GROUPS.
+ */
+ buf[5] = 0x80;
+
+ /*
+ * Set TPGS field for explict and/or implict ALUA access type
+ * and opteration.
+ *
+ * See spc4r17 section 6.4.2 Table 135
+ */
+ if (!port)
+ return;
+ tg_pt_gp_mem = port->sep_alua_tg_pt_gp_mem;
+ if (!tg_pt_gp_mem)
+ return;
+
+ spin_lock(&tg_pt_gp_mem->tg_pt_gp_mem_lock);
+ tg_pt_gp = tg_pt_gp_mem->tg_pt_gp;
+ if (tg_pt_gp)
+ buf[5] |= tg_pt_gp->tg_pt_gp_alua_access_type;
+ spin_unlock(&tg_pt_gp_mem->tg_pt_gp_mem_lock);
+}
+
+static int
+target_emulate_inquiry_std(struct se_cmd *cmd)
+{
+ struct se_lun *lun = SE_LUN(cmd);
+ struct se_device *dev = SE_DEV(cmd);
+ unsigned char *buf = cmd->t_task->t_task_buf;
+
+ /*
+ * Make sure we at least have 6 bytes of INQUIRY response
+ * payload going back for EVPD=0
+ */
+ if (cmd->data_length < 6) {
+ printk(KERN_ERR "SCSI Inquiry payload length: %u"
+ " too small for EVPD=0\n", cmd->data_length);
+ return -1;
+ }
+
+ buf[0] = dev->transport->get_device_type(dev);
+ if (buf[0] == TYPE_TAPE)
+ buf[1] = 0x80;
+ buf[2] = dev->transport->get_device_rev(dev);
+
+ /*
+ * Enable SCCS and TPGS fields for Emulated ALUA
+ */
+ if (T10_ALUA(dev->se_sub_dev)->alua_type == SPC3_ALUA_EMULATED)
+ target_fill_alua_data(lun->lun_sep, buf);
+
+ if (cmd->data_length < 8) {
+ buf[4] = 1; /* Set additional length to 1 */
+ return 0;
+ }
+
+ buf[7] = 0x32; /* Sync=1 and CmdQue=1 */
+
+ /*
+ * Do not include vendor, product, reversion info in INQUIRY
+ * response payload for cdbs with a small allocation length.
+ */
+ if (cmd->data_length < 36) {
+ buf[4] = 3; /* Set additional length to 3 */
+ return 0;
+ }
+
+ snprintf((unsigned char *)&buf[8], 8, "LIO-ORG");
+ snprintf((unsigned char *)&buf[16], 16, "%s",
+ &DEV_T10_WWN(dev)->model[0]);
+ snprintf((unsigned char *)&buf[32], 4, "%s",
+ &DEV_T10_WWN(dev)->revision[0]);
+ buf[4] = 31; /* Set additional length to 31 */
+ return 0;
+}
+
+/* supported vital product data pages */
+static int
+target_emulate_evpd_00(struct se_cmd *cmd, unsigned char *buf)
+{
+ buf[1] = 0x00;
+ if (cmd->data_length < 8)
+ return 0;
+
+ buf[4] = 0x0;
+ /*
+ * Only report the INQUIRY EVPD=1 pages after a valid NAA
+ * Registered Extended LUN WWN has been set via ConfigFS
+ * during device creation/restart.
+ */
+ if (SE_DEV(cmd)->se_sub_dev->su_dev_flags &
+ SDF_EMULATED_VPD_UNIT_SERIAL) {
+ buf[3] = 3;
+ buf[5] = 0x80;
+ buf[6] = 0x83;
+ buf[7] = 0x86;
+ }
+
+ return 0;
+}
+
+/* unit serial number */
+static int
+target_emulate_evpd_80(struct se_cmd *cmd, unsigned char *buf)
+{
+ struct se_device *dev = SE_DEV(cmd);
+ u16 len = 0;
+
+ buf[1] = 0x80;
+ if (dev->se_sub_dev->su_dev_flags &
+ SDF_EMULATED_VPD_UNIT_SERIAL) {
+ u32 unit_serial_len;
+
+ unit_serial_len =
+ strlen(&DEV_T10_WWN(dev)->unit_serial[0]);
+ unit_serial_len++; /* For NULL Terminator */
+
+ if (((len + 4) + unit_serial_len) > cmd->data_length) {
+ len += unit_serial_len;
+ buf[2] = ((len >> 8) & 0xff);
+ buf[3] = (len & 0xff);
+ return 0;
+ }
+ len += sprintf((unsigned char *)&buf[4], "%s",
+ &DEV_T10_WWN(dev)->unit_serial[0]);
+ len++; /* Extra Byte for NULL Terminator */
+ buf[3] = len;
+ }
+ return 0;
+}
+
+/*
+ * Device identification VPD, for a complete list of
+ * DESIGNATOR TYPEs see spc4r17 Table 459.
+ */
+static int
+target_emulate_evpd_83(struct se_cmd *cmd, unsigned char *buf)
+{
+ struct se_device *dev = SE_DEV(cmd);
+ struct se_lun *lun = SE_LUN(cmd);
+ struct se_port *port = NULL;
+ struct se_portal_group *tpg = NULL;
+ struct t10_alua_lu_gp_member *lu_gp_mem;
+ struct t10_alua_tg_pt_gp *tg_pt_gp;
+ struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem;
+ unsigned char binary, binary_new;
+ unsigned char *prod = &DEV_T10_WWN(dev)->model[0];
+ u32 prod_len;
+ u32 unit_serial_len, off = 0;
+ int i;
+ u16 len = 0, id_len;
+
+ buf[1] = 0x83;
+ off = 4;
+
+ /*
+ * NAA IEEE Registered Extended Assigned designator format, see
+ * spc4r17 section 7.7.3.6.5
+ *
+ * We depend upon a target_core_mod/ConfigFS provided
+ * /sys/kernel/config/target/core/$HBA/$DEV/wwn/vpd_unit_serial
+ * value in order to return the NAA id.
+ */
+ if (!(dev->se_sub_dev->su_dev_flags & SDF_EMULATED_VPD_UNIT_SERIAL))
+ goto check_t10_vend_desc;
+
+ if (off + 20 > cmd->data_length)
+ goto check_t10_vend_desc;
+
+ /* CODE SET == Binary */
+ buf[off++] = 0x1;
+
+ /* Set ASSOICATION == addressed logical unit: 0)b */
+ buf[off] = 0x00;
+
+ /* Identifier/Designator type == NAA identifier */
+ buf[off++] = 0x3;
+ off++;
+
+ /* Identifier/Designator length */
+ buf[off++] = 0x10;
+
+ /*
+ * Start NAA IEEE Registered Extended Identifier/Designator
+ */
+ buf[off++] = (0x6 << 4);
+
+ /*
+ * Use OpenFabrics IEEE Company ID: 00 14 05
+ */
+ buf[off++] = 0x01;
+ buf[off++] = 0x40;
+ buf[off] = (0x5 << 4);
+
+ /*
+ * Return ConfigFS Unit Serial Number information for
+ * VENDOR_SPECIFIC_IDENTIFIER and
+ * VENDOR_SPECIFIC_IDENTIFIER_EXTENTION
+ */
+ binary = transport_asciihex_to_binaryhex(
+ &DEV_T10_WWN(dev)->unit_serial[0]);
+ buf[off++] |= (binary & 0xf0) >> 4;
+ for (i = 0; i < 24; i += 2) {
+ binary_new = transport_asciihex_to_binaryhex(
+ &DEV_T10_WWN(dev)->unit_serial[i+2]);
+ buf[off] = (binary & 0x0f) << 4;
+ buf[off++] |= (binary_new & 0xf0) >> 4;
+ binary = binary_new;
+ }
+ len = 20;
+ off = (len + 4);
+
+check_t10_vend_desc:
+ /*
+ * T10 Vendor Identifier Page, see spc4r17 section 7.7.3.4
+ */
+ id_len = 8; /* For Vendor field */
+ prod_len = 4; /* For VPD Header */
+ prod_len += 8; /* For Vendor field */
+ prod_len += strlen(prod);
+ prod_len++; /* For : */
+
+ if (dev->se_sub_dev->su_dev_flags &
+ SDF_EMULATED_VPD_UNIT_SERIAL) {
+ unit_serial_len =
+ strlen(&DEV_T10_WWN(dev)->unit_serial[0]);
+ unit_serial_len++; /* For NULL Terminator */
+
+ if ((len + (id_len + 4) +
+ (prod_len + unit_serial_len)) >
+ cmd->data_length) {
+ len += (prod_len + unit_serial_len);
+ goto check_port;
+ }
+ id_len += sprintf((unsigned char *)&buf[off+12],
+ "%s:%s", prod,
+ &DEV_T10_WWN(dev)->unit_serial[0]);
+ }
+ buf[off] = 0x2; /* ASCII */
+ buf[off+1] = 0x1; /* T10 Vendor ID */
+ buf[off+2] = 0x0;
+ memcpy((unsigned char *)&buf[off+4], "LIO-ORG", 8);
+ /* Extra Byte for NULL Terminator */
+ id_len++;
+ /* Identifier Length */
+ buf[off+3] = id_len;
+ /* Header size for Designation descriptor */
+ len += (id_len + 4);
+ off += (id_len + 4);
+ /*
+ * struct se_port is only set for INQUIRY VPD=1 through $FABRIC_MOD
+ */
+check_port:
+ port = lun->lun_sep;
+ if (port) {
+ struct t10_alua_lu_gp *lu_gp;
+ u32 padding, scsi_name_len;
+ u16 lu_gp_id = 0;
+ u16 tg_pt_gp_id = 0;
+ u16 tpgt;
+
+ tpg = port->sep_tpg;
+ /*
+ * Relative target port identifer, see spc4r17
+ * section 7.7.3.7
+ *
+ * Get the PROTOCOL IDENTIFIER as defined by spc4r17
+ * section 7.5.1 Table 362
+ */
+ if (((len + 4) + 8) > cmd->data_length) {
+ len += 8;
+ goto check_tpgi;
+ }
+ buf[off] =
+ (TPG_TFO(tpg)->get_fabric_proto_ident(tpg) << 4);
+ buf[off++] |= 0x1; /* CODE SET == Binary */
+ buf[off] = 0x80; /* Set PIV=1 */
+ /* Set ASSOICATION == target port: 01b */
+ buf[off] |= 0x10;
+ /* DESIGNATOR TYPE == Relative target port identifer */
+ buf[off++] |= 0x4;
+ off++; /* Skip over Reserved */
+ buf[off++] = 4; /* DESIGNATOR LENGTH */
+ /* Skip over Obsolete field in RTPI payload
+ * in Table 472 */
+ off += 2;
+ buf[off++] = ((port->sep_rtpi >> 8) & 0xff);
+ buf[off++] = (port->sep_rtpi & 0xff);
+ len += 8; /* Header size + Designation descriptor */
+ /*
+ * Target port group identifier, see spc4r17
+ * section 7.7.3.8
+ *
+ * Get the PROTOCOL IDENTIFIER as defined by spc4r17
+ * section 7.5.1 Table 362
+ */
+check_tpgi:
+ if (T10_ALUA(dev->se_sub_dev)->alua_type !=
+ SPC3_ALUA_EMULATED)
+ goto check_scsi_name;
+
+ if (((len + 4) + 8) > cmd->data_length) {
+ len += 8;
+ goto check_lu_gp;
+ }
+ tg_pt_gp_mem = port->sep_alua_tg_pt_gp_mem;
+ if (!tg_pt_gp_mem)
+ goto check_lu_gp;
+
+ spin_lock(&tg_pt_gp_mem->tg_pt_gp_mem_lock);
+ tg_pt_gp = tg_pt_gp_mem->tg_pt_gp;
+ if (!(tg_pt_gp)) {
+ spin_unlock(&tg_pt_gp_mem->tg_pt_gp_mem_lock);
+ goto check_lu_gp;
+ }
+ tg_pt_gp_id = tg_pt_gp->tg_pt_gp_id;
+ spin_unlock(&tg_pt_gp_mem->tg_pt_gp_mem_lock);
+
+ buf[off] =
+ (TPG_TFO(tpg)->get_fabric_proto_ident(tpg) << 4);
+ buf[off++] |= 0x1; /* CODE SET == Binary */
+ buf[off] = 0x80; /* Set PIV=1 */
+ /* Set ASSOICATION == target port: 01b */
+ buf[off] |= 0x10;
+ /* DESIGNATOR TYPE == Target port group identifier */
+ buf[off++] |= 0x5;
+ off++; /* Skip over Reserved */
+ buf[off++] = 4; /* DESIGNATOR LENGTH */
+ off += 2; /* Skip over Reserved Field */
+ buf[off++] = ((tg_pt_gp_id >> 8) & 0xff);
+ buf[off++] = (tg_pt_gp_id & 0xff);
+ len += 8; /* Header size + Designation descriptor */
+ /*
+ * Logical Unit Group identifier, see spc4r17
+ * section 7.7.3.8
+ */
+check_lu_gp:
+ if (((len + 4) + 8) > cmd->data_length) {
+ len += 8;
+ goto check_scsi_name;
+ }
+ lu_gp_mem = dev->dev_alua_lu_gp_mem;
+ if (!(lu_gp_mem))
+ goto check_scsi_name;
+
+ spin_lock(&lu_gp_mem->lu_gp_mem_lock);
+ lu_gp = lu_gp_mem->lu_gp;
+ if (!(lu_gp)) {
+ spin_unlock(&lu_gp_mem->lu_gp_mem_lock);
+ goto check_scsi_name;
+ }
+ lu_gp_id = lu_gp->lu_gp_id;
+ spin_unlock(&lu_gp_mem->lu_gp_mem_lock);
+
+ buf[off++] |= 0x1; /* CODE SET == Binary */
+ /* DESIGNATOR TYPE == Logical Unit Group identifier */
+ buf[off++] |= 0x6;
+ off++; /* Skip over Reserved */
+ buf[off++] = 4; /* DESIGNATOR LENGTH */
+ off += 2; /* Skip over Reserved Field */
+ buf[off++] = ((lu_gp_id >> 8) & 0xff);
+ buf[off++] = (lu_gp_id & 0xff);
+ len += 8; /* Header size + Designation descriptor */
+ /*
+ * SCSI name string designator, see spc4r17
+ * section 7.7.3.11
+ *
+ * Get the PROTOCOL IDENTIFIER as defined by spc4r17
+ * section 7.5.1 Table 362
+ */
+check_scsi_name:
+ scsi_name_len = strlen(TPG_TFO(tpg)->tpg_get_wwn(tpg));
+ /* UTF-8 ",t,0x<16-bit TPGT>" + NULL Terminator */
+ scsi_name_len += 10;
+ /* Check for 4-byte padding */
+ padding = ((-scsi_name_len) & 3);
+ if (padding != 0)
+ scsi_name_len += padding;
+ /* Header size + Designation descriptor */
+ scsi_name_len += 4;
+
+ if (((len + 4) + scsi_name_len) > cmd->data_length) {
+ len += scsi_name_len;
+ goto set_len;
+ }
+ buf[off] =
+ (TPG_TFO(tpg)->get_fabric_proto_ident(tpg) << 4);
+ buf[off++] |= 0x3; /* CODE SET == UTF-8 */
+ buf[off] = 0x80; /* Set PIV=1 */
+ /* Set ASSOICATION == target port: 01b */
+ buf[off] |= 0x10;
+ /* DESIGNATOR TYPE == SCSI name string */
+ buf[off++] |= 0x8;
+ off += 2; /* Skip over Reserved and length */
+ /*
+ * SCSI name string identifer containing, $FABRIC_MOD
+ * dependent information. For LIO-Target and iSCSI
+ * Target Port, this means "<iSCSI name>,t,0x<TPGT> in
+ * UTF-8 encoding.
+ */
+ tpgt = TPG_TFO(tpg)->tpg_get_tag(tpg);
+ scsi_name_len = sprintf(&buf[off], "%s,t,0x%04x",
+ TPG_TFO(tpg)->tpg_get_wwn(tpg), tpgt);
+ scsi_name_len += 1 /* Include NULL terminator */;
+ /*
+ * The null-terminated, null-padded (see 4.4.2) SCSI
+ * NAME STRING field contains a UTF-8 format string.
+ * The number of bytes in the SCSI NAME STRING field
+ * (i.e., the value in the DESIGNATOR LENGTH field)
+ * shall be no larger than 256 and shall be a multiple
+ * of four.
+ */
+ if (padding)
+ scsi_name_len += padding;
+
+ buf[off-1] = scsi_name_len;
+ off += scsi_name_len;
+ /* Header size + Designation descriptor */
+ len += (scsi_name_len + 4);
+ }
+set_len:
+ buf[2] = ((len >> 8) & 0xff);
+ buf[3] = (len & 0xff); /* Page Length for VPD 0x83 */
+ return 0;
+}
+
+/* Extended INQUIRY Data VPD Page */
+static int
+target_emulate_evpd_86(struct se_cmd *cmd, unsigned char *buf)
+{
+ if (cmd->data_length < 60)
+ return 0;
+
+ buf[1] = 0x86;
+ buf[2] = 0x3c;
+ /* Set HEADSUP, ORDSUP, SIMPSUP */
+ buf[5] = 0x07;
+
+ /* If WriteCache emulation is enabled, set V_SUP */
+ if (DEV_ATTRIB(SE_DEV(cmd))->emulate_write_cache > 0)
+ buf[6] = 0x01;
+ return 0;
+}
+
+/* Block Limits VPD page */
+static int
+target_emulate_evpd_b0(struct se_cmd *cmd, unsigned char *buf)
+{
+ struct se_device *dev = SE_DEV(cmd);
+ int have_tp = 0;
+
+ /*
+ * Following sbc3r22 section 6.5.3 Block Limits VPD page, when
+ * emulate_tpu=1 or emulate_tpws=1 we will be expect a
+ * different page length for Thin Provisioning.
+ */
+ if (DEV_ATTRIB(dev)->emulate_tpu || DEV_ATTRIB(dev)->emulate_tpws)
+ have_tp = 1;
+
+ if (cmd->data_length < (0x10 + 4)) {
+ printk(KERN_INFO "Received data_length: %u"
+ " too small for EVPD 0xb0\n",
+ cmd->data_length);
+ return -1;
+ }
+
+ if (have_tp && cmd->data_length < (0x3c + 4)) {
+ printk(KERN_INFO "Received data_length: %u"
+ " too small for TPE=1 EVPD 0xb0\n",
+ cmd->data_length);
+ have_tp = 0;
+ }
+
+ buf[0] = dev->transport->get_device_type(dev);
+ buf[1] = 0xb0;
+ buf[3] = have_tp ? 0x3c : 0x10;
+
+ /*
+ * Set OPTIMAL TRANSFER LENGTH GRANULARITY
+ */
+ put_unaligned_be16(1, &buf[6]);
+
+ /*
+ * Set MAXIMUM TRANSFER LENGTH
+ */
+ put_unaligned_be32(DEV_ATTRIB(dev)->max_sectors, &buf[8]);
+
+ /*
+ * Set OPTIMAL TRANSFER LENGTH
+ */
+ put_unaligned_be32(DEV_ATTRIB(dev)->optimal_sectors, &buf[12]);
+
+ /*
+ * Exit now if we don't support TP or the initiator sent a too
+ * short buffer.
+ */
+ if (!have_tp || cmd->data_length < (0x3c + 4))
+ return 0;
+
+ /*
+ * Set MAXIMUM UNMAP LBA COUNT
+ */
+ put_unaligned_be32(DEV_ATTRIB(dev)->max_unmap_lba_count, &buf[20]);
+
+ /*
+ * Set MAXIMUM UNMAP BLOCK DESCRIPTOR COUNT
+ */
+ put_unaligned_be32(DEV_ATTRIB(dev)->max_unmap_block_desc_count,
+ &buf[24]);
+
+ /*
+ * Set OPTIMAL UNMAP GRANULARITY
+ */
+ put_unaligned_be32(DEV_ATTRIB(dev)->unmap_granularity, &buf[28]);
+
+ /*
+ * UNMAP GRANULARITY ALIGNMENT
+ */
+ put_unaligned_be32(DEV_ATTRIB(dev)->unmap_granularity_alignment,
+ &buf[32]);
+ if (DEV_ATTRIB(dev)->unmap_granularity_alignment != 0)
+ buf[32] |= 0x80; /* Set the UGAVALID bit */
+
+ return 0;
+}
+
+/* Thin Provisioning VPD */
+static int
+target_emulate_evpd_b2(struct se_cmd *cmd, unsigned char *buf)
+{
+ struct se_device *dev = SE_DEV(cmd);
+
+ /*
+ * From sbc3r22 section 6.5.4 Thin Provisioning VPD page:
+ *
+ * The PAGE LENGTH field is defined in SPC-4. If the DP bit is set to
+ * zero, then the page length shall be set to 0004h. If the DP bit
+ * is set to one, then the page length shall be set to the value
+ * defined in table 162.
+ */
+ buf[0] = dev->transport->get_device_type(dev);
+ buf[1] = 0xb2;
+
+ /*
+ * Set Hardcoded length mentioned above for DP=0
+ */
+ put_unaligned_be16(0x0004, &buf[2]);
+
+ /*
+ * The THRESHOLD EXPONENT field indicates the threshold set size in
+ * LBAs as a power of 2 (i.e., the threshold set size is equal to
+ * 2(threshold exponent)).
+ *
+ * Note that this is currently set to 0x00 as mkp says it will be
+ * changing again. We can enable this once it has settled in T10
+ * and is actually used by Linux/SCSI ML code.
+ */
+ buf[4] = 0x00;
+
+ /*
+ * A TPU bit set to one indicates that the device server supports
+ * the UNMAP command (see 5.25). A TPU bit set to zero indicates
+ * that the device server does not support the UNMAP command.
+ */
+ if (DEV_ATTRIB(dev)->emulate_tpu != 0)
+ buf[5] = 0x80;
+
+ /*
+ * A TPWS bit set to one indicates that the device server supports
+ * the use of the WRITE SAME (16) command (see 5.42) to unmap LBAs.
+ * A TPWS bit set to zero indicates that the device server does not
+ * support the use of the WRITE SAME (16) command to unmap LBAs.
+ */
+ if (DEV_ATTRIB(dev)->emulate_tpws != 0)
+ buf[5] |= 0x40;
+
+ return 0;
+}
+
+static int
+target_emulate_inquiry(struct se_cmd *cmd)
+{
+ struct se_device *dev = SE_DEV(cmd);
+ unsigned char *buf = cmd->t_task->t_task_buf;
+ unsigned char *cdb = cmd->t_task->t_task_cdb;
+
+ if (!(cdb[1] & 0x1))
+ return target_emulate_inquiry_std(cmd);
+
+ /*
+ * Make sure we at least have 4 bytes of INQUIRY response
+ * payload for 0x00 going back for EVPD=1. Note that 0x80
+ * and 0x83 will check for enough payload data length and
+ * jump to set_len: label when there is not enough inquiry EVPD
+ * payload length left for the next outgoing EVPD metadata
+ */
+ if (cmd->data_length < 4) {
+ printk(KERN_ERR "SCSI Inquiry payload length: %u"
+ " too small for EVPD=1\n", cmd->data_length);
+ return -1;
+ }
+ buf[0] = dev->transport->get_device_type(dev);
+
+ switch (cdb[2]) {
+ case 0x00:
+ return target_emulate_evpd_00(cmd, buf);
+ case 0x80:
+ return target_emulate_evpd_80(cmd, buf);
+ case 0x83:
+ return target_emulate_evpd_83(cmd, buf);
+ case 0x86:
+ return target_emulate_evpd_86(cmd, buf);
+ case 0xb0:
+ return target_emulate_evpd_b0(cmd, buf);
+ case 0xb2:
+ return target_emulate_evpd_b2(cmd, buf);
+ default:
+ printk(KERN_ERR "Unknown VPD Code: 0x%02x\n", cdb[2]);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+target_emulate_readcapacity(struct se_cmd *cmd)
+{
+ struct se_device *dev = SE_DEV(cmd);
+ unsigned char *buf = cmd->t_task->t_task_buf;
+ u32 blocks = dev->transport->get_blocks(dev);
+
+ buf[0] = (blocks >> 24) & 0xff;
+ buf[1] = (blocks >> 16) & 0xff;
+ buf[2] = (blocks >> 8) & 0xff;
+ buf[3] = blocks & 0xff;
+ buf[4] = (DEV_ATTRIB(dev)->block_size >> 24) & 0xff;
+ buf[5] = (DEV_ATTRIB(dev)->block_size >> 16) & 0xff;
+ buf[6] = (DEV_ATTRIB(dev)->block_size >> 8) & 0xff;
+ buf[7] = DEV_ATTRIB(dev)->block_size & 0xff;
+ /*
+ * Set max 32-bit blocks to signal SERVICE ACTION READ_CAPACITY_16
+ */
+ if (DEV_ATTRIB(dev)->emulate_tpu || DEV_ATTRIB(dev)->emulate_tpws)
+ put_unaligned_be32(0xFFFFFFFF, &buf[0]);
+
+ return 0;
+}
+
+static int
+target_emulate_readcapacity_16(struct se_cmd *cmd)
+{
+ struct se_device *dev = SE_DEV(cmd);
+ unsigned char *buf = cmd->t_task->t_task_buf;
+ unsigned long long blocks = dev->transport->get_blocks(dev);
+
+ buf[0] = (blocks >> 56) & 0xff;
+ buf[1] = (blocks >> 48) & 0xff;
+ buf[2] = (blocks >> 40) & 0xff;
+ buf[3] = (blocks >> 32) & 0xff;
+ buf[4] = (blocks >> 24) & 0xff;
+ buf[5] = (blocks >> 16) & 0xff;
+ buf[6] = (blocks >> 8) & 0xff;
+ buf[7] = blocks & 0xff;
+ buf[8] = (DEV_ATTRIB(dev)->block_size >> 24) & 0xff;
+ buf[9] = (DEV_ATTRIB(dev)->block_size >> 16) & 0xff;
+ buf[10] = (DEV_ATTRIB(dev)->block_size >> 8) & 0xff;
+ buf[11] = DEV_ATTRIB(dev)->block_size & 0xff;
+ /*
+ * Set Thin Provisioning Enable bit following sbc3r22 in section
+ * READ CAPACITY (16) byte 14 if emulate_tpu or emulate_tpws is enabled.
+ */
+ if (DEV_ATTRIB(dev)->emulate_tpu || DEV_ATTRIB(dev)->emulate_tpws)
+ buf[14] = 0x80;
+
+ return 0;
+}
+
+static int
+target_modesense_rwrecovery(unsigned char *p)
+{
+ p[0] = 0x01;
+ p[1] = 0x0a;
+
+ return 12;
+}
+
+static int
+target_modesense_control(struct se_device *dev, unsigned char *p)
+{
+ p[0] = 0x0a;
+ p[1] = 0x0a;
+ p[2] = 2;
+ /*
+ * From spc4r17, section 7.4.6 Control mode Page
+ *
+ * Unit Attention interlocks control (UN_INTLCK_CTRL) to code 00b
+ *
+ * 00b: The logical unit shall clear any unit attention condition
+ * reported in the same I_T_L_Q nexus transaction as a CHECK CONDITION
+ * status and shall not establish a unit attention condition when a com-
+ * mand is completed with BUSY, TASK SET FULL, or RESERVATION CONFLICT
+ * status.
+ *
+ * 10b: The logical unit shall not clear any unit attention condition
+ * reported in the same I_T_L_Q nexus transaction as a CHECK CONDITION
+ * status and shall not establish a unit attention condition when
+ * a command is completed with BUSY, TASK SET FULL, or RESERVATION
+ * CONFLICT status.
+ *
+ * 11b a The logical unit shall not clear any unit attention condition
+ * reported in the same I_T_L_Q nexus transaction as a CHECK CONDITION
+ * status and shall establish a unit attention condition for the
+ * initiator port associated with the I_T nexus on which the BUSY,
+ * TASK SET FULL, or RESERVATION CONFLICT status is being returned.
+ * Depending on the status, the additional sense code shall be set to
+ * PREVIOUS BUSY STATUS, PREVIOUS TASK SET FULL STATUS, or PREVIOUS
+ * RESERVATION CONFLICT STATUS. Until it is cleared by a REQUEST SENSE
+ * command, a unit attention condition shall be established only once
+ * for a BUSY, TASK SET FULL, or RESERVATION CONFLICT status regardless
+ * to the number of commands completed with one of those status codes.
+ */
+ p[4] = (DEV_ATTRIB(dev)->emulate_ua_intlck_ctrl == 2) ? 0x30 :
+ (DEV_ATTRIB(dev)->emulate_ua_intlck_ctrl == 1) ? 0x20 : 0x00;
+ /*
+ * From spc4r17, section 7.4.6 Control mode Page
+ *
+ * Task Aborted Status (TAS) bit set to zero.
+ *
+ * A task aborted status (TAS) bit set to zero specifies that aborted
+ * tasks shall be terminated by the device server without any response
+ * to the application client. A TAS bit set to one specifies that tasks
+ * aborted by the actions of an I_T nexus other than the I_T nexus on
+ * which the command was received shall be completed with TASK ABORTED
+ * status (see SAM-4).
+ */
+ p[5] = (DEV_ATTRIB(dev)->emulate_tas) ? 0x40 : 0x00;
+ p[8] = 0xff;
+ p[9] = 0xff;
+ p[11] = 30;
+
+ return 12;
+}
+
+static int
+target_modesense_caching(struct se_device *dev, unsigned char *p)
+{
+ p[0] = 0x08;
+ p[1] = 0x12;
+ if (DEV_ATTRIB(dev)->emulate_write_cache > 0)
+ p[2] = 0x04; /* Write Cache Enable */
+ p[12] = 0x20; /* Disabled Read Ahead */
+
+ return 20;
+}
+
+static void
+target_modesense_write_protect(unsigned char *buf, int type)
+{
+ /*
+ * I believe that the WP bit (bit 7) in the mode header is the same for
+ * all device types..
+ */
+ switch (type) {
+ case TYPE_DISK:
+ case TYPE_TAPE:
+ default:
+ buf[0] |= 0x80; /* WP bit */
+ break;
+ }
+}
+
+static void
+target_modesense_dpofua(unsigned char *buf, int type)
+{
+ switch (type) {
+ case TYPE_DISK:
+ buf[0] |= 0x10; /* DPOFUA bit */
+ break;
+ default:
+ break;
+ }
+}
+
+static int
+target_emulate_modesense(struct se_cmd *cmd, int ten)
+{
+ struct se_device *dev = SE_DEV(cmd);
+ char *cdb = cmd->t_task->t_task_cdb;
+ unsigned char *rbuf = cmd->t_task->t_task_buf;
+ int type = dev->transport->get_device_type(dev);
+ int offset = (ten) ? 8 : 4;
+ int length = 0;
+ unsigned char buf[SE_MODE_PAGE_BUF];
+
+ memset(buf, 0, SE_MODE_PAGE_BUF);
+
+ switch (cdb[2] & 0x3f) {
+ case 0x01:
+ length = target_modesense_rwrecovery(&buf[offset]);
+ break;
+ case 0x08:
+ length = target_modesense_caching(dev, &buf[offset]);
+ break;
+ case 0x0a:
+ length = target_modesense_control(dev, &buf[offset]);
+ break;
+ case 0x3f:
+ length = target_modesense_rwrecovery(&buf[offset]);
+ length += target_modesense_caching(dev, &buf[offset+length]);
+ length += target_modesense_control(dev, &buf[offset+length]);
+ break;
+ default:
+ printk(KERN_ERR "Got Unknown Mode Page: 0x%02x\n",
+ cdb[2] & 0x3f);
+ return PYX_TRANSPORT_UNKNOWN_MODE_PAGE;
+ }
+ offset += length;
+
+ if (ten) {
+ offset -= 2;
+ buf[0] = (offset >> 8) & 0xff;
+ buf[1] = offset & 0xff;
+
+ if ((SE_LUN(cmd)->lun_access & TRANSPORT_LUNFLAGS_READ_ONLY) ||
+ (cmd->se_deve &&
+ (cmd->se_deve->lun_flags & TRANSPORT_LUNFLAGS_READ_ONLY)))
+ target_modesense_write_protect(&buf[3], type);
+
+ if ((DEV_ATTRIB(dev)->emulate_write_cache > 0) &&
+ (DEV_ATTRIB(dev)->emulate_fua_write > 0))
+ target_modesense_dpofua(&buf[3], type);
+
+ if ((offset + 2) > cmd->data_length)
+ offset = cmd->data_length;
+
+ } else {
+ offset -= 1;
+ buf[0] = offset & 0xff;
+
+ if ((SE_LUN(cmd)->lun_access & TRANSPORT_LUNFLAGS_READ_ONLY) ||
+ (cmd->se_deve &&
+ (cmd->se_deve->lun_flags & TRANSPORT_LUNFLAGS_READ_ONLY)))
+ target_modesense_write_protect(&buf[2], type);
+
+ if ((DEV_ATTRIB(dev)->emulate_write_cache > 0) &&
+ (DEV_ATTRIB(dev)->emulate_fua_write > 0))
+ target_modesense_dpofua(&buf[2], type);
+
+ if ((offset + 1) > cmd->data_length)
+ offset = cmd->data_length;
+ }
+ memcpy(rbuf, buf, offset);
+
+ return 0;
+}
+
+static int
+target_emulate_request_sense(struct se_cmd *cmd)
+{
+ unsigned char *cdb = cmd->t_task->t_task_cdb;
+ unsigned char *buf = cmd->t_task->t_task_buf;
+ u8 ua_asc = 0, ua_ascq = 0;
+
+ if (cdb[1] & 0x01) {
+ printk(KERN_ERR "REQUEST_SENSE description emulation not"
+ " supported\n");
+ return PYX_TRANSPORT_INVALID_CDB_FIELD;
+ }
+ if (!(core_scsi3_ua_clear_for_request_sense(cmd, &ua_asc, &ua_ascq))) {
+ /*
+ * CURRENT ERROR, UNIT ATTENTION
+ */
+ buf[0] = 0x70;
+ buf[SPC_SENSE_KEY_OFFSET] = UNIT_ATTENTION;
+ /*
+ * Make sure request data length is enough for additional
+ * sense data.
+ */
+ if (cmd->data_length <= 18) {
+ buf[7] = 0x00;
+ return 0;
+ }
+ /*
+ * The Additional Sense Code (ASC) from the UNIT ATTENTION
+ */
+ buf[SPC_ASC_KEY_OFFSET] = ua_asc;
+ buf[SPC_ASCQ_KEY_OFFSET] = ua_ascq;
+ buf[7] = 0x0A;
+ } else {
+ /*
+ * CURRENT ERROR, NO SENSE
+ */
+ buf[0] = 0x70;
+ buf[SPC_SENSE_KEY_OFFSET] = NO_SENSE;
+ /*
+ * Make sure request data length is enough for additional
+ * sense data.
+ */
+ if (cmd->data_length <= 18) {
+ buf[7] = 0x00;
+ return 0;
+ }
+ /*
+ * NO ADDITIONAL SENSE INFORMATION
+ */
+ buf[SPC_ASC_KEY_OFFSET] = 0x00;
+ buf[7] = 0x0A;
+ }
+
+ return 0;
+}
+
+/*
+ * Used for TCM/IBLOCK and TCM/FILEIO for block/blk-lib.c level discard support.
+ * Note this is not used for TCM/pSCSI passthrough
+ */
+static int
+target_emulate_unmap(struct se_task *task)
+{
+ struct se_cmd *cmd = TASK_CMD(task);
+ struct se_device *dev = SE_DEV(cmd);
+ unsigned char *buf = cmd->t_task->t_task_buf, *ptr = NULL;
+ unsigned char *cdb = &cmd->t_task->t_task_cdb[0];
+ sector_t lba;
+ unsigned int size = cmd->data_length, range;
+ int ret, offset;
+ unsigned short dl, bd_dl;
+
+ /* First UNMAP block descriptor starts at 8 byte offset */
+ offset = 8;
+ size -= 8;
+ dl = get_unaligned_be16(&cdb[0]);
+ bd_dl = get_unaligned_be16(&cdb[2]);
+ ptr = &buf[offset];
+ printk(KERN_INFO "UNMAP: Sub: %s Using dl: %hu bd_dl: %hu size: %hu"
+ " ptr: %p\n", dev->transport->name, dl, bd_dl, size, ptr);
+
+ while (size) {
+ lba = get_unaligned_be64(&ptr[0]);
+ range = get_unaligned_be32(&ptr[8]);
+ printk(KERN_INFO "UNMAP: Using lba: %llu and range: %u\n",
+ (unsigned long long)lba, range);
+
+ ret = dev->transport->do_discard(dev, lba, range);
+ if (ret < 0) {
+ printk(KERN_ERR "blkdev_issue_discard() failed: %d\n",
+ ret);
+ return -1;
+ }
+
+ ptr += 16;
+ size -= 16;
+ }
+
+ task->task_scsi_status = GOOD;
+ transport_complete_task(task, 1);
+ return 0;
+}
+
+/*
+ * Used for TCM/IBLOCK and TCM/FILEIO for block/blk-lib.c level discard support.
+ * Note this is not used for TCM/pSCSI passthrough
+ */
+static int
+target_emulate_write_same(struct se_task *task)
+{
+ struct se_cmd *cmd = TASK_CMD(task);
+ struct se_device *dev = SE_DEV(cmd);
+ sector_t lba = cmd->t_task->t_task_lba;
+ unsigned int range;
+ int ret;
+
+ range = (cmd->data_length / DEV_ATTRIB(dev)->block_size);
+
+ printk(KERN_INFO "WRITE_SAME UNMAP: LBA: %llu Range: %u\n",
+ (unsigned long long)lba, range);
+
+ ret = dev->transport->do_discard(dev, lba, range);
+ if (ret < 0) {
+ printk(KERN_INFO "blkdev_issue_discard() failed for WRITE_SAME\n");
+ return -1;
+ }
+
+ task->task_scsi_status = GOOD;
+ transport_complete_task(task, 1);
+ return 0;
+}
+
+int
+transport_emulate_control_cdb(struct se_task *task)
+{
+ struct se_cmd *cmd = TASK_CMD(task);
+ struct se_device *dev = SE_DEV(cmd);
+ unsigned short service_action;
+ int ret = 0;
+
+ switch (cmd->t_task->t_task_cdb[0]) {
+ case INQUIRY:
+ ret = target_emulate_inquiry(cmd);
+ break;
+ case READ_CAPACITY:
+ ret = target_emulate_readcapacity(cmd);
+ break;
+ case MODE_SENSE:
+ ret = target_emulate_modesense(cmd, 0);
+ break;
+ case MODE_SENSE_10:
+ ret = target_emulate_modesense(cmd, 1);
+ break;
+ case SERVICE_ACTION_IN:
+ switch (cmd->t_task->t_task_cdb[1] & 0x1f) {
+ case SAI_READ_CAPACITY_16:
+ ret = target_emulate_readcapacity_16(cmd);
+ break;
+ default:
+ printk(KERN_ERR "Unsupported SA: 0x%02x\n",
+ cmd->t_task->t_task_cdb[1] & 0x1f);
+ return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE;
+ }
+ break;
+ case REQUEST_SENSE:
+ ret = target_emulate_request_sense(cmd);
+ break;
+ case UNMAP:
+ if (!dev->transport->do_discard) {
+ printk(KERN_ERR "UNMAP emulation not supported for: %s\n",
+ dev->transport->name);
+ return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE;
+ }
+ ret = target_emulate_unmap(task);
+ break;
+ case WRITE_SAME_16:
+ if (!dev->transport->do_discard) {
+ printk(KERN_ERR "WRITE_SAME_16 emulation not supported"
+ " for: %s\n", dev->transport->name);
+ return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE;
+ }
+ ret = target_emulate_write_same(task);
+ break;
+ case VARIABLE_LENGTH_CMD:
+ service_action =
+ get_unaligned_be16(&cmd->t_task->t_task_cdb[8]);
+ switch (service_action) {
+ case WRITE_SAME_32:
+ if (!dev->transport->do_discard) {
+ printk(KERN_ERR "WRITE_SAME_32 SA emulation not"
+ " supported for: %s\n",
+ dev->transport->name);
+ return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE;
+ }
+ ret = target_emulate_write_same(task);
+ break;
+ default:
+ printk(KERN_ERR "Unsupported VARIABLE_LENGTH_CMD SA:"
+ " 0x%02x\n", service_action);
+ break;
+ }
+ break;
+ case SYNCHRONIZE_CACHE:
+ case 0x91: /* SYNCHRONIZE_CACHE_16: */
+ if (!dev->transport->do_sync_cache) {
+ printk(KERN_ERR
+ "SYNCHRONIZE_CACHE emulation not supported"
+ " for: %s\n", dev->transport->name);
+ return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE;
+ }
+ dev->transport->do_sync_cache(task);
+ break;
+ case ALLOW_MEDIUM_REMOVAL:
+ case ERASE:
+ case REZERO_UNIT:
+ case SEEK_10:
+ case SPACE:
+ case START_STOP:
+ case TEST_UNIT_READY:
+ case VERIFY:
+ case WRITE_FILEMARKS:
+ break;
+ default:
+ printk(KERN_ERR "Unsupported SCSI Opcode: 0x%02x for %s\n",
+ cmd->t_task->t_task_cdb[0], dev->transport->name);
+ return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE;
+ }
+
+ if (ret < 0)
+ return ret;
+ task->task_scsi_status = GOOD;
+ transport_complete_task(task, 1);
+
+ return PYX_TRANSPORT_SENT_TO_TRANSPORT;
+}
diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c
new file mode 100644
index 0000000..2764510
--- /dev/null
+++ b/drivers/target/target_core_configfs.c
@@ -0,0 +1,3225 @@
+/*******************************************************************************
+ * Filename: target_core_configfs.c
+ *
+ * This file contains ConfigFS logic for the Generic Target Engine project.
+ *
+ * Copyright (c) 2008-2010 Rising Tide Systems
+ * Copyright (c) 2008-2010 Linux-iSCSI.org
+ *
+ * Nicholas A. Bellinger <nab@kernel.org>
+ *
+ * based on configfs Copyright (C) 2005 Oracle. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ ****************************************************************************/
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/version.h>
+#include <generated/utsrelease.h>
+#include <linux/utsname.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/namei.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/unistd.h>
+#include <linux/string.h>
+#include <linux/parser.h>
+#include <linux/syscalls.h>
+#include <linux/configfs.h>
+#include <linux/proc_fs.h>
+
+#include <target/target_core_base.h>
+#include <target/target_core_device.h>
+#include <target/target_core_transport.h>
+#include <target/target_core_fabric_ops.h>
+#include <target/target_core_fabric_configfs.h>
+#include <target/target_core_configfs.h>
+#include <target/configfs_macros.h>
+
+#include "target_core_alua.h"
+#include "target_core_hba.h"
+#include "target_core_pr.h"
+#include "target_core_rd.h"
+
+static struct list_head g_tf_list;
+static struct mutex g_tf_lock;
+
+struct target_core_configfs_attribute {
+ struct configfs_attribute attr;
+ ssize_t (*show)(void *, char *);
+ ssize_t (*store)(void *, const char *, size_t);
+};
+
+static inline struct se_hba *
+item_to_hba(struct config_item *item)
+{
+ return container_of(to_config_group(item), struct se_hba, hba_group);
+}
+
+/*
+ * Attributes for /sys/kernel/config/target/
+ */
+static ssize_t target_core_attr_show(struct config_item *item,
+ struct configfs_attribute *attr,
+ char *page)
+{
+ return sprintf(page, "Target Engine Core ConfigFS Infrastructure %s"
+ " on %s/%s on "UTS_RELEASE"\n", TARGET_CORE_CONFIGFS_VERSION,
+ utsname()->sysname, utsname()->machine);
+}
+
+static struct configfs_item_operations target_core_fabric_item_ops = {
+ .show_attribute = target_core_attr_show,
+};
+
+static struct configfs_attribute target_core_item_attr_version = {
+ .ca_owner = THIS_MODULE,
+ .ca_name = "version",
+ .ca_mode = S_IRUGO,
+};
+
+static struct target_fabric_configfs *target_core_get_fabric(
+ const char *name)
+{
+ struct target_fabric_configfs *tf;
+
+ if (!(name))
+ return NULL;
+
+ mutex_lock(&g_tf_lock);
+ list_for_each_entry(tf, &g_tf_list, tf_list) {
+ if (!(strcmp(tf->tf_name, name))) {
+ atomic_inc(&tf->tf_access_cnt);
+ mutex_unlock(&g_tf_lock);
+ return tf;
+ }
+ }
+ mutex_unlock(&g_tf_lock);
+
+ return NULL;
+}
+
+/*
+ * Called from struct target_core_group_ops->make_group()
+ */
+static struct config_group *target_core_register_fabric(
+ struct config_group *group,
+ const char *name)
+{
+ struct target_fabric_configfs *tf;
+ int ret;
+
+ printk(KERN_INFO "Target_Core_ConfigFS: REGISTER -> group: %p name:"
+ " %s\n", group, name);
+ /*
+ * Ensure that TCM subsystem plugins are loaded at this point for
+ * using the RAMDISK_DR virtual LUN 0 and all other struct se_port
+ * LUN symlinks.
+ */
+ if (transport_subsystem_check_init() < 0)
+ return ERR_PTR(-EINVAL);
+
+ /*
+ * Below are some hardcoded request_module() calls to automatically
+ * local fabric modules when the following is called:
+ *
+ * mkdir -p /sys/kernel/config/target/$MODULE_NAME
+ *
+ * Note that this does not limit which TCM fabric module can be
+ * registered, but simply provids auto loading logic for modules with
+ * mkdir(2) system calls with known TCM fabric modules.
+ */
+ if (!(strncmp(name, "iscsi", 5))) {
+ /*
+ * Automatically load the LIO Target fabric module when the
+ * following is called:
+ *
+ * mkdir -p $CONFIGFS/target/iscsi
+ */
+ ret = request_module("iscsi_target_mod");
+ if (ret < 0) {
+ printk(KERN_ERR "request_module() failed for"
+ " iscsi_target_mod.ko: %d\n", ret);
+ return ERR_PTR(-EINVAL);
+ }
+ } else if (!(strncmp(name, "loopback", 8))) {
+ /*
+ * Automatically load the tcm_loop fabric module when the
+ * following is called:
+ *
+ * mkdir -p $CONFIGFS/target/loopback
+ */
+ ret = request_module("tcm_loop");
+ if (ret < 0) {
+ printk(KERN_ERR "request_module() failed for"
+ " tcm_loop.ko: %d\n", ret);
+ return ERR_PTR(-EINVAL);
+ }
+ }
+
+ tf = target_core_get_fabric(name);
+ if (!(tf)) {
+ printk(KERN_ERR "target_core_get_fabric() failed for %s\n",
+ name);
+ return ERR_PTR(-EINVAL);
+ }
+ printk(KERN_INFO "Target_Core_ConfigFS: REGISTER -> Located fabric:"
+ " %s\n", tf->tf_name);
+ /*
+ * On a successful target_core_get_fabric() look, the returned
+ * struct target_fabric_configfs *tf will contain a usage reference.
+ */
+ printk(KERN_INFO "Target_Core_ConfigFS: REGISTER tfc_wwn_cit -> %p\n",
+ &TF_CIT_TMPL(tf)->tfc_wwn_cit);
+
+ tf->tf_group.default_groups = tf->tf_default_groups;
+ tf->tf_group.default_groups[0] = &tf->tf_disc_group;
+ tf->tf_group.default_groups[1] = NULL;
+
+ config_group_init_type_name(&tf->tf_group, name,
+ &TF_CIT_TMPL(tf)->tfc_wwn_cit);
+ config_group_init_type_name(&tf->tf_disc_group, "discovery_auth",
+ &TF_CIT_TMPL(tf)->tfc_discovery_cit);
+
+ printk(KERN_INFO "Target_Core_ConfigFS: REGISTER -> Allocated Fabric:"
+ " %s\n", tf->tf_group.cg_item.ci_name);
+ /*
+ * Setup tf_ops.tf_subsys pointer for usage with configfs_depend_item()
+ */
+ tf->tf_ops.tf_subsys = tf->tf_subsys;
+ tf->tf_fabric = &tf->tf_group.cg_item;
+ printk(KERN_INFO "Target_Core_ConfigFS: REGISTER -> Set tf->tf_fabric"
+ " for %s\n", name);
+
+ return &tf->tf_group;
+}
+
+/*
+ * Called from struct target_core_group_ops->drop_item()
+ */
+static void target_core_deregister_fabric(
+ struct config_group *group,
+ struct config_item *item)
+{
+ struct target_fabric_configfs *tf = container_of(
+ to_config_group(item), struct target_fabric_configfs, tf_group);
+ struct config_group *tf_group;
+ struct config_item *df_item;
+ int i;
+
+ printk(KERN_INFO "Target_Core_ConfigFS: DEREGISTER -> Looking up %s in"
+ " tf list\n", config_item_name(item));
+
+ printk(KERN_INFO "Target_Core_ConfigFS: DEREGISTER -> located fabric:"
+ " %s\n", tf->tf_name);
+ atomic_dec(&tf->tf_access_cnt);
+
+ printk(KERN_INFO "Target_Core_ConfigFS: DEREGISTER -> Releasing"
+ " tf->tf_fabric for %s\n", tf->tf_name);
+ tf->tf_fabric = NULL;
+
+ printk(KERN_INFO "Target_Core_ConfigFS: DEREGISTER -> Releasing ci"
+ " %s\n", config_item_name(item));
+
+ tf_group = &tf->tf_group;
+ for (i = 0; tf_group->default_groups[i]; i++) {
+ df_item = &tf_group->default_groups[i]->cg_item;
+ tf_group->default_groups[i] = NULL;
+ config_item_put(df_item);
+ }
+ config_item_put(item);
+}
+
+static struct configfs_group_operations target_core_fabric_group_ops = {
+ .make_group = &target_core_register_fabric,
+ .drop_item = &target_core_deregister_fabric,
+};
+
+/*
+ * All item attributes appearing in /sys/kernel/target/ appear here.
+ */
+static struct configfs_attribute *target_core_fabric_item_attrs[] = {
+ &target_core_item_attr_version,
+ NULL,
+};
+
+/*
+ * Provides Fabrics Groups and Item Attributes for /sys/kernel/config/target/
+ */
+static struct config_item_type target_core_fabrics_item = {
+ .ct_item_ops = &target_core_fabric_item_ops,
+ .ct_group_ops = &target_core_fabric_group_ops,
+ .ct_attrs = target_core_fabric_item_attrs,
+ .ct_owner = THIS_MODULE,
+};
+
+static struct configfs_subsystem target_core_fabrics = {
+ .su_group = {
+ .cg_item = {
+ .ci_namebuf = "target",
+ .ci_type = &target_core_fabrics_item,
+ },
+ },
+};
+
+static struct configfs_subsystem *target_core_subsystem[] = {
+ &target_core_fabrics,
+ NULL,
+};
+
+/*##############################################################################
+// Start functions called by external Target Fabrics Modules
+//############################################################################*/
+
+/*
+ * First function called by fabric modules to:
+ *
+ * 1) Allocate a struct target_fabric_configfs and save the *fabric_cit pointer.
+ * 2) Add struct target_fabric_configfs to g_tf_list
+ * 3) Return struct target_fabric_configfs to fabric module to be passed
+ * into target_fabric_configfs_register().
+ */
+struct target_fabric_configfs *target_fabric_configfs_init(
+ struct module *fabric_mod,
+ const char *name)
+{
+ struct target_fabric_configfs *tf;
+
+ if (!(fabric_mod)) {
+ printk(KERN_ERR "Missing struct module *fabric_mod pointer\n");
+ return NULL;
+ }
+ if (!(name)) {
+ printk(KERN_ERR "Unable to locate passed fabric name\n");
+ return NULL;
+ }
+ if (strlen(name) > TARGET_FABRIC_NAME_SIZE) {
+ printk(KERN_ERR "Passed name: %s exceeds TARGET_FABRIC"
+ "_NAME_SIZE\n", name);
+ return NULL;
+ }
+
+ tf = kzalloc(sizeof(struct target_fabric_configfs), GFP_KERNEL);
+ if (!(tf))
+ return ERR_PTR(-ENOMEM);
+
+ INIT_LIST_HEAD(&tf->tf_list);
+ atomic_set(&tf->tf_access_cnt, 0);
+ /*
+ * Setup the default generic struct config_item_type's (cits) in
+ * struct target_fabric_configfs->tf_cit_tmpl
+ */
+ tf->tf_module = fabric_mod;
+ target_fabric_setup_cits(tf);
+
+ tf->tf_subsys = target_core_subsystem[0];
+ snprintf(tf->tf_name, TARGET_FABRIC_NAME_SIZE, "%s", name);
+
+ mutex_lock(&g_tf_lock);
+ list_add_tail(&tf->tf_list, &g_tf_list);
+ mutex_unlock(&g_tf_lock);
+
+ printk(KERN_INFO "<<<<<<<<<<<<<<<<<<<<<< BEGIN FABRIC API >>>>>>>>"
+ ">>>>>>>>>>>>>>\n");
+ printk(KERN_INFO "Initialized struct target_fabric_configfs: %p for"
+ " %s\n", tf, tf->tf_name);
+ return tf;
+}
+EXPORT_SYMBOL(target_fabric_configfs_init);
+
+/*
+ * Called by fabric plugins after FAILED target_fabric_configfs_register() call.
+ */
+void target_fabric_configfs_free(
+ struct target_fabric_configfs *tf)
+{
+ mutex_lock(&g_tf_lock);
+ list_del(&tf->tf_list);
+ mutex_unlock(&g_tf_lock);
+
+ kfree(tf);
+}
+EXPORT_SYMBOL(target_fabric_configfs_free);
+
+/*
+ * Perform a sanity check of the passed tf->tf_ops before completing
+ * TCM fabric module registration.
+ */
+static int target_fabric_tf_ops_check(
+ struct target_fabric_configfs *tf)
+{
+ struct target_core_fabric_ops *tfo = &tf->tf_ops;
+
+ if (!(tfo->get_fabric_name)) {
+ printk(KERN_ERR "Missing tfo->get_fabric_name()\n");
+ return -EINVAL;
+ }
+ if (!(tfo->get_fabric_proto_ident)) {
+ printk(KERN_ERR "Missing tfo->get_fabric_proto_ident()\n");
+ return -EINVAL;
+ }
+ if (!(tfo->tpg_get_wwn)) {
+ printk(KERN_ERR "Missing tfo->tpg_get_wwn()\n");
+ return -EINVAL;
+ }
+ if (!(tfo->tpg_get_tag)) {
+ printk(KERN_ERR "Missing tfo->tpg_get_tag()\n");
+ return -EINVAL;
+ }
+ if (!(tfo->tpg_get_default_depth)) {
+ printk(KERN_ERR "Missing tfo->tpg_get_default_depth()\n");
+ return -EINVAL;
+ }
+ if (!(tfo->tpg_get_pr_transport_id)) {
+ printk(KERN_ERR "Missing tfo->tpg_get_pr_transport_id()\n");
+ return -EINVAL;
+ }
+ if (!(tfo->tpg_get_pr_transport_id_len)) {
+ printk(KERN_ERR "Missing tfo->tpg_get_pr_transport_id_len()\n");
+ return -EINVAL;
+ }
+ if (!(tfo->tpg_check_demo_mode)) {
+ printk(KERN_ERR "Missing tfo->tpg_check_demo_mode()\n");
+ return -EINVAL;
+ }
+ if (!(tfo->tpg_check_demo_mode_cache)) {
+ printk(KERN_ERR "Missing tfo->tpg_check_demo_mode_cache()\n");
+ return -EINVAL;
+ }
+ if (!(tfo->tpg_check_demo_mode_write_protect)) {
+ printk(KERN_ERR "Missing tfo->tpg_check_demo_mode_write_protect()\n");
+ return -EINVAL;
+ }
+ if (!(tfo->tpg_check_prod_mode_write_protect)) {
+ printk(KERN_ERR "Missing tfo->tpg_check_prod_mode_write_protect()\n");
+ return -EINVAL;
+ }
+ if (!(tfo->tpg_alloc_fabric_acl)) {
+ printk(KERN_ERR "Missing tfo->tpg_alloc_fabric_acl()\n");
+ return -EINVAL;
+ }
+ if (!(tfo->tpg_release_fabric_acl)) {
+ printk(KERN_ERR "Missing tfo->tpg_release_fabric_acl()\n");
+ return -EINVAL;
+ }
+ if (!(tfo->tpg_get_inst_index)) {
+ printk(KERN_ERR "Missing tfo->tpg_get_inst_index()\n");
+ return -EINVAL;
+ }
+ if (!(tfo->release_cmd_to_pool)) {
+ printk(KERN_ERR "Missing tfo->release_cmd_to_pool()\n");
+ return -EINVAL;
+ }
+ if (!(tfo->release_cmd_direct)) {
+ printk(KERN_ERR "Missing tfo->release_cmd_direct()\n");
+ return -EINVAL;
+ }
+ if (!(tfo->shutdown_session)) {
+ printk(KERN_ERR "Missing tfo->shutdown_session()\n");
+ return -EINVAL;
+ }
+ if (!(tfo->close_session)) {
+ printk(KERN_ERR "Missing tfo->close_session()\n");
+ return -EINVAL;
+ }
+ if (!(tfo->stop_session)) {
+ printk(KERN_ERR "Missing tfo->stop_session()\n");
+ return -EINVAL;
+ }
+ if (!(tfo->fall_back_to_erl0)) {
+ printk(KERN_ERR "Missing tfo->fall_back_to_erl0()\n");
+ return -EINVAL;
+ }
+ if (!(tfo->sess_logged_in)) {
+ printk(KERN_ERR "Missing tfo->sess_logged_in()\n");
+ return -EINVAL;
+ }
+ if (!(tfo->sess_get_index)) {
+ printk(KERN_ERR "Missing tfo->sess_get_index()\n");
+ return -EINVAL;
+ }
+ if (!(tfo->write_pending)) {
+ printk(KERN_ERR "Missing tfo->write_pending()\n");
+ return -EINVAL;
+ }
+ if (!(tfo->write_pending_status)) {
+ printk(KERN_ERR "Missing tfo->write_pending_status()\n");
+ return -EINVAL;
+ }
+ if (!(tfo->set_default_node_attributes)) {
+ printk(KERN_ERR "Missing tfo->set_default_node_attributes()\n");
+ return -EINVAL;
+ }
+ if (!(tfo->get_task_tag)) {
+ printk(KERN_ERR "Missing tfo->get_task_tag()\n");
+ return -EINVAL;
+ }
+ if (!(tfo->get_cmd_state)) {
+ printk(KERN_ERR "Missing tfo->get_cmd_state()\n");
+ return -EINVAL;
+ }
+ if (!(tfo->new_cmd_failure)) {
+ printk(KERN_ERR "Missing tfo->new_cmd_failure()\n");
+ return -EINVAL;
+ }
+ if (!(tfo->queue_data_in)) {
+ printk(KERN_ERR "Missing tfo->queue_data_in()\n");
+ return -EINVAL;
+ }
+ if (!(tfo->queue_status)) {
+ printk(KERN_ERR "Missing tfo->queue_status()\n");
+ return -EINVAL;
+ }
+ if (!(tfo->queue_tm_rsp)) {
+ printk(KERN_ERR "Missing tfo->queue_tm_rsp()\n");
+ return -EINVAL;
+ }
+ if (!(tfo->set_fabric_sense_len)) {
+ printk(KERN_ERR "Missing tfo->set_fabric_sense_len()\n");
+ return -EINVAL;
+ }
+ if (!(tfo->get_fabric_sense_len)) {
+ printk(KERN_ERR "Missing tfo->get_fabric_sense_len()\n");
+ return -EINVAL;
+ }
+ if (!(tfo->is_state_remove)) {
+ printk(KERN_ERR "Missing tfo->is_state_remove()\n");
+ return -EINVAL;
+ }
+ if (!(tfo->pack_lun)) {
+ printk(KERN_ERR "Missing tfo->pack_lun()\n");
+ return -EINVAL;
+ }
+ /*
+ * We at least require tfo->fabric_make_wwn(), tfo->fabric_drop_wwn()
+ * tfo->fabric_make_tpg() and tfo->fabric_drop_tpg() in
+ * target_core_fabric_configfs.c WWN+TPG group context code.
+ */
+ if (!(tfo->fabric_make_wwn)) {
+ printk(KERN_ERR "Missing tfo->fabric_make_wwn()\n");
+ return -EINVAL;
+ }
+ if (!(tfo->fabric_drop_wwn)) {
+ printk(KERN_ERR "Missing tfo->fabric_drop_wwn()\n");
+ return -EINVAL;
+ }
+ if (!(tfo->fabric_make_tpg)) {
+ printk(KERN_ERR "Missing tfo->fabric_make_tpg()\n");
+ return -EINVAL;
+ }
+ if (!(tfo->fabric_drop_tpg)) {
+ printk(KERN_ERR "Missing tfo->fabric_drop_tpg()\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/*
+ * Called 2nd from fabric module with returned parameter of
+ * struct target_fabric_configfs * from target_fabric_configfs_init().
+ *
+ * Upon a successful registration, the new fabric's struct config_item is
+ * return. Also, a pointer to this struct is set in the passed
+ * struct target_fabric_configfs.
+ */
+int target_fabric_configfs_register(
+ struct target_fabric_configfs *tf)
+{
+ struct config_group *su_group;
+ int ret;
+
+ if (!(tf)) {
+ printk(KERN_ERR "Unable to locate target_fabric_configfs"
+ " pointer\n");
+ return -EINVAL;
+ }
+ if (!(tf->tf_subsys)) {
+ printk(KERN_ERR "Unable to target struct config_subsystem"
+ " pointer\n");
+ return -EINVAL;
+ }
+ su_group = &tf->tf_subsys->su_group;
+ if (!(su_group)) {
+ printk(KERN_ERR "Unable to locate target struct config_group"
+ " pointer\n");
+ return -EINVAL;
+ }
+ ret = target_fabric_tf_ops_check(tf);
+ if (ret < 0)
+ return ret;
+
+ printk(KERN_INFO "<<<<<<<<<<<<<<<<<<<<<< END FABRIC API >>>>>>>>>>>>"
+ ">>>>>>>>>>\n");
+ return 0;
+}
+EXPORT_SYMBOL(target_fabric_configfs_register);
+
+void target_fabric_configfs_deregister(
+ struct target_fabric_configfs *tf)
+{
+ struct config_group *su_group;
+ struct configfs_subsystem *su;
+
+ if (!(tf)) {
+ printk(KERN_ERR "Unable to locate passed target_fabric_"
+ "configfs\n");
+ return;
+ }
+ su = tf->tf_subsys;
+ if (!(su)) {
+ printk(KERN_ERR "Unable to locate passed tf->tf_subsys"
+ " pointer\n");
+ return;
+ }
+ su_group = &tf->tf_subsys->su_group;
+ if (!(su_group)) {
+ printk(KERN_ERR "Unable to locate target struct config_group"
+ " pointer\n");
+ return;
+ }
+
+ printk(KERN_INFO "<<<<<<<<<<<<<<<<<<<<<< BEGIN FABRIC API >>>>>>>>>>"
+ ">>>>>>>>>>>>\n");
+ mutex_lock(&g_tf_lock);
+ if (atomic_read(&tf->tf_access_cnt)) {
+ mutex_unlock(&g_tf_lock);
+ printk(KERN_ERR "Non zero tf->tf_access_cnt for fabric %s\n",
+ tf->tf_name);
+ BUG();
+ }
+ list_del(&tf->tf_list);
+ mutex_unlock(&g_tf_lock);
+
+ printk(KERN_INFO "Target_Core_ConfigFS: DEREGISTER -> Releasing tf:"
+ " %s\n", tf->tf_name);
+ tf->tf_module = NULL;
+ tf->tf_subsys = NULL;
+ kfree(tf);
+
+ printk("<<<<<<<<<<<<<<<<<<<<<< END FABRIC API >>>>>>>>>>>>>>>>>"
+ ">>>>>\n");
+ return;
+}
+EXPORT_SYMBOL(target_fabric_configfs_deregister);
+
+/*##############################################################################
+// Stop functions called by external Target Fabrics Modules
+//############################################################################*/
+
+/* Start functions for struct config_item_type target_core_dev_attrib_cit */
+
+#define DEF_DEV_ATTRIB_SHOW(_name) \
+static ssize_t target_core_dev_show_attr_##_name( \
+ struct se_dev_attrib *da, \
+ char *page) \
+{ \
+ struct se_device *dev; \
+ struct se_subsystem_dev *se_dev = da->da_sub_dev; \
+ ssize_t rb; \
+ \
+ spin_lock(&se_dev->se_dev_lock); \
+ dev = se_dev->se_dev_ptr; \
+ if (!(dev)) { \
+ spin_unlock(&se_dev->se_dev_lock); \
+ return -ENODEV; \
+ } \
+ rb = snprintf(page, PAGE_SIZE, "%u\n", (u32)DEV_ATTRIB(dev)->_name); \
+ spin_unlock(&se_dev->se_dev_lock); \
+ \
+ return rb; \
+}
+
+#define DEF_DEV_ATTRIB_STORE(_name) \
+static ssize_t target_core_dev_store_attr_##_name( \
+ struct se_dev_attrib *da, \
+ const char *page, \
+ size_t count) \
+{ \
+ struct se_device *dev; \
+ struct se_subsystem_dev *se_dev = da->da_sub_dev; \
+ unsigned long val; \
+ int ret; \
+ \
+ spin_lock(&se_dev->se_dev_lock); \
+ dev = se_dev->se_dev_ptr; \
+ if (!(dev)) { \
+ spin_unlock(&se_dev->se_dev_lock); \
+ return -ENODEV; \
+ } \
+ ret = strict_strtoul(page, 0, &val); \
+ if (ret < 0) { \
+ spin_unlock(&se_dev->se_dev_lock); \
+ printk(KERN_ERR "strict_strtoul() failed with" \
+ " ret: %d\n", ret); \
+ return -EINVAL; \
+ } \
+ ret = se_dev_set_##_name(dev, (u32)val); \
+ spin_unlock(&se_dev->se_dev_lock); \
+ \
+ return (!ret) ? count : -EINVAL; \
+}
+
+#define DEF_DEV_ATTRIB(_name) \
+DEF_DEV_ATTRIB_SHOW(_name); \
+DEF_DEV_ATTRIB_STORE(_name);
+
+#define DEF_DEV_ATTRIB_RO(_name) \
+DEF_DEV_ATTRIB_SHOW(_name);
+
+CONFIGFS_EATTR_STRUCT(target_core_dev_attrib, se_dev_attrib);
+#define SE_DEV_ATTR(_name, _mode) \
+static struct target_core_dev_attrib_attribute \
+ target_core_dev_attrib_##_name = \
+ __CONFIGFS_EATTR(_name, _mode, \
+ target_core_dev_show_attr_##_name, \
+ target_core_dev_store_attr_##_name);
+
+#define SE_DEV_ATTR_RO(_name); \
+static struct target_core_dev_attrib_attribute \
+ target_core_dev_attrib_##_name = \
+ __CONFIGFS_EATTR_RO(_name, \
+ target_core_dev_show_attr_##_name);
+
+DEF_DEV_ATTRIB(emulate_dpo);
+SE_DEV_ATTR(emulate_dpo, S_IRUGO | S_IWUSR);
+
+DEF_DEV_ATTRIB(emulate_fua_write);
+SE_DEV_ATTR(emulate_fua_write, S_IRUGO | S_IWUSR);
+
+DEF_DEV_ATTRIB(emulate_fua_read);
+SE_DEV_ATTR(emulate_fua_read, S_IRUGO | S_IWUSR);
+
+DEF_DEV_ATTRIB(emulate_write_cache);
+SE_DEV_ATTR(emulate_write_cache, S_IRUGO | S_IWUSR);
+
+DEF_DEV_ATTRIB(emulate_ua_intlck_ctrl);
+SE_DEV_ATTR(emulate_ua_intlck_ctrl, S_IRUGO | S_IWUSR);
+
+DEF_DEV_ATTRIB(emulate_tas);
+SE_DEV_ATTR(emulate_tas, S_IRUGO | S_IWUSR);
+
+DEF_DEV_ATTRIB(emulate_tpu);
+SE_DEV_ATTR(emulate_tpu, S_IRUGO | S_IWUSR);
+
+DEF_DEV_ATTRIB(emulate_tpws);
+SE_DEV_ATTR(emulate_tpws, S_IRUGO | S_IWUSR);
+
+DEF_DEV_ATTRIB(enforce_pr_isids);
+SE_DEV_ATTR(enforce_pr_isids, S_IRUGO | S_IWUSR);
+
+DEF_DEV_ATTRIB_RO(hw_block_size);
+SE_DEV_ATTR_RO(hw_block_size);
+
+DEF_DEV_ATTRIB(block_size);
+SE_DEV_ATTR(block_size, S_IRUGO | S_IWUSR);
+
+DEF_DEV_ATTRIB_RO(hw_max_sectors);
+SE_DEV_ATTR_RO(hw_max_sectors);
+
+DEF_DEV_ATTRIB(max_sectors);
+SE_DEV_ATTR(max_sectors, S_IRUGO | S_IWUSR);
+
+DEF_DEV_ATTRIB(optimal_sectors);
+SE_DEV_ATTR(optimal_sectors, S_IRUGO | S_IWUSR);
+
+DEF_DEV_ATTRIB_RO(hw_queue_depth);
+SE_DEV_ATTR_RO(hw_queue_depth);
+
+DEF_DEV_ATTRIB(queue_depth);
+SE_DEV_ATTR(queue_depth, S_IRUGO | S_IWUSR);
+
+DEF_DEV_ATTRIB(task_timeout);
+SE_DEV_ATTR(task_timeout, S_IRUGO | S_IWUSR);
+
+DEF_DEV_ATTRIB(max_unmap_lba_count);
+SE_DEV_ATTR(max_unmap_lba_count, S_IRUGO | S_IWUSR);
+
+DEF_DEV_ATTRIB(max_unmap_block_desc_count);
+SE_DEV_ATTR(max_unmap_block_desc_count, S_IRUGO | S_IWUSR);
+
+DEF_DEV_ATTRIB(unmap_granularity);
+SE_DEV_ATTR(unmap_granularity, S_IRUGO | S_IWUSR);
+
+DEF_DEV_ATTRIB(unmap_granularity_alignment);
+SE_DEV_ATTR(unmap_granularity_alignment, S_IRUGO | S_IWUSR);
+
+CONFIGFS_EATTR_OPS(target_core_dev_attrib, se_dev_attrib, da_group);
+
+static struct configfs_attribute *target_core_dev_attrib_attrs[] = {
+ &target_core_dev_attrib_emulate_dpo.attr,
+ &target_core_dev_attrib_emulate_fua_write.attr,
+ &target_core_dev_attrib_emulate_fua_read.attr,
+ &target_core_dev_attrib_emulate_write_cache.attr,
+ &target_core_dev_attrib_emulate_ua_intlck_ctrl.attr,
+ &target_core_dev_attrib_emulate_tas.attr,
+ &target_core_dev_attrib_emulate_tpu.attr,
+ &target_core_dev_attrib_emulate_tpws.attr,
+ &target_core_dev_attrib_enforce_pr_isids.attr,
+ &target_core_dev_attrib_hw_block_size.attr,
+ &target_core_dev_attrib_block_size.attr,
+ &target_core_dev_attrib_hw_max_sectors.attr,
+ &target_core_dev_attrib_max_sectors.attr,
+ &target_core_dev_attrib_optimal_sectors.attr,
+ &target_core_dev_attrib_hw_queue_depth.attr,
+ &target_core_dev_attrib_queue_depth.attr,
+ &target_core_dev_attrib_task_timeout.attr,
+ &target_core_dev_attrib_max_unmap_lba_count.attr,
+ &target_core_dev_attrib_max_unmap_block_desc_count.attr,
+ &target_core_dev_attrib_unmap_granularity.attr,
+ &target_core_dev_attrib_unmap_granularity_alignment.attr,
+ NULL,
+};
+
+static struct configfs_item_operations target_core_dev_attrib_ops = {
+ .show_attribute = target_core_dev_attrib_attr_show,
+ .store_attribute = target_core_dev_attrib_attr_store,
+};
+
+static struct config_item_type target_core_dev_attrib_cit = {
+ .ct_item_ops = &target_core_dev_attrib_ops,
+ .ct_attrs = target_core_dev_attrib_attrs,
+ .ct_owner = THIS_MODULE,
+};
+
+/* End functions for struct config_item_type target_core_dev_attrib_cit */
+
+/* Start functions for struct config_item_type target_core_dev_wwn_cit */
+
+CONFIGFS_EATTR_STRUCT(target_core_dev_wwn, t10_wwn);
+#define SE_DEV_WWN_ATTR(_name, _mode) \
+static struct target_core_dev_wwn_attribute target_core_dev_wwn_##_name = \
+ __CONFIGFS_EATTR(_name, _mode, \
+ target_core_dev_wwn_show_attr_##_name, \
+ target_core_dev_wwn_store_attr_##_name);
+
+#define SE_DEV_WWN_ATTR_RO(_name); \
+do { \
+ static struct target_core_dev_wwn_attribute \
+ target_core_dev_wwn_##_name = \
+ __CONFIGFS_EATTR_RO(_name, \
+ target_core_dev_wwn_show_attr_##_name); \
+} while (0);
+
+/*
+ * VPD page 0x80 Unit serial
+ */
+static ssize_t target_core_dev_wwn_show_attr_vpd_unit_serial(
+ struct t10_wwn *t10_wwn,
+ char *page)
+{
+ struct se_subsystem_dev *se_dev = t10_wwn->t10_sub_dev;
+ struct se_device *dev;
+
+ dev = se_dev->se_dev_ptr;
+ if (!(dev))
+ return -ENODEV;
+
+ return sprintf(page, "T10 VPD Unit Serial Number: %s\n",
+ &t10_wwn->unit_serial[0]);
+}
+
+static ssize_t target_core_dev_wwn_store_attr_vpd_unit_serial(
+ struct t10_wwn *t10_wwn,
+ const char *page,
+ size_t count)
+{
+ struct se_subsystem_dev *su_dev = t10_wwn->t10_sub_dev;
+ struct se_device *dev;
+ unsigned char buf[INQUIRY_VPD_SERIAL_LEN];
+
+ /*
+ * If Linux/SCSI subsystem_api_t plugin got a VPD Unit Serial
+ * from the struct scsi_device level firmware, do not allow
+ * VPD Unit Serial to be emulated.
+ *
+ * Note this struct scsi_device could also be emulating VPD
+ * information from its drivers/scsi LLD. But for now we assume
+ * it is doing 'the right thing' wrt a world wide unique
+ * VPD Unit Serial Number that OS dependent multipath can depend on.
+ */
+ if (su_dev->su_dev_flags & SDF_FIRMWARE_VPD_UNIT_SERIAL) {
+ printk(KERN_ERR "Underlying SCSI device firmware provided VPD"
+ " Unit Serial, ignoring request\n");
+ return -EOPNOTSUPP;
+ }
+
+ if ((strlen(page) + 1) > INQUIRY_VPD_SERIAL_LEN) {
+ printk(KERN_ERR "Emulated VPD Unit Serial exceeds"
+ " INQUIRY_VPD_SERIAL_LEN: %d\n", INQUIRY_VPD_SERIAL_LEN);
+ return -EOVERFLOW;
+ }
+ /*
+ * Check to see if any active $FABRIC_MOD exports exist. If they
+ * do exist, fail here as changing this information on the fly
+ * (underneath the initiator side OS dependent multipath code)
+ * could cause negative effects.
+ */
+ dev = su_dev->se_dev_ptr;
+ if ((dev)) {
+ if (atomic_read(&dev->dev_export_obj.obj_access_count)) {
+ printk(KERN_ERR "Unable to set VPD Unit Serial while"
+ " active %d $FABRIC_MOD exports exist\n",
+ atomic_read(&dev->dev_export_obj.obj_access_count));
+ return -EINVAL;
+ }
+ }
+ /*
+ * This currently assumes ASCII encoding for emulated VPD Unit Serial.
+ *
+ * Also, strip any newline added from the userspace
+ * echo $UUID > $TARGET/$HBA/$STORAGE_OBJECT/wwn/vpd_unit_serial
+ */
+ memset(buf, 0, INQUIRY_VPD_SERIAL_LEN);
+ snprintf(buf, INQUIRY_VPD_SERIAL_LEN, "%s", page);
+ snprintf(su_dev->t10_wwn.unit_serial, INQUIRY_VPD_SERIAL_LEN,
+ "%s", strstrip(buf));
+ su_dev->su_dev_flags |= SDF_EMULATED_VPD_UNIT_SERIAL;
+
+ printk(KERN_INFO "Target_Core_ConfigFS: Set emulated VPD Unit Serial:"
+ " %s\n", su_dev->t10_wwn.unit_serial);
+
+ return count;
+}
+
+SE_DEV_WWN_ATTR(vpd_unit_serial, S_IRUGO | S_IWUSR);
+
+/*
+ * VPD page 0x83 Protocol Identifier
+ */
+static ssize_t target_core_dev_wwn_show_attr_vpd_protocol_identifier(
+ struct t10_wwn *t10_wwn,
+ char *page)
+{
+ struct se_subsystem_dev *se_dev = t10_wwn->t10_sub_dev;
+ struct se_device *dev;
+ struct t10_vpd *vpd;
+ unsigned char buf[VPD_TMP_BUF_SIZE];
+ ssize_t len = 0;
+
+ dev = se_dev->se_dev_ptr;
+ if (!(dev))
+ return -ENODEV;
+
+ memset(buf, 0, VPD_TMP_BUF_SIZE);
+
+ spin_lock(&t10_wwn->t10_vpd_lock);
+ list_for_each_entry(vpd, &t10_wwn->t10_vpd_list, vpd_list) {
+ if (!(vpd->protocol_identifier_set))
+ continue;
+
+ transport_dump_vpd_proto_id(vpd, buf, VPD_TMP_BUF_SIZE);
+
+ if ((len + strlen(buf) > PAGE_SIZE))
+ break;
+
+ len += sprintf(page+len, "%s", buf);
+ }
+ spin_unlock(&t10_wwn->t10_vpd_lock);
+
+ return len;
+}
+
+static ssize_t target_core_dev_wwn_store_attr_vpd_protocol_identifier(
+ struct t10_wwn *t10_wwn,
+ const char *page,
+ size_t count)
+{
+ return -ENOSYS;
+}
+
+SE_DEV_WWN_ATTR(vpd_protocol_identifier, S_IRUGO | S_IWUSR);
+
+/*
+ * Generic wrapper for dumping VPD identifiers by association.
+ */
+#define DEF_DEV_WWN_ASSOC_SHOW(_name, _assoc) \
+static ssize_t target_core_dev_wwn_show_attr_##_name( \
+ struct t10_wwn *t10_wwn, \
+ char *page) \
+{ \
+ struct se_subsystem_dev *se_dev = t10_wwn->t10_sub_dev; \
+ struct se_device *dev; \
+ struct t10_vpd *vpd; \
+ unsigned char buf[VPD_TMP_BUF_SIZE]; \
+ ssize_t len = 0; \
+ \
+ dev = se_dev->se_dev_ptr; \
+ if (!(dev)) \
+ return -ENODEV; \
+ \
+ spin_lock(&t10_wwn->t10_vpd_lock); \
+ list_for_each_entry(vpd, &t10_wwn->t10_vpd_list, vpd_list) { \
+ if (vpd->association != _assoc) \
+ continue; \
+ \
+ memset(buf, 0, VPD_TMP_BUF_SIZE); \
+ transport_dump_vpd_assoc(vpd, buf, VPD_TMP_BUF_SIZE); \
+ if ((len + strlen(buf) > PAGE_SIZE)) \
+ break; \
+ len += sprintf(page+len, "%s", buf); \
+ \
+ memset(buf, 0, VPD_TMP_BUF_SIZE); \
+ transport_dump_vpd_ident_type(vpd, buf, VPD_TMP_BUF_SIZE); \
+ if ((len + strlen(buf) > PAGE_SIZE)) \
+ break; \
+ len += sprintf(page+len, "%s", buf); \
+ \
+ memset(buf, 0, VPD_TMP_BUF_SIZE); \
+ transport_dump_vpd_ident(vpd, buf, VPD_TMP_BUF_SIZE); \
+ if ((len + strlen(buf) > PAGE_SIZE)) \
+ break; \
+ len += sprintf(page+len, "%s", buf); \
+ } \
+ spin_unlock(&t10_wwn->t10_vpd_lock); \
+ \
+ return len; \
+}
+
+/*
+ * VPD page 0x83 Assoication: Logical Unit
+ */
+DEF_DEV_WWN_ASSOC_SHOW(vpd_assoc_logical_unit, 0x00);
+
+static ssize_t target_core_dev_wwn_store_attr_vpd_assoc_logical_unit(
+ struct t10_wwn *t10_wwn,
+ const char *page,
+ size_t count)
+{
+ return -ENOSYS;
+}
+
+SE_DEV_WWN_ATTR(vpd_assoc_logical_unit, S_IRUGO | S_IWUSR);
+
+/*
+ * VPD page 0x83 Association: Target Port
+ */
+DEF_DEV_WWN_ASSOC_SHOW(vpd_assoc_target_port, 0x10);
+
+static ssize_t target_core_dev_wwn_store_attr_vpd_assoc_target_port(
+ struct t10_wwn *t10_wwn,
+ const char *page,
+ size_t count)
+{
+ return -ENOSYS;
+}
+
+SE_DEV_WWN_ATTR(vpd_assoc_target_port, S_IRUGO | S_IWUSR);
+
+/*
+ * VPD page 0x83 Association: SCSI Target Device
+ */
+DEF_DEV_WWN_ASSOC_SHOW(vpd_assoc_scsi_target_device, 0x20);
+
+static ssize_t target_core_dev_wwn_store_attr_vpd_assoc_scsi_target_device(
+ struct t10_wwn *t10_wwn,
+ const char *page,
+ size_t count)
+{
+ return -ENOSYS;
+}
+
+SE_DEV_WWN_ATTR(vpd_assoc_scsi_target_device, S_IRUGO | S_IWUSR);
+
+CONFIGFS_EATTR_OPS(target_core_dev_wwn, t10_wwn, t10_wwn_group);
+
+static struct configfs_attribute *target_core_dev_wwn_attrs[] = {
+ &target_core_dev_wwn_vpd_unit_serial.attr,
+ &target_core_dev_wwn_vpd_protocol_identifier.attr,
+ &target_core_dev_wwn_vpd_assoc_logical_unit.attr,
+ &target_core_dev_wwn_vpd_assoc_target_port.attr,
+ &target_core_dev_wwn_vpd_assoc_scsi_target_device.attr,
+ NULL,
+};
+
+static struct configfs_item_operations target_core_dev_wwn_ops = {
+ .show_attribute = target_core_dev_wwn_attr_show,
+ .store_attribute = target_core_dev_wwn_attr_store,
+};
+
+static struct config_item_type target_core_dev_wwn_cit = {
+ .ct_item_ops = &target_core_dev_wwn_ops,
+ .ct_attrs = target_core_dev_wwn_attrs,
+ .ct_owner = THIS_MODULE,
+};
+
+/* End functions for struct config_item_type target_core_dev_wwn_cit */
+
+/* Start functions for struct config_item_type target_core_dev_pr_cit */
+
+CONFIGFS_EATTR_STRUCT(target_core_dev_pr, se_subsystem_dev);
+#define SE_DEV_PR_ATTR(_name, _mode) \
+static struct target_core_dev_pr_attribute target_core_dev_pr_##_name = \
+ __CONFIGFS_EATTR(_name, _mode, \
+ target_core_dev_pr_show_attr_##_name, \
+ target_core_dev_pr_store_attr_##_name);
+
+#define SE_DEV_PR_ATTR_RO(_name); \
+static struct target_core_dev_pr_attribute target_core_dev_pr_##_name = \
+ __CONFIGFS_EATTR_RO(_name, \
+ target_core_dev_pr_show_attr_##_name);
+
+/*
+ * res_holder
+ */
+static ssize_t target_core_dev_pr_show_spc3_res(
+ struct se_device *dev,
+ char *page,
+ ssize_t *len)
+{
+ struct se_node_acl *se_nacl;
+ struct t10_pr_registration *pr_reg;
+ char i_buf[PR_REG_ISID_ID_LEN];
+ int prf_isid;
+
+ memset(i_buf, 0, PR_REG_ISID_ID_LEN);
+
+ spin_lock(&dev->dev_reservation_lock);
+ pr_reg = dev->dev_pr_res_holder;
+ if (!(pr_reg)) {
+ *len += sprintf(page + *len, "No SPC-3 Reservation holder\n");
+ spin_unlock(&dev->dev_reservation_lock);
+ return *len;
+ }
+ se_nacl = pr_reg->pr_reg_nacl;
+ prf_isid = core_pr_dump_initiator_port(pr_reg, &i_buf[0],
+ PR_REG_ISID_ID_LEN);
+
+ *len += sprintf(page + *len, "SPC-3 Reservation: %s Initiator: %s%s\n",
+ TPG_TFO(se_nacl->se_tpg)->get_fabric_name(),
+ se_nacl->initiatorname, (prf_isid) ? &i_buf[0] : "");
+ spin_unlock(&dev->dev_reservation_lock);
+
+ return *len;
+}
+
+static ssize_t target_core_dev_pr_show_spc2_res(
+ struct se_device *dev,
+ char *page,
+ ssize_t *len)
+{
+ struct se_node_acl *se_nacl;
+
+ spin_lock(&dev->dev_reservation_lock);
+ se_nacl = dev->dev_reserved_node_acl;
+ if (!(se_nacl)) {
+ *len += sprintf(page + *len, "No SPC-2 Reservation holder\n");
+ spin_unlock(&dev->dev_reservation_lock);
+ return *len;
+ }
+ *len += sprintf(page + *len, "SPC-2 Reservation: %s Initiator: %s\n",
+ TPG_TFO(se_nacl->se_tpg)->get_fabric_name(),
+ se_nacl->initiatorname);
+ spin_unlock(&dev->dev_reservation_lock);
+
+ return *len;
+}
+
+static ssize_t target_core_dev_pr_show_attr_res_holder(
+ struct se_subsystem_dev *su_dev,
+ char *page)
+{
+ ssize_t len = 0;
+
+ if (!(su_dev->se_dev_ptr))
+ return -ENODEV;
+
+ switch (T10_RES(su_dev)->res_type) {
+ case SPC3_PERSISTENT_RESERVATIONS:
+ target_core_dev_pr_show_spc3_res(su_dev->se_dev_ptr,
+ page, &len);
+ break;
+ case SPC2_RESERVATIONS:
+ target_core_dev_pr_show_spc2_res(su_dev->se_dev_ptr,
+ page, &len);
+ break;
+ case SPC_PASSTHROUGH:
+ len += sprintf(page+len, "Passthrough\n");
+ break;
+ default:
+ len += sprintf(page+len, "Unknown\n");
+ break;
+ }
+
+ return len;
+}
+
+SE_DEV_PR_ATTR_RO(res_holder);
+
+/*
+ * res_pr_all_tgt_pts
+ */
+static ssize_t target_core_dev_pr_show_attr_res_pr_all_tgt_pts(
+ struct se_subsystem_dev *su_dev,
+ char *page)
+{
+ struct se_device *dev;
+ struct t10_pr_registration *pr_reg;
+ ssize_t len = 0;
+
+ dev = su_dev->se_dev_ptr;
+ if (!(dev))
+ return -ENODEV;
+
+ if (T10_RES(su_dev)->res_type != SPC3_PERSISTENT_RESERVATIONS)
+ return len;
+
+ spin_lock(&dev->dev_reservation_lock);
+ pr_reg = dev->dev_pr_res_holder;
+ if (!(pr_reg)) {
+ len = sprintf(page, "No SPC-3 Reservation holder\n");
+ spin_unlock(&dev->dev_reservation_lock);
+ return len;
+ }
+ /*
+ * See All Target Ports (ALL_TG_PT) bit in spcr17, section 6.14.3
+ * Basic PERSISTENT RESERVER OUT parameter list, page 290
+ */
+ if (pr_reg->pr_reg_all_tg_pt)
+ len = sprintf(page, "SPC-3 Reservation: All Target"
+ " Ports registration\n");
+ else
+ len = sprintf(page, "SPC-3 Reservation: Single"
+ " Target Port registration\n");
+ spin_unlock(&dev->dev_reservation_lock);
+
+ return len;
+}
+
+SE_DEV_PR_ATTR_RO(res_pr_all_tgt_pts);
+
+/*
+ * res_pr_generation
+ */
+static ssize_t target_core_dev_pr_show_attr_res_pr_generation(
+ struct se_subsystem_dev *su_dev,
+ char *page)
+{
+ if (!(su_dev->se_dev_ptr))
+ return -ENODEV;
+
+ if (T10_RES(su_dev)->res_type != SPC3_PERSISTENT_RESERVATIONS)
+ return 0;
+
+ return sprintf(page, "0x%08x\n", T10_RES(su_dev)->pr_generation);
+}
+
+SE_DEV_PR_ATTR_RO(res_pr_generation);
+
+/*
+ * res_pr_holder_tg_port
+ */
+static ssize_t target_core_dev_pr_show_attr_res_pr_holder_tg_port(
+ struct se_subsystem_dev *su_dev,
+ char *page)
+{
+ struct se_device *dev;
+ struct se_node_acl *se_nacl;
+ struct se_lun *lun;
+ struct se_portal_group *se_tpg;
+ struct t10_pr_registration *pr_reg;
+ struct target_core_fabric_ops *tfo;
+ ssize_t len = 0;
+
+ dev = su_dev->se_dev_ptr;
+ if (!(dev))
+ return -ENODEV;
+
+ if (T10_RES(su_dev)->res_type != SPC3_PERSISTENT_RESERVATIONS)
+ return len;
+
+ spin_lock(&dev->dev_reservation_lock);
+ pr_reg = dev->dev_pr_res_holder;
+ if (!(pr_reg)) {
+ len = sprintf(page, "No SPC-3 Reservation holder\n");
+ spin_unlock(&dev->dev_reservation_lock);
+ return len;
+ }
+ se_nacl = pr_reg->pr_reg_nacl;
+ se_tpg = se_nacl->se_tpg;
+ lun = pr_reg->pr_reg_tg_pt_lun;
+ tfo = TPG_TFO(se_tpg);
+
+ len += sprintf(page+len, "SPC-3 Reservation: %s"
+ " Target Node Endpoint: %s\n", tfo->get_fabric_name(),
+ tfo->tpg_get_wwn(se_tpg));
+ len += sprintf(page+len, "SPC-3 Reservation: Relative Port"
+ " Identifer Tag: %hu %s Portal Group Tag: %hu"
+ " %s Logical Unit: %u\n", lun->lun_sep->sep_rtpi,
+ tfo->get_fabric_name(), tfo->tpg_get_tag(se_tpg),
+ tfo->get_fabric_name(), lun->unpacked_lun);
+ spin_unlock(&dev->dev_reservation_lock);
+
+ return len;
+}
+
+SE_DEV_PR_ATTR_RO(res_pr_holder_tg_port);
+
+/*
+ * res_pr_registered_i_pts
+ */
+static ssize_t target_core_dev_pr_show_attr_res_pr_registered_i_pts(
+ struct se_subsystem_dev *su_dev,
+ char *page)
+{
+ struct target_core_fabric_ops *tfo;
+ struct t10_pr_registration *pr_reg;
+ unsigned char buf[384];
+ char i_buf[PR_REG_ISID_ID_LEN];
+ ssize_t len = 0;
+ int reg_count = 0, prf_isid;
+
+ if (!(su_dev->se_dev_ptr))
+ return -ENODEV;
+
+ if (T10_RES(su_dev)->res_type != SPC3_PERSISTENT_RESERVATIONS)
+ return len;
+
+ len += sprintf(page+len, "SPC-3 PR Registrations:\n");
+
+ spin_lock(&T10_RES(su_dev)->registration_lock);
+ list_for_each_entry(pr_reg, &T10_RES(su_dev)->registration_list,
+ pr_reg_list) {
+
+ memset(buf, 0, 384);
+ memset(i_buf, 0, PR_REG_ISID_ID_LEN);
+ tfo = pr_reg->pr_reg_nacl->se_tpg->se_tpg_tfo;
+ prf_isid = core_pr_dump_initiator_port(pr_reg, &i_buf[0],
+ PR_REG_ISID_ID_LEN);
+ sprintf(buf, "%s Node: %s%s Key: 0x%016Lx PRgen: 0x%08x\n",
+ tfo->get_fabric_name(),
+ pr_reg->pr_reg_nacl->initiatorname, (prf_isid) ?
+ &i_buf[0] : "", pr_reg->pr_res_key,
+ pr_reg->pr_res_generation);
+
+ if ((len + strlen(buf) > PAGE_SIZE))
+ break;
+
+ len += sprintf(page+len, "%s", buf);
+ reg_count++;
+ }
+ spin_unlock(&T10_RES(su_dev)->registration_lock);
+
+ if (!(reg_count))
+ len += sprintf(page+len, "None\n");
+
+ return len;
+}
+
+SE_DEV_PR_ATTR_RO(res_pr_registered_i_pts);
+
+/*
+ * res_pr_type
+ */
+static ssize_t target_core_dev_pr_show_attr_res_pr_type(
+ struct se_subsystem_dev *su_dev,
+ char *page)
+{
+ struct se_device *dev;
+ struct t10_pr_registration *pr_reg;
+ ssize_t len = 0;
+
+ dev = su_dev->se_dev_ptr;
+ if (!(dev))
+ return -ENODEV;
+
+ if (T10_RES(su_dev)->res_type != SPC3_PERSISTENT_RESERVATIONS)
+ return len;
+
+ spin_lock(&dev->dev_reservation_lock);
+ pr_reg = dev->dev_pr_res_holder;
+ if (!(pr_reg)) {
+ len = sprintf(page, "No SPC-3 Reservation holder\n");
+ spin_unlock(&dev->dev_reservation_lock);
+ return len;
+ }
+ len = sprintf(page, "SPC-3 Reservation Type: %s\n",
+ core_scsi3_pr_dump_type(pr_reg->pr_res_type));
+ spin_unlock(&dev->dev_reservation_lock);
+
+ return len;
+}
+
+SE_DEV_PR_ATTR_RO(res_pr_type);
+
+/*
+ * res_type
+ */
+static ssize_t target_core_dev_pr_show_attr_res_type(
+ struct se_subsystem_dev *su_dev,
+ char *page)
+{
+ ssize_t len = 0;
+
+ if (!(su_dev->se_dev_ptr))
+ return -ENODEV;
+
+ switch (T10_RES(su_dev)->res_type) {
+ case SPC3_PERSISTENT_RESERVATIONS:
+ len = sprintf(page, "SPC3_PERSISTENT_RESERVATIONS\n");
+ break;
+ case SPC2_RESERVATIONS:
+ len = sprintf(page, "SPC2_RESERVATIONS\n");
+ break;
+ case SPC_PASSTHROUGH:
+ len = sprintf(page, "SPC_PASSTHROUGH\n");
+ break;
+ default:
+ len = sprintf(page, "UNKNOWN\n");
+ break;
+ }
+
+ return len;
+}
+
+SE_DEV_PR_ATTR_RO(res_type);
+
+/*
+ * res_aptpl_active
+ */
+
+static ssize_t target_core_dev_pr_show_attr_res_aptpl_active(
+ struct se_subsystem_dev *su_dev,
+ char *page)
+{
+ if (!(su_dev->se_dev_ptr))
+ return -ENODEV;
+
+ if (T10_RES(su_dev)->res_type != SPC3_PERSISTENT_RESERVATIONS)
+ return 0;
+
+ return sprintf(page, "APTPL Bit Status: %s\n",
+ (T10_RES(su_dev)->pr_aptpl_active) ? "Activated" : "Disabled");
+}
+
+SE_DEV_PR_ATTR_RO(res_aptpl_active);
+
+/*
+ * res_aptpl_metadata
+ */
+static ssize_t target_core_dev_pr_show_attr_res_aptpl_metadata(
+ struct se_subsystem_dev *su_dev,
+ char *page)
+{
+ if (!(su_dev->se_dev_ptr))
+ return -ENODEV;
+
+ if (T10_RES(su_dev)->res_type != SPC3_PERSISTENT_RESERVATIONS)
+ return 0;
+
+ return sprintf(page, "Ready to process PR APTPL metadata..\n");
+}
+
+enum {
+ Opt_initiator_fabric, Opt_initiator_node, Opt_initiator_sid,
+ Opt_sa_res_key, Opt_res_holder, Opt_res_type, Opt_res_scope,
+ Opt_res_all_tg_pt, Opt_mapped_lun, Opt_target_fabric,
+ Opt_target_node, Opt_tpgt, Opt_port_rtpi, Opt_target_lun, Opt_err
+};
+
+static match_table_t tokens = {
+ {Opt_initiator_fabric, "initiator_fabric=%s"},
+ {Opt_initiator_node, "initiator_node=%s"},
+ {Opt_initiator_sid, "initiator_sid=%s"},
+ {Opt_sa_res_key, "sa_res_key=%s"},
+ {Opt_res_holder, "res_holder=%d"},
+ {Opt_res_type, "res_type=%d"},
+ {Opt_res_scope, "res_scope=%d"},
+ {Opt_res_all_tg_pt, "res_all_tg_pt=%d"},
+ {Opt_mapped_lun, "mapped_lun=%d"},
+ {Opt_target_fabric, "target_fabric=%s"},
+ {Opt_target_node, "target_node=%s"},
+ {Opt_tpgt, "tpgt=%d"},
+ {Opt_port_rtpi, "port_rtpi=%d"},
+ {Opt_target_lun, "target_lun=%d"},
+ {Opt_err, NULL}
+};
+
+static ssize_t target_core_dev_pr_store_attr_res_aptpl_metadata(
+ struct se_subsystem_dev *su_dev,
+ const char *page,
+ size_t count)
+{
+ struct se_device *dev;
+ unsigned char *i_fabric, *t_fabric, *i_port = NULL, *t_port = NULL;
+ unsigned char *isid = NULL;
+ char *orig, *ptr, *arg_p, *opts;
+ substring_t args[MAX_OPT_ARGS];
+ unsigned long long tmp_ll;
+ u64 sa_res_key = 0;
+ u32 mapped_lun = 0, target_lun = 0;
+ int ret = -1, res_holder = 0, all_tg_pt = 0, arg, token;
+ u16 port_rpti = 0, tpgt = 0;
+ u8 type = 0, scope;
+
+ dev = su_dev->se_dev_ptr;
+ if (!(dev))
+ return -ENODEV;
+
+ if (T10_RES(su_dev)->res_type != SPC3_PERSISTENT_RESERVATIONS)
+ return 0;
+
+ if (atomic_read(&dev->dev_export_obj.obj_access_count)) {
+ printk(KERN_INFO "Unable to process APTPL metadata while"
+ " active fabric exports exist\n");
+ return -EINVAL;
+ }
+
+ opts = kstrdup(page, GFP_KERNEL);
+ if (!opts)
+ return -ENOMEM;
+
+ orig = opts;
+ while ((ptr = strsep(&opts, ",")) != NULL) {
+ if (!*ptr)
+ continue;
+
+ token = match_token(ptr, tokens, args);
+ switch (token) {
+ case Opt_initiator_fabric:
+ i_fabric = match_strdup(&args[0]);
+ break;
+ case Opt_initiator_node:
+ i_port = match_strdup(&args[0]);
+ if (strlen(i_port) > PR_APTPL_MAX_IPORT_LEN) {
+ printk(KERN_ERR "APTPL metadata initiator_node="
+ " exceeds PR_APTPL_MAX_IPORT_LEN: %d\n",
+ PR_APTPL_MAX_IPORT_LEN);
+ ret = -EINVAL;
+ break;
+ }
+ break;
+ case Opt_initiator_sid:
+ isid = match_strdup(&args[0]);
+ if (strlen(isid) > PR_REG_ISID_LEN) {
+ printk(KERN_ERR "APTPL metadata initiator_isid"
+ "= exceeds PR_REG_ISID_LEN: %d\n",
+ PR_REG_ISID_LEN);
+ ret = -EINVAL;
+ break;
+ }
+ break;
+ case Opt_sa_res_key:
+ arg_p = match_strdup(&args[0]);
+ ret = strict_strtoull(arg_p, 0, &tmp_ll);
+ if (ret < 0) {
+ printk(KERN_ERR "strict_strtoull() failed for"
+ " sa_res_key=\n");
+ goto out;
+ }
+ sa_res_key = (u64)tmp_ll;
+ break;
+ /*
+ * PR APTPL Metadata for Reservation
+ */
+ case Opt_res_holder:
+ match_int(args, &arg);
+ res_holder = arg;
+ break;
+ case Opt_res_type:
+ match_int(args, &arg);
+ type = (u8)arg;
+ break;
+ case Opt_res_scope:
+ match_int(args, &arg);
+ scope = (u8)arg;
+ break;
+ case Opt_res_all_tg_pt:
+ match_int(args, &arg);
+ all_tg_pt = (int)arg;
+ break;
+ case Opt_mapped_lun:
+ match_int(args, &arg);
+ mapped_lun = (u32)arg;
+ break;
+ /*
+ * PR APTPL Metadata for Target Port
+ */
+ case Opt_target_fabric:
+ t_fabric = match_strdup(&args[0]);
+ break;
+ case Opt_target_node:
+ t_port = match_strdup(&args[0]);
+ if (strlen(t_port) > PR_APTPL_MAX_TPORT_LEN) {
+ printk(KERN_ERR "APTPL metadata target_node="
+ " exceeds PR_APTPL_MAX_TPORT_LEN: %d\n",
+ PR_APTPL_MAX_TPORT_LEN);
+ ret = -EINVAL;
+ break;
+ }
+ break;
+ case Opt_tpgt:
+ match_int(args, &arg);
+ tpgt = (u16)arg;
+ break;
+ case Opt_port_rtpi:
+ match_int(args, &arg);
+ port_rpti = (u16)arg;
+ break;
+ case Opt_target_lun:
+ match_int(args, &arg);
+ target_lun = (u32)arg;
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (!(i_port) || !(t_port) || !(sa_res_key)) {
+ printk(KERN_ERR "Illegal parameters for APTPL registration\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (res_holder && !(type)) {
+ printk(KERN_ERR "Illegal PR type: 0x%02x for reservation"
+ " holder\n", type);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ ret = core_scsi3_alloc_aptpl_registration(T10_RES(su_dev), sa_res_key,
+ i_port, isid, mapped_lun, t_port, tpgt, target_lun,
+ res_holder, all_tg_pt, type);
+out:
+ kfree(orig);
+ return (ret == 0) ? count : ret;
+}
+
+SE_DEV_PR_ATTR(res_aptpl_metadata, S_IRUGO | S_IWUSR);
+
+CONFIGFS_EATTR_OPS(target_core_dev_pr, se_subsystem_dev, se_dev_pr_group);
+
+static struct configfs_attribute *target_core_dev_pr_attrs[] = {
+ &target_core_dev_pr_res_holder.attr,
+ &target_core_dev_pr_res_pr_all_tgt_pts.attr,
+ &target_core_dev_pr_res_pr_generation.attr,
+ &target_core_dev_pr_res_pr_holder_tg_port.attr,
+ &target_core_dev_pr_res_pr_registered_i_pts.attr,
+ &target_core_dev_pr_res_pr_type.attr,
+ &target_core_dev_pr_res_type.attr,
+ &target_core_dev_pr_res_aptpl_active.attr,
+ &target_core_dev_pr_res_aptpl_metadata.attr,
+ NULL,
+};
+
+static struct configfs_item_operations target_core_dev_pr_ops = {
+ .show_attribute = target_core_dev_pr_attr_show,
+ .store_attribute = target_core_dev_pr_attr_store,
+};
+
+static struct config_item_type target_core_dev_pr_cit = {
+ .ct_item_ops = &target_core_dev_pr_ops,
+ .ct_attrs = target_core_dev_pr_attrs,
+ .ct_owner = THIS_MODULE,
+};
+
+/* End functions for struct config_item_type target_core_dev_pr_cit */
+
+/* Start functions for struct config_item_type target_core_dev_cit */
+
+static ssize_t target_core_show_dev_info(void *p, char *page)
+{
+ struct se_subsystem_dev *se_dev = (struct se_subsystem_dev *)p;
+ struct se_hba *hba = se_dev->se_dev_hba;
+ struct se_subsystem_api *t = hba->transport;
+ int bl = 0;
+ ssize_t read_bytes = 0;
+
+ if (!(se_dev->se_dev_ptr))
+ return -ENODEV;
+
+ transport_dump_dev_state(se_dev->se_dev_ptr, page, &bl);
+ read_bytes += bl;
+ read_bytes += t->show_configfs_dev_params(hba, se_dev, page+read_bytes);
+ return read_bytes;
+}
+
+static struct target_core_configfs_attribute target_core_attr_dev_info = {
+ .attr = { .ca_owner = THIS_MODULE,
+ .ca_name = "info",
+ .ca_mode = S_IRUGO },
+ .show = target_core_show_dev_info,
+ .store = NULL,
+};
+
+static ssize_t target_core_store_dev_control(
+ void *p,
+ const char *page,
+ size_t count)
+{
+ struct se_subsystem_dev *se_dev = (struct se_subsystem_dev *)p;
+ struct se_hba *hba = se_dev->se_dev_hba;
+ struct se_subsystem_api *t = hba->transport;
+
+ if (!(se_dev->se_dev_su_ptr)) {
+ printk(KERN_ERR "Unable to locate struct se_subsystem_dev>se"
+ "_dev_su_ptr\n");
+ return -EINVAL;
+ }
+
+ return t->set_configfs_dev_params(hba, se_dev, page, count);
+}
+
+static struct target_core_configfs_attribute target_core_attr_dev_control = {
+ .attr = { .ca_owner = THIS_MODULE,
+ .ca_name = "control",
+ .ca_mode = S_IWUSR },
+ .show = NULL,
+ .store = target_core_store_dev_control,
+};
+
+static ssize_t target_core_show_dev_alias(void *p, char *page)
+{
+ struct se_subsystem_dev *se_dev = (struct se_subsystem_dev *)p;
+
+ if (!(se_dev->su_dev_flags & SDF_USING_ALIAS))
+ return 0;
+
+ return snprintf(page, PAGE_SIZE, "%s\n", se_dev->se_dev_alias);
+}
+
+static ssize_t target_core_store_dev_alias(
+ void *p,
+ const char *page,
+ size_t count)
+{
+ struct se_subsystem_dev *se_dev = (struct se_subsystem_dev *)p;
+ struct se_hba *hba = se_dev->se_dev_hba;
+ ssize_t read_bytes;
+
+ if (count > (SE_DEV_ALIAS_LEN-1)) {
+ printk(KERN_ERR "alias count: %d exceeds"
+ " SE_DEV_ALIAS_LEN-1: %u\n", (int)count,
+ SE_DEV_ALIAS_LEN-1);
+ return -EINVAL;
+ }
+
+ se_dev->su_dev_flags |= SDF_USING_ALIAS;
+ read_bytes = snprintf(&se_dev->se_dev_alias[0], SE_DEV_ALIAS_LEN,
+ "%s", page);
+
+ printk(KERN_INFO "Target_Core_ConfigFS: %s/%s set alias: %s\n",
+ config_item_name(&hba->hba_group.cg_item),
+ config_item_name(&se_dev->se_dev_group.cg_item),
+ se_dev->se_dev_alias);
+
+ return read_bytes;
+}
+
+static struct target_core_configfs_attribute target_core_attr_dev_alias = {
+ .attr = { .ca_owner = THIS_MODULE,
+ .ca_name = "alias",
+ .ca_mode = S_IRUGO | S_IWUSR },
+ .show = target_core_show_dev_alias,
+ .store = target_core_store_dev_alias,
+};
+
+static ssize_t target_core_show_dev_udev_path(void *p, char *page)
+{
+ struct se_subsystem_dev *se_dev = (struct se_subsystem_dev *)p;
+
+ if (!(se_dev->su_dev_flags & SDF_USING_UDEV_PATH))
+ return 0;
+
+ return snprintf(page, PAGE_SIZE, "%s\n", se_dev->se_dev_udev_path);
+}
+
+static ssize_t target_core_store_dev_udev_path(
+ void *p,
+ const char *page,
+ size_t count)
+{
+ struct se_subsystem_dev *se_dev = (struct se_subsystem_dev *)p;
+ struct se_hba *hba = se_dev->se_dev_hba;
+ ssize_t read_bytes;
+
+ if (count > (SE_UDEV_PATH_LEN-1)) {
+ printk(KERN_ERR "udev_path count: %d exceeds"
+ " SE_UDEV_PATH_LEN-1: %u\n", (int)count,
+ SE_UDEV_PATH_LEN-1);
+ return -EINVAL;
+ }
+
+ se_dev->su_dev_flags |= SDF_USING_UDEV_PATH;
+ read_bytes = snprintf(&se_dev->se_dev_udev_path[0], SE_UDEV_PATH_LEN,
+ "%s", page);
+
+ printk(KERN_INFO "Target_Core_ConfigFS: %s/%s set udev_path: %s\n",
+ config_item_name(&hba->hba_group.cg_item),
+ config_item_name(&se_dev->se_dev_group.cg_item),
+ se_dev->se_dev_udev_path);
+
+ return read_bytes;
+}
+
+static struct target_core_configfs_attribute target_core_attr_dev_udev_path = {
+ .attr = { .ca_owner = THIS_MODULE,
+ .ca_name = "udev_path",
+ .ca_mode = S_IRUGO | S_IWUSR },
+ .show = target_core_show_dev_udev_path,
+ .store = target_core_store_dev_udev_path,
+};
+
+static ssize_t target_core_store_dev_enable(
+ void *p,
+ const char *page,
+ size_t count)
+{
+ struct se_subsystem_dev *se_dev = (struct se_subsystem_dev *)p;
+ struct se_device *dev;
+ struct se_hba *hba = se_dev->se_dev_hba;
+ struct se_subsystem_api *t = hba->transport;
+ char *ptr;
+
+ ptr = strstr(page, "1");
+ if (!(ptr)) {
+ printk(KERN_ERR "For dev_enable ops, only valid value"
+ " is \"1\"\n");
+ return -EINVAL;
+ }
+ if ((se_dev->se_dev_ptr)) {
+ printk(KERN_ERR "se_dev->se_dev_ptr already set for storage"
+ " object\n");
+ return -EEXIST;
+ }
+
+ if (t->check_configfs_dev_params(hba, se_dev) < 0)
+ return -EINVAL;
+
+ dev = t->create_virtdevice(hba, se_dev, se_dev->se_dev_su_ptr);
+ if (!(dev) || IS_ERR(dev))
+ return -EINVAL;
+
+ se_dev->se_dev_ptr = dev;
+ printk(KERN_INFO "Target_Core_ConfigFS: Registered se_dev->se_dev_ptr:"
+ " %p\n", se_dev->se_dev_ptr);
+
+ return count;
+}
+
+static struct target_core_configfs_attribute target_core_attr_dev_enable = {
+ .attr = { .ca_owner = THIS_MODULE,
+ .ca_name = "enable",
+ .ca_mode = S_IWUSR },
+ .show = NULL,
+ .store = target_core_store_dev_enable,
+};
+
+static ssize_t target_core_show_alua_lu_gp(void *p, char *page)
+{
+ struct se_device *dev;
+ struct se_subsystem_dev *su_dev = (struct se_subsystem_dev *)p;
+ struct config_item *lu_ci;
+ struct t10_alua_lu_gp *lu_gp;
+ struct t10_alua_lu_gp_member *lu_gp_mem;
+ ssize_t len = 0;
+
+ dev = su_dev->se_dev_ptr;
+ if (!(dev))
+ return -ENODEV;
+
+ if (T10_ALUA(su_dev)->alua_type != SPC3_ALUA_EMULATED)
+ return len;
+
+ lu_gp_mem = dev->dev_alua_lu_gp_mem;
+ if (!(lu_gp_mem)) {
+ printk(KERN_ERR "NULL struct se_device->dev_alua_lu_gp_mem"
+ " pointer\n");
+ return -EINVAL;
+ }
+
+ spin_lock(&lu_gp_mem->lu_gp_mem_lock);
+ lu_gp = lu_gp_mem->lu_gp;
+ if ((lu_gp)) {
+ lu_ci = &lu_gp->lu_gp_group.cg_item;
+ len += sprintf(page, "LU Group Alias: %s\nLU Group ID: %hu\n",
+ config_item_name(lu_ci), lu_gp->lu_gp_id);
+ }
+ spin_unlock(&lu_gp_mem->lu_gp_mem_lock);
+
+ return len;
+}
+
+static ssize_t target_core_store_alua_lu_gp(
+ void *p,
+ const char *page,
+ size_t count)
+{
+ struct se_device *dev;
+ struct se_subsystem_dev *su_dev = (struct se_subsystem_dev *)p;
+ struct se_hba *hba = su_dev->se_dev_hba;
+ struct t10_alua_lu_gp *lu_gp = NULL, *lu_gp_new = NULL;
+ struct t10_alua_lu_gp_member *lu_gp_mem;
+ unsigned char buf[LU_GROUP_NAME_BUF];
+ int move = 0;
+
+ dev = su_dev->se_dev_ptr;
+ if (!(dev))
+ return -ENODEV;
+
+ if (T10_ALUA(su_dev)->alua_type != SPC3_ALUA_EMULATED) {
+ printk(KERN_WARNING "SPC3_ALUA_EMULATED not enabled for %s/%s\n",
+ config_item_name(&hba->hba_group.cg_item),
+ config_item_name(&su_dev->se_dev_group.cg_item));
+ return -EINVAL;
+ }
+ if (count > LU_GROUP_NAME_BUF) {
+ printk(KERN_ERR "ALUA LU Group Alias too large!\n");
+ return -EINVAL;
+ }
+ memset(buf, 0, LU_GROUP_NAME_BUF);
+ memcpy(buf, page, count);
+ /*
+ * Any ALUA logical unit alias besides "NULL" means we will be
+ * making a new group association.
+ */
+ if (strcmp(strstrip(buf), "NULL")) {
+ /*
+ * core_alua_get_lu_gp_by_name() will increment reference to
+ * struct t10_alua_lu_gp. This reference is released with
+ * core_alua_get_lu_gp_by_name below().
+ */
+ lu_gp_new = core_alua_get_lu_gp_by_name(strstrip(buf));
+ if (!(lu_gp_new))
+ return -ENODEV;
+ }
+ lu_gp_mem = dev->dev_alua_lu_gp_mem;
+ if (!(lu_gp_mem)) {
+ if (lu_gp_new)
+ core_alua_put_lu_gp_from_name(lu_gp_new);
+ printk(KERN_ERR "NULL struct se_device->dev_alua_lu_gp_mem"
+ " pointer\n");
+ return -EINVAL;
+ }
+
+ spin_lock(&lu_gp_mem->lu_gp_mem_lock);
+ lu_gp = lu_gp_mem->lu_gp;
+ if ((lu_gp)) {
+ /*
+ * Clearing an existing lu_gp association, and replacing
+ * with NULL
+ */
+ if (!(lu_gp_new)) {
+ printk(KERN_INFO "Target_Core_ConfigFS: Releasing %s/%s"
+ " from ALUA LU Group: core/alua/lu_gps/%s, ID:"
+ " %hu\n",
+ config_item_name(&hba->hba_group.cg_item),
+ config_item_name(&su_dev->se_dev_group.cg_item),
+ config_item_name(&lu_gp->lu_gp_group.cg_item),
+ lu_gp->lu_gp_id);
+
+ __core_alua_drop_lu_gp_mem(lu_gp_mem, lu_gp);
+ spin_unlock(&lu_gp_mem->lu_gp_mem_lock);
+
+ return count;
+ }
+ /*
+ * Removing existing association of lu_gp_mem with lu_gp
+ */
+ __core_alua_drop_lu_gp_mem(lu_gp_mem, lu_gp);
+ move = 1;
+ }
+ /*
+ * Associate lu_gp_mem with lu_gp_new.
+ */
+ __core_alua_attach_lu_gp_mem(lu_gp_mem, lu_gp_new);
+ spin_unlock(&lu_gp_mem->lu_gp_mem_lock);
+
+ printk(KERN_INFO "Target_Core_ConfigFS: %s %s/%s to ALUA LU Group:"
+ " core/alua/lu_gps/%s, ID: %hu\n",
+ (move) ? "Moving" : "Adding",
+ config_item_name(&hba->hba_group.cg_item),
+ config_item_name(&su_dev->se_dev_group.cg_item),
+ config_item_name(&lu_gp_new->lu_gp_group.cg_item),
+ lu_gp_new->lu_gp_id);
+
+ core_alua_put_lu_gp_from_name(lu_gp_new);
+ return count;
+}
+
+static struct target_core_configfs_attribute target_core_attr_dev_alua_lu_gp = {
+ .attr = { .ca_owner = THIS_MODULE,
+ .ca_name = "alua_lu_gp",
+ .ca_mode = S_IRUGO | S_IWUSR },
+ .show = target_core_show_alua_lu_gp,
+ .store = target_core_store_alua_lu_gp,
+};
+
+static struct configfs_attribute *lio_core_dev_attrs[] = {
+ &target_core_attr_dev_info.attr,
+ &target_core_attr_dev_control.attr,
+ &target_core_attr_dev_alias.attr,
+ &target_core_attr_dev_udev_path.attr,
+ &target_core_attr_dev_enable.attr,
+ &target_core_attr_dev_alua_lu_gp.attr,
+ NULL,
+};
+
+static void target_core_dev_release(struct config_item *item)
+{
+ struct se_subsystem_dev *se_dev = container_of(to_config_group(item),
+ struct se_subsystem_dev, se_dev_group);
+ struct config_group *dev_cg;
+
+ if (!(se_dev))
+ return;
+
+ dev_cg = &se_dev->se_dev_group;
+ kfree(dev_cg->default_groups);
+}
+
+static ssize_t target_core_dev_show(struct config_item *item,
+ struct configfs_attribute *attr,
+ char *page)
+{
+ struct se_subsystem_dev *se_dev = container_of(
+ to_config_group(item), struct se_subsystem_dev,
+ se_dev_group);
+ struct target_core_configfs_attribute *tc_attr = container_of(
+ attr, struct target_core_configfs_attribute, attr);
+
+ if (!(tc_attr->show))
+ return -EINVAL;
+
+ return tc_attr->show((void *)se_dev, page);
+}
+
+static ssize_t target_core_dev_store(struct config_item *item,
+ struct configfs_attribute *attr,
+ const char *page, size_t count)
+{
+ struct se_subsystem_dev *se_dev = container_of(
+ to_config_group(item), struct se_subsystem_dev,
+ se_dev_group);
+ struct target_core_configfs_attribute *tc_attr = container_of(
+ attr, struct target_core_configfs_attribute, attr);
+
+ if (!(tc_attr->store))
+ return -EINVAL;
+
+ return tc_attr->store((void *)se_dev, page, count);
+}
+
+static struct configfs_item_operations target_core_dev_item_ops = {
+ .release = target_core_dev_release,
+ .show_attribute = target_core_dev_show,
+ .store_attribute = target_core_dev_store,
+};
+
+static struct config_item_type target_core_dev_cit = {
+ .ct_item_ops = &target_core_dev_item_ops,
+ .ct_attrs = lio_core_dev_attrs,
+ .ct_owner = THIS_MODULE,
+};
+
+/* End functions for struct config_item_type target_core_dev_cit */
+
+/* Start functions for struct config_item_type target_core_alua_lu_gp_cit */
+
+CONFIGFS_EATTR_STRUCT(target_core_alua_lu_gp, t10_alua_lu_gp);
+#define SE_DEV_ALUA_LU_ATTR(_name, _mode) \
+static struct target_core_alua_lu_gp_attribute \
+ target_core_alua_lu_gp_##_name = \
+ __CONFIGFS_EATTR(_name, _mode, \
+ target_core_alua_lu_gp_show_attr_##_name, \
+ target_core_alua_lu_gp_store_attr_##_name);
+
+#define SE_DEV_ALUA_LU_ATTR_RO(_name) \
+static struct target_core_alua_lu_gp_attribute \
+ target_core_alua_lu_gp_##_name = \
+ __CONFIGFS_EATTR_RO(_name, \
+ target_core_alua_lu_gp_show_attr_##_name);
+
+/*
+ * lu_gp_id
+ */
+static ssize_t target_core_alua_lu_gp_show_attr_lu_gp_id(
+ struct t10_alua_lu_gp *lu_gp,
+ char *page)
+{
+ if (!(lu_gp->lu_gp_valid_id))
+ return 0;
+
+ return sprintf(page, "%hu\n", lu_gp->lu_gp_id);
+}
+
+static ssize_t target_core_alua_lu_gp_store_attr_lu_gp_id(
+ struct t10_alua_lu_gp *lu_gp,
+ const char *page,
+ size_t count)
+{
+ struct config_group *alua_lu_gp_cg = &lu_gp->lu_gp_group;
+ unsigned long lu_gp_id;
+ int ret;
+
+ ret = strict_strtoul(page, 0, &lu_gp_id);
+ if (ret < 0) {
+ printk(KERN_ERR "strict_strtoul() returned %d for"
+ " lu_gp_id\n", ret);
+ return -EINVAL;
+ }
+ if (lu_gp_id > 0x0000ffff) {
+ printk(KERN_ERR "ALUA lu_gp_id: %lu exceeds maximum:"
+ " 0x0000ffff\n", lu_gp_id);
+ return -EINVAL;
+ }
+
+ ret = core_alua_set_lu_gp_id(lu_gp, (u16)lu_gp_id);
+ if (ret < 0)
+ return -EINVAL;
+
+ printk(KERN_INFO "Target_Core_ConfigFS: Set ALUA Logical Unit"
+ " Group: core/alua/lu_gps/%s to ID: %hu\n",
+ config_item_name(&alua_lu_gp_cg->cg_item),
+ lu_gp->lu_gp_id);
+
+ return count;
+}
+
+SE_DEV_ALUA_LU_ATTR(lu_gp_id, S_IRUGO | S_IWUSR);
+
+/*
+ * members
+ */
+static ssize_t target_core_alua_lu_gp_show_attr_members(
+ struct t10_alua_lu_gp *lu_gp,
+ char *page)
+{
+ struct se_device *dev;
+ struct se_hba *hba;
+ struct se_subsystem_dev *su_dev;
+ struct t10_alua_lu_gp_member *lu_gp_mem;
+ ssize_t len = 0, cur_len;
+ unsigned char buf[LU_GROUP_NAME_BUF];
+
+ memset(buf, 0, LU_GROUP_NAME_BUF);
+
+ spin_lock(&lu_gp->lu_gp_lock);
+ list_for_each_entry(lu_gp_mem, &lu_gp->lu_gp_mem_list, lu_gp_mem_list) {
+ dev = lu_gp_mem->lu_gp_mem_dev;
+ su_dev = dev->se_sub_dev;
+ hba = su_dev->se_dev_hba;
+
+ cur_len = snprintf(buf, LU_GROUP_NAME_BUF, "%s/%s\n",
+ config_item_name(&hba->hba_group.cg_item),
+ config_item_name(&su_dev->se_dev_group.cg_item));
+ cur_len++; /* Extra byte for NULL terminator */
+
+ if ((cur_len + len) > PAGE_SIZE) {
+ printk(KERN_WARNING "Ran out of lu_gp_show_attr"
+ "_members buffer\n");
+ break;
+ }
+ memcpy(page+len, buf, cur_len);
+ len += cur_len;
+ }
+ spin_unlock(&lu_gp->lu_gp_lock);
+
+ return len;
+}
+
+SE_DEV_ALUA_LU_ATTR_RO(members);
+
+CONFIGFS_EATTR_OPS(target_core_alua_lu_gp, t10_alua_lu_gp, lu_gp_group);
+
+static struct configfs_attribute *target_core_alua_lu_gp_attrs[] = {
+ &target_core_alua_lu_gp_lu_gp_id.attr,
+ &target_core_alua_lu_gp_members.attr,
+ NULL,
+};
+
+static struct configfs_item_operations target_core_alua_lu_gp_ops = {
+ .show_attribute = target_core_alua_lu_gp_attr_show,
+ .store_attribute = target_core_alua_lu_gp_attr_store,
+};
+
+static struct config_item_type target_core_alua_lu_gp_cit = {
+ .ct_item_ops = &target_core_alua_lu_gp_ops,
+ .ct_attrs = target_core_alua_lu_gp_attrs,
+ .ct_owner = THIS_MODULE,
+};
+
+/* End functions for struct config_item_type target_core_alua_lu_gp_cit */
+
+/* Start functions for struct config_item_type target_core_alua_lu_gps_cit */
+
+static struct config_group *target_core_alua_create_lu_gp(
+ struct config_group *group,
+ const char *name)
+{
+ struct t10_alua_lu_gp *lu_gp;
+ struct config_group *alua_lu_gp_cg = NULL;
+ struct config_item *alua_lu_gp_ci = NULL;
+
+ lu_gp = core_alua_allocate_lu_gp(name, 0);
+ if (IS_ERR(lu_gp))
+ return NULL;
+
+ alua_lu_gp_cg = &lu_gp->lu_gp_group;
+ alua_lu_gp_ci = &alua_lu_gp_cg->cg_item;
+
+ config_group_init_type_name(alua_lu_gp_cg, name,
+ &target_core_alua_lu_gp_cit);
+
+ printk(KERN_INFO "Target_Core_ConfigFS: Allocated ALUA Logical Unit"
+ " Group: core/alua/lu_gps/%s\n",
+ config_item_name(alua_lu_gp_ci));
+
+ return alua_lu_gp_cg;
+
+}
+
+static void target_core_alua_drop_lu_gp(
+ struct config_group *group,
+ struct config_item *item)
+{
+ struct t10_alua_lu_gp *lu_gp = container_of(to_config_group(item),
+ struct t10_alua_lu_gp, lu_gp_group);
+
+ printk(KERN_INFO "Target_Core_ConfigFS: Releasing ALUA Logical Unit"
+ " Group: core/alua/lu_gps/%s, ID: %hu\n",
+ config_item_name(item), lu_gp->lu_gp_id);
+
+ config_item_put(item);
+ core_alua_free_lu_gp(lu_gp);
+}
+
+static struct configfs_group_operations target_core_alua_lu_gps_group_ops = {
+ .make_group = &target_core_alua_create_lu_gp,
+ .drop_item = &target_core_alua_drop_lu_gp,
+};
+
+static struct config_item_type target_core_alua_lu_gps_cit = {
+ .ct_item_ops = NULL,
+ .ct_group_ops = &target_core_alua_lu_gps_group_ops,
+ .ct_owner = THIS_MODULE,
+};
+
+/* End functions for struct config_item_type target_core_alua_lu_gps_cit */
+
+/* Start functions for struct config_item_type target_core_alua_tg_pt_gp_cit */
+
+CONFIGFS_EATTR_STRUCT(target_core_alua_tg_pt_gp, t10_alua_tg_pt_gp);
+#define SE_DEV_ALUA_TG_PT_ATTR(_name, _mode) \
+static struct target_core_alua_tg_pt_gp_attribute \
+ target_core_alua_tg_pt_gp_##_name = \
+ __CONFIGFS_EATTR(_name, _mode, \
+ target_core_alua_tg_pt_gp_show_attr_##_name, \
+ target_core_alua_tg_pt_gp_store_attr_##_name);
+
+#define SE_DEV_ALUA_TG_PT_ATTR_RO(_name) \
+static struct target_core_alua_tg_pt_gp_attribute \
+ target_core_alua_tg_pt_gp_##_name = \
+ __CONFIGFS_EATTR_RO(_name, \
+ target_core_alua_tg_pt_gp_show_attr_##_name);
+
+/*
+ * alua_access_state
+ */
+static ssize_t target_core_alua_tg_pt_gp_show_attr_alua_access_state(
+ struct t10_alua_tg_pt_gp *tg_pt_gp,
+ char *page)
+{
+ return sprintf(page, "%d\n",
+ atomic_read(&tg_pt_gp->tg_pt_gp_alua_access_state));
+}
+
+static ssize_t target_core_alua_tg_pt_gp_store_attr_alua_access_state(
+ struct t10_alua_tg_pt_gp *tg_pt_gp,
+ const char *page,
+ size_t count)
+{
+ struct se_subsystem_dev *su_dev = tg_pt_gp->tg_pt_gp_su_dev;
+ unsigned long tmp;
+ int new_state, ret;
+
+ if (!(tg_pt_gp->tg_pt_gp_valid_id)) {
+ printk(KERN_ERR "Unable to do implict ALUA on non valid"
+ " tg_pt_gp ID: %hu\n", tg_pt_gp->tg_pt_gp_valid_id);
+ return -EINVAL;
+ }
+
+ ret = strict_strtoul(page, 0, &tmp);
+ if (ret < 0) {
+ printk("Unable to extract new ALUA access state from"
+ " %s\n", page);
+ return -EINVAL;
+ }
+ new_state = (int)tmp;
+
+ if (!(tg_pt_gp->tg_pt_gp_alua_access_type & TPGS_IMPLICT_ALUA)) {
+ printk(KERN_ERR "Unable to process implict configfs ALUA"
+ " transition while TPGS_IMPLICT_ALUA is diabled\n");
+ return -EINVAL;
+ }
+
+ ret = core_alua_do_port_transition(tg_pt_gp, su_dev->se_dev_ptr,
+ NULL, NULL, new_state, 0);
+ return (!ret) ? count : -EINVAL;
+}
+
+SE_DEV_ALUA_TG_PT_ATTR(alua_access_state, S_IRUGO | S_IWUSR);
+
+/*
+ * alua_access_status
+ */
+static ssize_t target_core_alua_tg_pt_gp_show_attr_alua_access_status(
+ struct t10_alua_tg_pt_gp *tg_pt_gp,
+ char *page)
+{
+ return sprintf(page, "%s\n",
+ core_alua_dump_status(tg_pt_gp->tg_pt_gp_alua_access_status));
+}
+
+static ssize_t target_core_alua_tg_pt_gp_store_attr_alua_access_status(
+ struct t10_alua_tg_pt_gp *tg_pt_gp,
+ const char *page,
+ size_t count)
+{
+ unsigned long tmp;
+ int new_status, ret;
+
+ if (!(tg_pt_gp->tg_pt_gp_valid_id)) {
+ printk(KERN_ERR "Unable to do set ALUA access status on non"
+ " valid tg_pt_gp ID: %hu\n",
+ tg_pt_gp->tg_pt_gp_valid_id);
+ return -EINVAL;
+ }
+
+ ret = strict_strtoul(page, 0, &tmp);
+ if (ret < 0) {
+ printk(KERN_ERR "Unable to extract new ALUA access status"
+ " from %s\n", page);
+ return -EINVAL;
+ }
+ new_status = (int)tmp;
+
+ if ((new_status != ALUA_STATUS_NONE) &&
+ (new_status != ALUA_STATUS_ALTERED_BY_EXPLICT_STPG) &&
+ (new_status != ALUA_STATUS_ALTERED_BY_IMPLICT_ALUA)) {
+ printk(KERN_ERR "Illegal ALUA access status: 0x%02x\n",
+ new_status);
+ return -EINVAL;
+ }
+
+ tg_pt_gp->tg_pt_gp_alua_access_status = new_status;
+ return count;
+}
+
+SE_DEV_ALUA_TG_PT_ATTR(alua_access_status, S_IRUGO | S_IWUSR);
+
+/*
+ * alua_access_type
+ */
+static ssize_t target_core_alua_tg_pt_gp_show_attr_alua_access_type(
+ struct t10_alua_tg_pt_gp *tg_pt_gp,
+ char *page)
+{
+ return core_alua_show_access_type(tg_pt_gp, page);
+}
+
+static ssize_t target_core_alua_tg_pt_gp_store_attr_alua_access_type(
+ struct t10_alua_tg_pt_gp *tg_pt_gp,
+ const char *page,
+ size_t count)
+{
+ return core_alua_store_access_type(tg_pt_gp, page, count);
+}
+
+SE_DEV_ALUA_TG_PT_ATTR(alua_access_type, S_IRUGO | S_IWUSR);
+
+/*
+ * alua_write_metadata
+ */
+static ssize_t target_core_alua_tg_pt_gp_show_attr_alua_write_metadata(
+ struct t10_alua_tg_pt_gp *tg_pt_gp,
+ char *page)
+{
+ return sprintf(page, "%d\n", tg_pt_gp->tg_pt_gp_write_metadata);
+}
+
+static ssize_t target_core_alua_tg_pt_gp_store_attr_alua_write_metadata(
+ struct t10_alua_tg_pt_gp *tg_pt_gp,
+ const char *page,
+ size_t count)
+{
+ unsigned long tmp;
+ int ret;
+
+ ret = strict_strtoul(page, 0, &tmp);
+ if (ret < 0) {
+ printk(KERN_ERR "Unable to extract alua_write_metadata\n");
+ return -EINVAL;
+ }
+
+ if ((tmp != 0) && (tmp != 1)) {
+ printk(KERN_ERR "Illegal value for alua_write_metadata:"
+ " %lu\n", tmp);
+ return -EINVAL;
+ }
+ tg_pt_gp->tg_pt_gp_write_metadata = (int)tmp;
+
+ return count;
+}
+
+SE_DEV_ALUA_TG_PT_ATTR(alua_write_metadata, S_IRUGO | S_IWUSR);
+
+
+
+/*
+ * nonop_delay_msecs
+ */
+static ssize_t target_core_alua_tg_pt_gp_show_attr_nonop_delay_msecs(
+ struct t10_alua_tg_pt_gp *tg_pt_gp,
+ char *page)
+{
+ return core_alua_show_nonop_delay_msecs(tg_pt_gp, page);
+
+}
+
+static ssize_t target_core_alua_tg_pt_gp_store_attr_nonop_delay_msecs(
+ struct t10_alua_tg_pt_gp *tg_pt_gp,
+ const char *page,
+ size_t count)
+{
+ return core_alua_store_nonop_delay_msecs(tg_pt_gp, page, count);
+}
+
+SE_DEV_ALUA_TG_PT_ATTR(nonop_delay_msecs, S_IRUGO | S_IWUSR);
+
+/*
+ * trans_delay_msecs
+ */
+static ssize_t target_core_alua_tg_pt_gp_show_attr_trans_delay_msecs(
+ struct t10_alua_tg_pt_gp *tg_pt_gp,
+ char *page)
+{
+ return core_alua_show_trans_delay_msecs(tg_pt_gp, page);
+}
+
+static ssize_t target_core_alua_tg_pt_gp_store_attr_trans_delay_msecs(
+ struct t10_alua_tg_pt_gp *tg_pt_gp,
+ const char *page,
+ size_t count)
+{
+ return core_alua_store_trans_delay_msecs(tg_pt_gp, page, count);
+}
+
+SE_DEV_ALUA_TG_PT_ATTR(trans_delay_msecs, S_IRUGO | S_IWUSR);
+
+/*
+ * preferred
+ */
+
+static ssize_t target_core_alua_tg_pt_gp_show_attr_preferred(
+ struct t10_alua_tg_pt_gp *tg_pt_gp,
+ char *page)
+{
+ return core_alua_show_preferred_bit(tg_pt_gp, page);
+}
+
+static ssize_t target_core_alua_tg_pt_gp_store_attr_preferred(
+ struct t10_alua_tg_pt_gp *tg_pt_gp,
+ const char *page,
+ size_t count)
+{
+ return core_alua_store_preferred_bit(tg_pt_gp, page, count);
+}
+
+SE_DEV_ALUA_TG_PT_ATTR(preferred, S_IRUGO | S_IWUSR);
+
+/*
+ * tg_pt_gp_id
+ */
+static ssize_t target_core_alua_tg_pt_gp_show_attr_tg_pt_gp_id(
+ struct t10_alua_tg_pt_gp *tg_pt_gp,
+ char *page)
+{
+ if (!(tg_pt_gp->tg_pt_gp_valid_id))
+ return 0;
+
+ return sprintf(page, "%hu\n", tg_pt_gp->tg_pt_gp_id);
+}
+
+static ssize_t target_core_alua_tg_pt_gp_store_attr_tg_pt_gp_id(
+ struct t10_alua_tg_pt_gp *tg_pt_gp,
+ const char *page,
+ size_t count)
+{
+ struct config_group *alua_tg_pt_gp_cg = &tg_pt_gp->tg_pt_gp_group;
+ unsigned long tg_pt_gp_id;
+ int ret;
+
+ ret = strict_strtoul(page, 0, &tg_pt_gp_id);
+ if (ret < 0) {
+ printk(KERN_ERR "strict_strtoul() returned %d for"
+ " tg_pt_gp_id\n", ret);
+ return -EINVAL;
+ }
+ if (tg_pt_gp_id > 0x0000ffff) {
+ printk(KERN_ERR "ALUA tg_pt_gp_id: %lu exceeds maximum:"
+ " 0x0000ffff\n", tg_pt_gp_id);
+ return -EINVAL;
+ }
+
+ ret = core_alua_set_tg_pt_gp_id(tg_pt_gp, (u16)tg_pt_gp_id);
+ if (ret < 0)
+ return -EINVAL;
+
+ printk(KERN_INFO "Target_Core_ConfigFS: Set ALUA Target Port Group: "
+ "core/alua/tg_pt_gps/%s to ID: %hu\n",
+ config_item_name(&alua_tg_pt_gp_cg->cg_item),
+ tg_pt_gp->tg_pt_gp_id);
+
+ return count;
+}
+
+SE_DEV_ALUA_TG_PT_ATTR(tg_pt_gp_id, S_IRUGO | S_IWUSR);
+
+/*
+ * members
+ */
+static ssize_t target_core_alua_tg_pt_gp_show_attr_members(
+ struct t10_alua_tg_pt_gp *tg_pt_gp,
+ char *page)
+{
+ struct se_port *port;
+ struct se_portal_group *tpg;
+ struct se_lun *lun;
+ struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem;
+ ssize_t len = 0, cur_len;
+ unsigned char buf[TG_PT_GROUP_NAME_BUF];
+
+ memset(buf, 0, TG_PT_GROUP_NAME_BUF);
+
+ spin_lock(&tg_pt_gp->tg_pt_gp_lock);
+ list_for_each_entry(tg_pt_gp_mem, &tg_pt_gp->tg_pt_gp_mem_list,
+ tg_pt_gp_mem_list) {
+ port = tg_pt_gp_mem->tg_pt;
+ tpg = port->sep_tpg;
+ lun = port->sep_lun;
+
+ cur_len = snprintf(buf, TG_PT_GROUP_NAME_BUF, "%s/%s/tpgt_%hu"
+ "/%s\n", TPG_TFO(tpg)->get_fabric_name(),
+ TPG_TFO(tpg)->tpg_get_wwn(tpg),
+ TPG_TFO(tpg)->tpg_get_tag(tpg),
+ config_item_name(&lun->lun_group.cg_item));
+ cur_len++; /* Extra byte for NULL terminator */
+
+ if ((cur_len + len) > PAGE_SIZE) {
+ printk(KERN_WARNING "Ran out of lu_gp_show_attr"
+ "_members buffer\n");
+ break;
+ }
+ memcpy(page+len, buf, cur_len);
+ len += cur_len;
+ }
+ spin_unlock(&tg_pt_gp->tg_pt_gp_lock);
+
+ return len;
+}
+
+SE_DEV_ALUA_TG_PT_ATTR_RO(members);
+
+CONFIGFS_EATTR_OPS(target_core_alua_tg_pt_gp, t10_alua_tg_pt_gp,
+ tg_pt_gp_group);
+
+static struct configfs_attribute *target_core_alua_tg_pt_gp_attrs[] = {
+ &target_core_alua_tg_pt_gp_alua_access_state.attr,
+ &target_core_alua_tg_pt_gp_alua_access_status.attr,
+ &target_core_alua_tg_pt_gp_alua_access_type.attr,
+ &target_core_alua_tg_pt_gp_alua_write_metadata.attr,
+ &target_core_alua_tg_pt_gp_nonop_delay_msecs.attr,
+ &target_core_alua_tg_pt_gp_trans_delay_msecs.attr,
+ &target_core_alua_tg_pt_gp_preferred.attr,
+ &target_core_alua_tg_pt_gp_tg_pt_gp_id.attr,
+ &target_core_alua_tg_pt_gp_members.attr,
+ NULL,
+};
+
+static struct configfs_item_operations target_core_alua_tg_pt_gp_ops = {
+ .show_attribute = target_core_alua_tg_pt_gp_attr_show,
+ .store_attribute = target_core_alua_tg_pt_gp_attr_store,
+};
+
+static struct config_item_type target_core_alua_tg_pt_gp_cit = {
+ .ct_item_ops = &target_core_alua_tg_pt_gp_ops,
+ .ct_attrs = target_core_alua_tg_pt_gp_attrs,
+ .ct_owner = THIS_MODULE,
+};
+
+/* End functions for struct config_item_type target_core_alua_tg_pt_gp_cit */
+
+/* Start functions for struct config_item_type target_core_alua_tg_pt_gps_cit */
+
+static struct config_group *target_core_alua_create_tg_pt_gp(
+ struct config_group *group,
+ const char *name)
+{
+ struct t10_alua *alua = container_of(group, struct t10_alua,
+ alua_tg_pt_gps_group);
+ struct t10_alua_tg_pt_gp *tg_pt_gp;
+ struct se_subsystem_dev *su_dev = alua->t10_sub_dev;
+ struct config_group *alua_tg_pt_gp_cg = NULL;
+ struct config_item *alua_tg_pt_gp_ci = NULL;
+
+ tg_pt_gp = core_alua_allocate_tg_pt_gp(su_dev, name, 0);
+ if (!(tg_pt_gp))
+ return NULL;
+
+ alua_tg_pt_gp_cg = &tg_pt_gp->tg_pt_gp_group;
+ alua_tg_pt_gp_ci = &alua_tg_pt_gp_cg->cg_item;
+
+ config_group_init_type_name(alua_tg_pt_gp_cg, name,
+ &target_core_alua_tg_pt_gp_cit);
+
+ printk(KERN_INFO "Target_Core_ConfigFS: Allocated ALUA Target Port"
+ " Group: alua/tg_pt_gps/%s\n",
+ config_item_name(alua_tg_pt_gp_ci));
+
+ return alua_tg_pt_gp_cg;
+}
+
+static void target_core_alua_drop_tg_pt_gp(
+ struct config_group *group,
+ struct config_item *item)
+{
+ struct t10_alua_tg_pt_gp *tg_pt_gp = container_of(to_config_group(item),
+ struct t10_alua_tg_pt_gp, tg_pt_gp_group);
+
+ printk(KERN_INFO "Target_Core_ConfigFS: Releasing ALUA Target Port"
+ " Group: alua/tg_pt_gps/%s, ID: %hu\n",
+ config_item_name(item), tg_pt_gp->tg_pt_gp_id);
+
+ config_item_put(item);
+ core_alua_free_tg_pt_gp(tg_pt_gp);
+}
+
+static struct configfs_group_operations target_core_alua_tg_pt_gps_group_ops = {
+ .make_group = &target_core_alua_create_tg_pt_gp,
+ .drop_item = &target_core_alua_drop_tg_pt_gp,
+};
+
+static struct config_item_type target_core_alua_tg_pt_gps_cit = {
+ .ct_group_ops = &target_core_alua_tg_pt_gps_group_ops,
+ .ct_owner = THIS_MODULE,
+};
+
+/* End functions for struct config_item_type target_core_alua_tg_pt_gps_cit */
+
+/* Start functions for struct config_item_type target_core_alua_cit */
+
+/*
+ * target_core_alua_cit is a ConfigFS group that lives under
+ * /sys/kernel/config/target/core/alua. There are default groups
+ * core/alua/lu_gps and core/alua/tg_pt_gps that are attached to
+ * target_core_alua_cit in target_core_init_configfs() below.
+ */
+static struct config_item_type target_core_alua_cit = {
+ .ct_item_ops = NULL,
+ .ct_attrs = NULL,
+ .ct_owner = THIS_MODULE,
+};
+
+/* End functions for struct config_item_type target_core_alua_cit */
+
+/* Start functions for struct config_item_type target_core_hba_cit */
+
+static struct config_group *target_core_make_subdev(
+ struct config_group *group,
+ const char *name)
+{
+ struct t10_alua_tg_pt_gp *tg_pt_gp;
+ struct se_subsystem_dev *se_dev;
+ struct se_subsystem_api *t;
+ struct config_item *hba_ci = &group->cg_item;
+ struct se_hba *hba = item_to_hba(hba_ci);
+ struct config_group *dev_cg = NULL, *tg_pt_gp_cg = NULL;
+
+ if (mutex_lock_interruptible(&hba->hba_access_mutex))
+ return NULL;
+
+ /*
+ * Locate the struct se_subsystem_api from parent's struct se_hba.
+ */
+ t = hba->transport;
+
+ se_dev = kzalloc(sizeof(struct se_subsystem_dev), GFP_KERNEL);
+ if (!se_dev) {
+ printk(KERN_ERR "Unable to allocate memory for"
+ " struct se_subsystem_dev\n");
+ goto unlock;
+ }
+ INIT_LIST_HEAD(&se_dev->g_se_dev_list);
+ INIT_LIST_HEAD(&se_dev->t10_wwn.t10_vpd_list);
+ spin_lock_init(&se_dev->t10_wwn.t10_vpd_lock);
+ INIT_LIST_HEAD(&se_dev->t10_reservation.registration_list);
+ INIT_LIST_HEAD(&se_dev->t10_reservation.aptpl_reg_list);
+ spin_lock_init(&se_dev->t10_reservation.registration_lock);
+ spin_lock_init(&se_dev->t10_reservation.aptpl_reg_lock);
+ INIT_LIST_HEAD(&se_dev->t10_alua.tg_pt_gps_list);
+ spin_lock_init(&se_dev->t10_alua.tg_pt_gps_lock);
+ spin_lock_init(&se_dev->se_dev_lock);
+ se_dev->t10_reservation.pr_aptpl_buf_len = PR_APTPL_BUF_LEN;
+ se_dev->t10_wwn.t10_sub_dev = se_dev;
+ se_dev->t10_alua.t10_sub_dev = se_dev;
+ se_dev->se_dev_attrib.da_sub_dev = se_dev;
+
+ se_dev->se_dev_hba = hba;
+ dev_cg = &se_dev->se_dev_group;
+
+ dev_cg->default_groups = kzalloc(sizeof(struct config_group) * 6,
+ GFP_KERNEL);
+ if (!(dev_cg->default_groups))
+ goto out;
+ /*
+ * Set se_dev_su_ptr from struct se_subsystem_api returned void ptr
+ * for ->allocate_virtdevice()
+ *
+ * se_dev->se_dev_ptr will be set after ->create_virtdev()
+ * has been called successfully in the next level up in the
+ * configfs tree for device object's struct config_group.
+ */
+ se_dev->se_dev_su_ptr = t->allocate_virtdevice(hba, name);
+ if (!(se_dev->se_dev_su_ptr)) {
+ printk(KERN_ERR "Unable to locate subsystem dependent pointer"
+ " from allocate_virtdevice()\n");
+ goto out;
+ }
+ spin_lock(&se_global->g_device_lock);
+ list_add_tail(&se_dev->g_se_dev_list, &se_global->g_se_dev_list);
+ spin_unlock(&se_global->g_device_lock);
+
+ config_group_init_type_name(&se_dev->se_dev_group, name,
+ &target_core_dev_cit);
+ config_group_init_type_name(&se_dev->se_dev_attrib.da_group, "attrib",
+ &target_core_dev_attrib_cit);
+ config_group_init_type_name(&se_dev->se_dev_pr_group, "pr",
+ &target_core_dev_pr_cit);
+ config_group_init_type_name(&se_dev->t10_wwn.t10_wwn_group, "wwn",
+ &target_core_dev_wwn_cit);
+ config_group_init_type_name(&se_dev->t10_alua.alua_tg_pt_gps_group,
+ "alua", &target_core_alua_tg_pt_gps_cit);
+ dev_cg->default_groups[0] = &se_dev->se_dev_attrib.da_group;
+ dev_cg->default_groups[1] = &se_dev->se_dev_pr_group;
+ dev_cg->default_groups[2] = &se_dev->t10_wwn.t10_wwn_group;
+ dev_cg->default_groups[3] = &se_dev->t10_alua.alua_tg_pt_gps_group;
+ dev_cg->default_groups[4] = NULL;
+ /*
+ * Add core/$HBA/$DEV/alua/tg_pt_gps/default_tg_pt_gp
+ */
+ tg_pt_gp = core_alua_allocate_tg_pt_gp(se_dev, "default_tg_pt_gp", 1);
+ if (!(tg_pt_gp))
+ goto out;
+
+ tg_pt_gp_cg = &T10_ALUA(se_dev)->alua_tg_pt_gps_group;
+ tg_pt_gp_cg->default_groups = kzalloc(sizeof(struct config_group) * 2,
+ GFP_KERNEL);
+ if (!(tg_pt_gp_cg->default_groups)) {
+ printk(KERN_ERR "Unable to allocate tg_pt_gp_cg->"
+ "default_groups\n");
+ goto out;
+ }
+
+ config_group_init_type_name(&tg_pt_gp->tg_pt_gp_group,
+ "default_tg_pt_gp", &target_core_alua_tg_pt_gp_cit);
+ tg_pt_gp_cg->default_groups[0] = &tg_pt_gp->tg_pt_gp_group;
+ tg_pt_gp_cg->default_groups[1] = NULL;
+ T10_ALUA(se_dev)->default_tg_pt_gp = tg_pt_gp;
+
+ printk(KERN_INFO "Target_Core_ConfigFS: Allocated struct se_subsystem_dev:"
+ " %p se_dev_su_ptr: %p\n", se_dev, se_dev->se_dev_su_ptr);
+
+ mutex_unlock(&hba->hba_access_mutex);
+ return &se_dev->se_dev_group;
+out:
+ if (T10_ALUA(se_dev)->default_tg_pt_gp) {
+ core_alua_free_tg_pt_gp(T10_ALUA(se_dev)->default_tg_pt_gp);
+ T10_ALUA(se_dev)->default_tg_pt_gp = NULL;
+ }
+ if (tg_pt_gp_cg)
+ kfree(tg_pt_gp_cg->default_groups);
+ if (dev_cg)
+ kfree(dev_cg->default_groups);
+ if (se_dev->se_dev_su_ptr)
+ t->free_device(se_dev->se_dev_su_ptr);
+ kfree(se_dev);
+unlock:
+ mutex_unlock(&hba->hba_access_mutex);
+ return NULL;
+}
+
+static void target_core_drop_subdev(
+ struct config_group *group,
+ struct config_item *item)
+{
+ struct se_subsystem_dev *se_dev = container_of(to_config_group(item),
+ struct se_subsystem_dev, se_dev_group);
+ struct se_hba *hba;
+ struct se_subsystem_api *t;
+ struct config_item *df_item;
+ struct config_group *dev_cg, *tg_pt_gp_cg;
+ int i, ret;
+
+ hba = item_to_hba(&se_dev->se_dev_hba->hba_group.cg_item);
+
+ if (mutex_lock_interruptible(&hba->hba_access_mutex))
+ goto out;
+
+ t = hba->transport;
+
+ spin_lock(&se_global->g_device_lock);
+ list_del(&se_dev->g_se_dev_list);
+ spin_unlock(&se_global->g_device_lock);
+
+ tg_pt_gp_cg = &T10_ALUA(se_dev)->alua_tg_pt_gps_group;
+ for (i = 0; tg_pt_gp_cg->default_groups[i]; i++) {
+ df_item = &tg_pt_gp_cg->default_groups[i]->cg_item;
+ tg_pt_gp_cg->default_groups[i] = NULL;
+ config_item_put(df_item);
+ }
+ kfree(tg_pt_gp_cg->default_groups);
+ core_alua_free_tg_pt_gp(T10_ALUA(se_dev)->default_tg_pt_gp);
+ T10_ALUA(se_dev)->default_tg_pt_gp = NULL;
+
+ dev_cg = &se_dev->se_dev_group;
+ for (i = 0; dev_cg->default_groups[i]; i++) {
+ df_item = &dev_cg->default_groups[i]->cg_item;
+ dev_cg->default_groups[i] = NULL;
+ config_item_put(df_item);
+ }
+
+ config_item_put(item);
+ /*
+ * This pointer will set when the storage is enabled with:
+ * `echo 1 > $CONFIGFS/core/$HBA/$DEV/dev_enable`
+ */
+ if (se_dev->se_dev_ptr) {
+ printk(KERN_INFO "Target_Core_ConfigFS: Calling se_free_"
+ "virtual_device() for se_dev_ptr: %p\n",
+ se_dev->se_dev_ptr);
+
+ ret = se_free_virtual_device(se_dev->se_dev_ptr, hba);
+ if (ret < 0)
+ goto hba_out;
+ } else {
+ /*
+ * Release struct se_subsystem_dev->se_dev_su_ptr..
+ */
+ printk(KERN_INFO "Target_Core_ConfigFS: Calling t->free_"
+ "device() for se_dev_su_ptr: %p\n",
+ se_dev->se_dev_su_ptr);
+
+ t->free_device(se_dev->se_dev_su_ptr);
+ }
+
+ printk(KERN_INFO "Target_Core_ConfigFS: Deallocating se_subsystem"
+ "_dev_t: %p\n", se_dev);
+
+hba_out:
+ mutex_unlock(&hba->hba_access_mutex);
+out:
+ kfree(se_dev);
+}
+
+static struct configfs_group_operations target_core_hba_group_ops = {
+ .make_group = target_core_make_subdev,
+ .drop_item = target_core_drop_subdev,
+};
+
+CONFIGFS_EATTR_STRUCT(target_core_hba, se_hba);
+#define SE_HBA_ATTR(_name, _mode) \
+static struct target_core_hba_attribute \
+ target_core_hba_##_name = \
+ __CONFIGFS_EATTR(_name, _mode, \
+ target_core_hba_show_attr_##_name, \
+ target_core_hba_store_attr_##_name);
+
+#define SE_HBA_ATTR_RO(_name) \
+static struct target_core_hba_attribute \
+ target_core_hba_##_name = \
+ __CONFIGFS_EATTR_RO(_name, \
+ target_core_hba_show_attr_##_name);
+
+static ssize_t target_core_hba_show_attr_hba_info(
+ struct se_hba *hba,
+ char *page)
+{
+ return sprintf(page, "HBA Index: %d plugin: %s version: %s\n",
+ hba->hba_id, hba->transport->name,
+ TARGET_CORE_CONFIGFS_VERSION);
+}
+
+SE_HBA_ATTR_RO(hba_info);
+
+static ssize_t target_core_hba_show_attr_hba_mode(struct se_hba *hba,
+ char *page)
+{
+ int hba_mode = 0;
+
+ if (hba->hba_flags & HBA_FLAGS_PSCSI_MODE)
+ hba_mode = 1;
+
+ return sprintf(page, "%d\n", hba_mode);
+}
+
+static ssize_t target_core_hba_store_attr_hba_mode(struct se_hba *hba,
+ const char *page, size_t count)
+{
+ struct se_subsystem_api *transport = hba->transport;
+ unsigned long mode_flag;
+ int ret;
+
+ if (transport->pmode_enable_hba == NULL)
+ return -EINVAL;
+
+ ret = strict_strtoul(page, 0, &mode_flag);
+ if (ret < 0) {
+ printk(KERN_ERR "Unable to extract hba mode flag: %d\n", ret);
+ return -EINVAL;
+ }
+
+ spin_lock(&hba->device_lock);
+ if (!(list_empty(&hba->hba_dev_list))) {
+ printk(KERN_ERR "Unable to set hba_mode with active devices\n");
+ spin_unlock(&hba->device_lock);
+ return -EINVAL;
+ }
+ spin_unlock(&hba->device_lock);
+
+ ret = transport->pmode_enable_hba(hba, mode_flag);
+ if (ret < 0)
+ return -EINVAL;
+ if (ret > 0)
+ hba->hba_flags |= HBA_FLAGS_PSCSI_MODE;
+ else if (ret == 0)
+ hba->hba_flags &= ~HBA_FLAGS_PSCSI_MODE;
+
+ return count;
+}
+
+SE_HBA_ATTR(hba_mode, S_IRUGO | S_IWUSR);
+
+CONFIGFS_EATTR_OPS(target_core_hba, se_hba, hba_group);
+
+static struct configfs_attribute *target_core_hba_attrs[] = {
+ &target_core_hba_hba_info.attr,
+ &target_core_hba_hba_mode.attr,
+ NULL,
+};
+
+static struct configfs_item_operations target_core_hba_item_ops = {
+ .show_attribute = target_core_hba_attr_show,
+ .store_attribute = target_core_hba_attr_store,
+};
+
+static struct config_item_type target_core_hba_cit = {
+ .ct_item_ops = &target_core_hba_item_ops,
+ .ct_group_ops = &target_core_hba_group_ops,
+ .ct_attrs = target_core_hba_attrs,
+ .ct_owner = THIS_MODULE,
+};
+
+static struct config_group *target_core_call_addhbatotarget(
+ struct config_group *group,
+ const char *name)
+{
+ char *se_plugin_str, *str, *str2;
+ struct se_hba *hba;
+ char buf[TARGET_CORE_NAME_MAX_LEN];
+ unsigned long plugin_dep_id = 0;
+ int ret;
+
+ memset(buf, 0, TARGET_CORE_NAME_MAX_LEN);
+ if (strlen(name) > TARGET_CORE_NAME_MAX_LEN) {
+ printk(KERN_ERR "Passed *name strlen(): %d exceeds"
+ " TARGET_CORE_NAME_MAX_LEN: %d\n", (int)strlen(name),
+ TARGET_CORE_NAME_MAX_LEN);
+ return ERR_PTR(-ENAMETOOLONG);
+ }
+ snprintf(buf, TARGET_CORE_NAME_MAX_LEN, "%s", name);
+
+ str = strstr(buf, "_");
+ if (!(str)) {
+ printk(KERN_ERR "Unable to locate \"_\" for $SUBSYSTEM_PLUGIN_$HOST_ID\n");
+ return ERR_PTR(-EINVAL);
+ }
+ se_plugin_str = buf;
+ /*
+ * Special case for subsystem plugins that have "_" in their names.
+ * Namely rd_direct and rd_mcp..
+ */
+ str2 = strstr(str+1, "_");
+ if ((str2)) {
+ *str2 = '\0'; /* Terminate for *se_plugin_str */
+ str2++; /* Skip to start of plugin dependent ID */
+ str = str2;
+ } else {
+ *str = '\0'; /* Terminate for *se_plugin_str */
+ str++; /* Skip to start of plugin dependent ID */
+ }
+
+ ret = strict_strtoul(str, 0, &plugin_dep_id);
+ if (ret < 0) {
+ printk(KERN_ERR "strict_strtoul() returned %d for"
+ " plugin_dep_id\n", ret);
+ return ERR_PTR(-EINVAL);
+ }
+ /*
+ * Load up TCM subsystem plugins if they have not already been loaded.
+ */
+ if (transport_subsystem_check_init() < 0)
+ return ERR_PTR(-EINVAL);
+
+ hba = core_alloc_hba(se_plugin_str, plugin_dep_id, 0);
+ if (IS_ERR(hba))
+ return ERR_CAST(hba);
+
+ config_group_init_type_name(&hba->hba_group, name,
+ &target_core_hba_cit);
+
+ return &hba->hba_group;
+}
+
+static void target_core_call_delhbafromtarget(
+ struct config_group *group,
+ struct config_item *item)
+{
+ struct se_hba *hba = item_to_hba(item);
+
+ config_item_put(item);
+ core_delete_hba(hba);
+}
+
+static struct configfs_group_operations target_core_group_ops = {
+ .make_group = target_core_call_addhbatotarget,
+ .drop_item = target_core_call_delhbafromtarget,
+};
+
+static struct config_item_type target_core_cit = {
+ .ct_item_ops = NULL,
+ .ct_group_ops = &target_core_group_ops,
+ .ct_attrs = NULL,
+ .ct_owner = THIS_MODULE,
+};
+
+/* Stop functions for struct config_item_type target_core_hba_cit */
+
+static int target_core_init_configfs(void)
+{
+ struct config_group *target_cg, *hba_cg = NULL, *alua_cg = NULL;
+ struct config_group *lu_gp_cg = NULL;
+ struct configfs_subsystem *subsys;
+ struct proc_dir_entry *scsi_target_proc = NULL;
+ struct t10_alua_lu_gp *lu_gp;
+ int ret;
+
+ printk(KERN_INFO "TARGET_CORE[0]: Loading Generic Kernel Storage"
+ " Engine: %s on %s/%s on "UTS_RELEASE"\n",
+ TARGET_CORE_VERSION, utsname()->sysname, utsname()->machine);
+
+ subsys = target_core_subsystem[0];
+ config_group_init(&subsys->su_group);
+ mutex_init(&subsys->su_mutex);
+
+ INIT_LIST_HEAD(&g_tf_list);
+ mutex_init(&g_tf_lock);
+ init_scsi_index_table();
+ ret = init_se_global();
+ if (ret < 0)
+ return -1;
+ /*
+ * Create $CONFIGFS/target/core default group for HBA <-> Storage Object
+ * and ALUA Logical Unit Group and Target Port Group infrastructure.
+ */
+ target_cg = &subsys->su_group;
+ target_cg->default_groups = kzalloc(sizeof(struct config_group) * 2,
+ GFP_KERNEL);
+ if (!(target_cg->default_groups)) {
+ printk(KERN_ERR "Unable to allocate target_cg->default_groups\n");
+ goto out_global;
+ }
+
+ config_group_init_type_name(&se_global->target_core_hbagroup,
+ "core", &target_core_cit);
+ target_cg->default_groups[0] = &se_global->target_core_hbagroup;
+ target_cg->default_groups[1] = NULL;
+ /*
+ * Create ALUA infrastructure under /sys/kernel/config/target/core/alua/
+ */
+ hba_cg = &se_global->target_core_hbagroup;
+ hba_cg->default_groups = kzalloc(sizeof(struct config_group) * 2,
+ GFP_KERNEL);
+ if (!(hba_cg->default_groups)) {
+ printk(KERN_ERR "Unable to allocate hba_cg->default_groups\n");
+ goto out_global;
+ }
+ config_group_init_type_name(&se_global->alua_group,
+ "alua", &target_core_alua_cit);
+ hba_cg->default_groups[0] = &se_global->alua_group;
+ hba_cg->default_groups[1] = NULL;
+ /*
+ * Add ALUA Logical Unit Group and Target Port Group ConfigFS
+ * groups under /sys/kernel/config/target/core/alua/
+ */
+ alua_cg = &se_global->alua_group;
+ alua_cg->default_groups = kzalloc(sizeof(struct config_group) * 2,
+ GFP_KERNEL);
+ if (!(alua_cg->default_groups)) {
+ printk(KERN_ERR "Unable to allocate alua_cg->default_groups\n");
+ goto out_global;
+ }
+
+ config_group_init_type_name(&se_global->alua_lu_gps_group,
+ "lu_gps", &target_core_alua_lu_gps_cit);
+ alua_cg->default_groups[0] = &se_global->alua_lu_gps_group;
+ alua_cg->default_groups[1] = NULL;
+ /*
+ * Add core/alua/lu_gps/default_lu_gp
+ */
+ lu_gp = core_alua_allocate_lu_gp("default_lu_gp", 1);
+ if (IS_ERR(lu_gp))
+ goto out_global;
+
+ lu_gp_cg = &se_global->alua_lu_gps_group;
+ lu_gp_cg->default_groups = kzalloc(sizeof(struct config_group) * 2,
+ GFP_KERNEL);
+ if (!(lu_gp_cg->default_groups)) {
+ printk(KERN_ERR "Unable to allocate lu_gp_cg->default_groups\n");
+ goto out_global;
+ }
+
+ config_group_init_type_name(&lu_gp->lu_gp_group, "default_lu_gp",
+ &target_core_alua_lu_gp_cit);
+ lu_gp_cg->default_groups[0] = &lu_gp->lu_gp_group;
+ lu_gp_cg->default_groups[1] = NULL;
+ se_global->default_lu_gp = lu_gp;
+ /*
+ * Register the target_core_mod subsystem with configfs.
+ */
+ ret = configfs_register_subsystem(subsys);
+ if (ret < 0) {
+ printk(KERN_ERR "Error %d while registering subsystem %s\n",
+ ret, subsys->su_group.cg_item.ci_namebuf);
+ goto out_global;
+ }
+ printk(KERN_INFO "TARGET_CORE[0]: Initialized ConfigFS Fabric"
+ " Infrastructure: "TARGET_CORE_CONFIGFS_VERSION" on %s/%s"
+ " on "UTS_RELEASE"\n", utsname()->sysname, utsname()->machine);
+ /*
+ * Register built-in RAMDISK subsystem logic for virtual LUN 0
+ */
+ ret = rd_module_init();
+ if (ret < 0)
+ goto out;
+
+ if (core_dev_setup_virtual_lun0() < 0)
+ goto out;
+
+ scsi_target_proc = proc_mkdir("scsi_target", 0);
+ if (!(scsi_target_proc)) {
+ printk(KERN_ERR "proc_mkdir(scsi_target, 0) failed\n");
+ goto out;
+ }
+ ret = init_scsi_target_mib();
+ if (ret < 0)
+ goto out;
+
+ return 0;
+
+out:
+ configfs_unregister_subsystem(subsys);
+ if (scsi_target_proc)
+ remove_proc_entry("scsi_target", 0);
+ core_dev_release_virtual_lun0();
+ rd_module_exit();
+out_global:
+ if (se_global->default_lu_gp) {
+ core_alua_free_lu_gp(se_global->default_lu_gp);
+ se_global->default_lu_gp = NULL;
+ }
+ if (lu_gp_cg)
+ kfree(lu_gp_cg->default_groups);
+ if (alua_cg)
+ kfree(alua_cg->default_groups);
+ if (hba_cg)
+ kfree(hba_cg->default_groups);
+ kfree(target_cg->default_groups);
+ release_se_global();
+ return -1;
+}
+
+static void target_core_exit_configfs(void)
+{
+ struct configfs_subsystem *subsys;
+ struct config_group *hba_cg, *alua_cg, *lu_gp_cg;
+ struct config_item *item;
+ int i;
+
+ se_global->in_shutdown = 1;
+ subsys = target_core_subsystem[0];
+
+ lu_gp_cg = &se_global->alua_lu_gps_group;
+ for (i = 0; lu_gp_cg->default_groups[i]; i++) {
+ item = &lu_gp_cg->default_groups[i]->cg_item;
+ lu_gp_cg->default_groups[i] = NULL;
+ config_item_put(item);
+ }
+ kfree(lu_gp_cg->default_groups);
+ core_alua_free_lu_gp(se_global->default_lu_gp);
+ se_global->default_lu_gp = NULL;
+
+ alua_cg = &se_global->alua_group;
+ for (i = 0; alua_cg->default_groups[i]; i++) {
+ item = &alua_cg->default_groups[i]->cg_item;
+ alua_cg->default_groups[i] = NULL;
+ config_item_put(item);
+ }
+ kfree(alua_cg->default_groups);
+
+ hba_cg = &se_global->target_core_hbagroup;
+ for (i = 0; hba_cg->default_groups[i]; i++) {
+ item = &hba_cg->default_groups[i]->cg_item;
+ hba_cg->default_groups[i] = NULL;
+ config_item_put(item);
+ }
+ kfree(hba_cg->default_groups);
+
+ for (i = 0; subsys->su_group.default_groups[i]; i++) {
+ item = &subsys->su_group.default_groups[i]->cg_item;
+ subsys->su_group.default_groups[i] = NULL;
+ config_item_put(item);
+ }
+ kfree(subsys->su_group.default_groups);
+
+ configfs_unregister_subsystem(subsys);
+ printk(KERN_INFO "TARGET_CORE[0]: Released ConfigFS Fabric"
+ " Infrastructure\n");
+
+ remove_scsi_target_mib();
+ remove_proc_entry("scsi_target", 0);
+ core_dev_release_virtual_lun0();
+ rd_module_exit();
+ release_se_global();
+
+ return;
+}
+
+MODULE_DESCRIPTION("Target_Core_Mod/ConfigFS");
+MODULE_AUTHOR("nab@Linux-iSCSI.org");
+MODULE_LICENSE("GPL");
+
+module_init(target_core_init_configfs);
+module_exit(target_core_exit_configfs);
diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c
new file mode 100644
index 0000000..317ce58
--- /dev/null
+++ b/drivers/target/target_core_device.c
@@ -0,0 +1,1694 @@
+/*******************************************************************************
+ * Filename: target_core_device.c (based on iscsi_target_device.c)
+ *
+ * This file contains the iSCSI Virtual Device and Disk Transport
+ * agnostic related functions.
+ *
+ * Copyright (c) 2003, 2004, 2005 PyX Technologies, Inc.
+ * Copyright (c) 2005-2006 SBE, Inc. All Rights Reserved.
+ * Copyright (c) 2007-2010 Rising Tide Systems
+ * Copyright (c) 2008-2010 Linux-iSCSI.org
+ *
+ * Nicholas A. Bellinger <nab@kernel.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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ ******************************************************************************/
+
+#include <linux/net.h>
+#include <linux/string.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/smp_lock.h>
+#include <linux/kthread.h>
+#include <linux/in.h>
+#include <net/sock.h>
+#include <net/tcp.h>
+#include <scsi/scsi.h>
+
+#include <target/target_core_base.h>
+#include <target/target_core_device.h>
+#include <target/target_core_tpg.h>
+#include <target/target_core_transport.h>
+#include <target/target_core_fabric_ops.h>
+
+#include "target_core_alua.h"
+#include "target_core_hba.h"
+#include "target_core_pr.h"
+#include "target_core_ua.h"
+
+static void se_dev_start(struct se_device *dev);
+static void se_dev_stop(struct se_device *dev);
+
+int transport_get_lun_for_cmd(
+ struct se_cmd *se_cmd,
+ unsigned char *cdb,
+ u32 unpacked_lun)
+{
+ struct se_dev_entry *deve;
+ struct se_lun *se_lun = NULL;
+ struct se_session *se_sess = SE_SESS(se_cmd);
+ unsigned long flags;
+ int read_only = 0;
+
+ spin_lock_irq(&SE_NODE_ACL(se_sess)->device_list_lock);
+ deve = se_cmd->se_deve =
+ &SE_NODE_ACL(se_sess)->device_list[unpacked_lun];
+ if (deve->lun_flags & TRANSPORT_LUNFLAGS_INITIATOR_ACCESS) {
+ if (se_cmd) {
+ deve->total_cmds++;
+ deve->total_bytes += se_cmd->data_length;
+
+ if (se_cmd->data_direction == DMA_TO_DEVICE) {
+ if (deve->lun_flags &
+ TRANSPORT_LUNFLAGS_READ_ONLY) {
+ read_only = 1;
+ goto out;
+ }
+ deve->write_bytes += se_cmd->data_length;
+ } else if (se_cmd->data_direction ==
+ DMA_FROM_DEVICE) {
+ deve->read_bytes += se_cmd->data_length;
+ }
+ }
+ deve->deve_cmds++;
+
+ se_lun = se_cmd->se_lun = deve->se_lun;
+ se_cmd->pr_res_key = deve->pr_res_key;
+ se_cmd->orig_fe_lun = unpacked_lun;
+ se_cmd->se_orig_obj_ptr = SE_LUN(se_cmd)->lun_se_dev;
+ se_cmd->se_cmd_flags |= SCF_SE_LUN_CMD;
+ }
+out:
+ spin_unlock_irq(&SE_NODE_ACL(se_sess)->device_list_lock);
+
+ if (!se_lun) {
+ if (read_only) {
+ se_cmd->scsi_sense_reason = TCM_WRITE_PROTECTED;
+ se_cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION;
+ printk("TARGET_CORE[%s]: Detected WRITE_PROTECTED LUN"
+ " Access for 0x%08x\n",
+ CMD_TFO(se_cmd)->get_fabric_name(),
+ unpacked_lun);
+ return -1;
+ } else {
+ /*
+ * Use the se_portal_group->tpg_virt_lun0 to allow for
+ * REPORT_LUNS, et al to be returned when no active
+ * MappedLUN=0 exists for this Initiator Port.
+ */
+ if (unpacked_lun != 0) {
+ se_cmd->scsi_sense_reason = TCM_NON_EXISTENT_LUN;
+ se_cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION;
+ printk("TARGET_CORE[%s]: Detected NON_EXISTENT_LUN"
+ " Access for 0x%08x\n",
+ CMD_TFO(se_cmd)->get_fabric_name(),
+ unpacked_lun);
+ return -1;
+ }
+ /*
+ * Force WRITE PROTECT for virtual LUN 0
+ */
+ if ((se_cmd->data_direction != DMA_FROM_DEVICE) &&
+ (se_cmd->data_direction != DMA_NONE)) {
+ se_cmd->scsi_sense_reason = TCM_WRITE_PROTECTED;
+ se_cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION;
+ return -1;
+ }
+#if 0
+ printk("TARGET_CORE[%s]: Using virtual LUN0! :-)\n",
+ CMD_TFO(se_cmd)->get_fabric_name());
+#endif
+ se_lun = se_cmd->se_lun = &se_sess->se_tpg->tpg_virt_lun0;
+ se_cmd->orig_fe_lun = 0;
+ se_cmd->se_orig_obj_ptr = SE_LUN(se_cmd)->lun_se_dev;
+ se_cmd->se_cmd_flags |= SCF_SE_LUN_CMD;
+ }
+ }
+ /*
+ * Determine if the struct se_lun is online.
+ */
+/* #warning FIXME: Check for LUN_RESET + UNIT Attention */
+ if (se_dev_check_online(se_lun->lun_se_dev) != 0) {
+ se_cmd->scsi_sense_reason = TCM_NON_EXISTENT_LUN;
+ se_cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION;
+ return -1;
+ }
+
+ {
+ struct se_device *dev = se_lun->lun_se_dev;
+ spin_lock(&dev->stats_lock);
+ dev->num_cmds++;
+ if (se_cmd->data_direction == DMA_TO_DEVICE)
+ dev->write_bytes += se_cmd->data_length;
+ else if (se_cmd->data_direction == DMA_FROM_DEVICE)
+ dev->read_bytes += se_cmd->data_length;
+ spin_unlock(&dev->stats_lock);
+ }
+
+ /*
+ * Add the iscsi_cmd_t to the struct se_lun's cmd list. This list is used
+ * for tracking state of struct se_cmds during LUN shutdown events.
+ */
+ spin_lock_irqsave(&se_lun->lun_cmd_lock, flags);
+ list_add_tail(&se_cmd->se_lun_list, &se_lun->lun_cmd_list);
+ atomic_set(&T_TASK(se_cmd)->transport_lun_active, 1);
+#if 0
+ printk(KERN_INFO "Adding ITT: 0x%08x to LUN LIST[%d]\n",
+ CMD_TFO(se_cmd)->get_task_tag(se_cmd), se_lun->unpacked_lun);
+#endif
+ spin_unlock_irqrestore(&se_lun->lun_cmd_lock, flags);
+
+ return 0;
+}
+EXPORT_SYMBOL(transport_get_lun_for_cmd);
+
+int transport_get_lun_for_tmr(
+ struct se_cmd *se_cmd,
+ u32 unpacked_lun)
+{
+ struct se_device *dev = NULL;
+ struct se_dev_entry *deve;
+ struct se_lun *se_lun = NULL;
+ struct se_session *se_sess = SE_SESS(se_cmd);
+ struct se_tmr_req *se_tmr = se_cmd->se_tmr_req;
+
+ spin_lock_irq(&SE_NODE_ACL(se_sess)->device_list_lock);
+ deve = se_cmd->se_deve =
+ &SE_NODE_ACL(se_sess)->device_list[unpacked_lun];
+ if (deve->lun_flags & TRANSPORT_LUNFLAGS_INITIATOR_ACCESS) {
+ se_lun = se_cmd->se_lun = se_tmr->tmr_lun = deve->se_lun;
+ dev = se_tmr->tmr_dev = se_lun->lun_se_dev;
+ se_cmd->pr_res_key = deve->pr_res_key;
+ se_cmd->orig_fe_lun = unpacked_lun;
+ se_cmd->se_orig_obj_ptr = SE_LUN(se_cmd)->lun_se_dev;
+/* se_cmd->se_cmd_flags |= SCF_SE_LUN_CMD; */
+ }
+ spin_unlock_irq(&SE_NODE_ACL(se_sess)->device_list_lock);
+
+ if (!se_lun) {
+ printk(KERN_INFO "TARGET_CORE[%s]: Detected NON_EXISTENT_LUN"
+ " Access for 0x%08x\n",
+ CMD_TFO(se_cmd)->get_fabric_name(),
+ unpacked_lun);
+ se_cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION;
+ return -1;
+ }
+ /*
+ * Determine if the struct se_lun is online.
+ */
+/* #warning FIXME: Check for LUN_RESET + UNIT Attention */
+ if (se_dev_check_online(se_lun->lun_se_dev) != 0) {
+ se_cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION;
+ return -1;
+ }
+
+ spin_lock(&dev->se_tmr_lock);
+ list_add_tail(&se_tmr->tmr_list, &dev->dev_tmr_list);
+ spin_unlock(&dev->se_tmr_lock);
+
+ return 0;
+}
+EXPORT_SYMBOL(transport_get_lun_for_tmr);
+
+/*
+ * This function is called from core_scsi3_emulate_pro_register_and_move()
+ * and core_scsi3_decode_spec_i_port(), and will increment &deve->pr_ref_count
+ * when a matching rtpi is found.
+ */
+struct se_dev_entry *core_get_se_deve_from_rtpi(
+ struct se_node_acl *nacl,
+ u16 rtpi)
+{
+ struct se_dev_entry *deve;
+ struct se_lun *lun;
+ struct se_port *port;
+ struct se_portal_group *tpg = nacl->se_tpg;
+ u32 i;
+
+ spin_lock_irq(&nacl->device_list_lock);
+ for (i = 0; i < TRANSPORT_MAX_LUNS_PER_TPG; i++) {
+ deve = &nacl->device_list[i];
+
+ if (!(deve->lun_flags & TRANSPORT_LUNFLAGS_INITIATOR_ACCESS))
+ continue;
+
+ lun = deve->se_lun;
+ if (!(lun)) {
+ printk(KERN_ERR "%s device entries device pointer is"
+ " NULL, but Initiator has access.\n",
+ TPG_TFO(tpg)->get_fabric_name());
+ continue;
+ }
+ port = lun->lun_sep;
+ if (!(port)) {
+ printk(KERN_ERR "%s device entries device pointer is"
+ " NULL, but Initiator has access.\n",
+ TPG_TFO(tpg)->get_fabric_name());
+ continue;
+ }
+ if (port->sep_rtpi != rtpi)
+ continue;
+
+ atomic_inc(&deve->pr_ref_count);
+ smp_mb__after_atomic_inc();
+ spin_unlock_irq(&nacl->device_list_lock);
+
+ return deve;
+ }
+ spin_unlock_irq(&nacl->device_list_lock);
+
+ return NULL;
+}
+
+int core_free_device_list_for_node(
+ struct se_node_acl *nacl,
+ struct se_portal_group *tpg)
+{
+ struct se_dev_entry *deve;
+ struct se_lun *lun;
+ u32 i;
+
+ if (!nacl->device_list)
+ return 0;
+
+ spin_lock_irq(&nacl->device_list_lock);
+ for (i = 0; i < TRANSPORT_MAX_LUNS_PER_TPG; i++) {
+ deve = &nacl->device_list[i];
+
+ if (!(deve->lun_flags & TRANSPORT_LUNFLAGS_INITIATOR_ACCESS))
+ continue;
+
+ if (!deve->se_lun) {
+ printk(KERN_ERR "%s device entries device pointer is"
+ " NULL, but Initiator has access.\n",
+ TPG_TFO(tpg)->get_fabric_name());
+ continue;
+ }
+ lun = deve->se_lun;
+
+ spin_unlock_irq(&nacl->device_list_lock);
+ core_update_device_list_for_node(lun, NULL, deve->mapped_lun,
+ TRANSPORT_LUNFLAGS_NO_ACCESS, nacl, tpg, 0);
+ spin_lock_irq(&nacl->device_list_lock);
+ }
+ spin_unlock_irq(&nacl->device_list_lock);
+
+ kfree(nacl->device_list);
+ nacl->device_list = NULL;
+
+ return 0;
+}
+
+void core_dec_lacl_count(struct se_node_acl *se_nacl, struct se_cmd *se_cmd)
+{
+ struct se_dev_entry *deve;
+
+ spin_lock_irq(&se_nacl->device_list_lock);
+ deve = &se_nacl->device_list[se_cmd->orig_fe_lun];
+ deve->deve_cmds--;
+ spin_unlock_irq(&se_nacl->device_list_lock);
+
+ return;
+}
+
+void core_update_device_list_access(
+ u32 mapped_lun,
+ u32 lun_access,
+ struct se_node_acl *nacl)
+{
+ struct se_dev_entry *deve;
+
+ spin_lock_irq(&nacl->device_list_lock);
+ deve = &nacl->device_list[mapped_lun];
+ if (lun_access & TRANSPORT_LUNFLAGS_READ_WRITE) {
+ deve->lun_flags &= ~TRANSPORT_LUNFLAGS_READ_ONLY;
+ deve->lun_flags |= TRANSPORT_LUNFLAGS_READ_WRITE;
+ } else {
+ deve->lun_flags &= ~TRANSPORT_LUNFLAGS_READ_WRITE;
+ deve->lun_flags |= TRANSPORT_LUNFLAGS_READ_ONLY;
+ }
+ spin_unlock_irq(&nacl->device_list_lock);
+
+ return;
+}
+
+/* core_update_device_list_for_node():
+ *
+ *
+ */
+int core_update_device_list_for_node(
+ struct se_lun *lun,
+ struct se_lun_acl *lun_acl,
+ u32 mapped_lun,
+ u32 lun_access,
+ struct se_node_acl *nacl,
+ struct se_portal_group *tpg,
+ int enable)
+{
+ struct se_port *port = lun->lun_sep;
+ struct se_dev_entry *deve = &nacl->device_list[mapped_lun];
+ int trans = 0;
+ /*
+ * If the MappedLUN entry is being disabled, the entry in
+ * port->sep_alua_list must be removed now before clearing the
+ * struct se_dev_entry pointers below as logic in
+ * core_alua_do_transition_tg_pt() depends on these being present.
+ */
+ if (!(enable)) {
+ /*
+ * deve->se_lun_acl will be NULL for demo-mode created LUNs
+ * that have not been explictly concerted to MappedLUNs ->
+ * struct se_lun_acl.
+ */
+ if (!(deve->se_lun_acl))
+ return 0;
+
+ spin_lock_bh(&port->sep_alua_lock);
+ list_del(&deve->alua_port_list);
+ spin_unlock_bh(&port->sep_alua_lock);
+ }
+
+ spin_lock_irq(&nacl->device_list_lock);
+ if (enable) {
+ /*
+ * Check if the call is handling demo mode -> explict LUN ACL
+ * transition. This transition must be for the same struct se_lun
+ * + mapped_lun that was setup in demo mode..
+ */
+ if (deve->lun_flags & TRANSPORT_LUNFLAGS_INITIATOR_ACCESS) {
+ if (deve->se_lun_acl != NULL) {
+ printk(KERN_ERR "struct se_dev_entry->se_lun_acl"
+ " already set for demo mode -> explict"
+ " LUN ACL transition\n");
+ return -1;
+ }
+ if (deve->se_lun != lun) {
+ printk(KERN_ERR "struct se_dev_entry->se_lun does"
+ " match passed struct se_lun for demo mode"
+ " -> explict LUN ACL transition\n");
+ return -1;
+ }
+ deve->se_lun_acl = lun_acl;
+ trans = 1;
+ } else {
+ deve->se_lun = lun;
+ deve->se_lun_acl = lun_acl;
+ deve->mapped_lun = mapped_lun;
+ deve->lun_flags |= TRANSPORT_LUNFLAGS_INITIATOR_ACCESS;
+ }
+
+ if (lun_access & TRANSPORT_LUNFLAGS_READ_WRITE) {
+ deve->lun_flags &= ~TRANSPORT_LUNFLAGS_READ_ONLY;
+ deve->lun_flags |= TRANSPORT_LUNFLAGS_READ_WRITE;
+ } else {
+ deve->lun_flags &= ~TRANSPORT_LUNFLAGS_READ_WRITE;
+ deve->lun_flags |= TRANSPORT_LUNFLAGS_READ_ONLY;
+ }
+
+ if (trans) {
+ spin_unlock_irq(&nacl->device_list_lock);
+ return 0;
+ }
+ deve->creation_time = get_jiffies_64();
+ deve->attach_count++;
+ spin_unlock_irq(&nacl->device_list_lock);
+
+ spin_lock_bh(&port->sep_alua_lock);
+ list_add_tail(&deve->alua_port_list, &port->sep_alua_list);
+ spin_unlock_bh(&port->sep_alua_lock);
+
+ return 0;
+ }
+ /*
+ * Wait for any in process SPEC_I_PT=1 or REGISTER_AND_MOVE
+ * PR operation to complete.
+ */
+ spin_unlock_irq(&nacl->device_list_lock);
+ while (atomic_read(&deve->pr_ref_count) != 0)
+ cpu_relax();
+ spin_lock_irq(&nacl->device_list_lock);
+ /*
+ * Disable struct se_dev_entry LUN ACL mapping
+ */
+ core_scsi3_ua_release_all(deve);
+ deve->se_lun = NULL;
+ deve->se_lun_acl = NULL;
+ deve->lun_flags = 0;
+ deve->creation_time = 0;
+ deve->attach_count--;
+ spin_unlock_irq(&nacl->device_list_lock);
+
+ core_scsi3_free_pr_reg_from_nacl(lun->lun_se_dev, nacl);
+ return 0;
+}
+
+/* core_clear_lun_from_tpg():
+ *
+ *
+ */
+void core_clear_lun_from_tpg(struct se_lun *lun, struct se_portal_group *tpg)
+{
+ struct se_node_acl *nacl;
+ struct se_dev_entry *deve;
+ u32 i;
+
+ spin_lock_bh(&tpg->acl_node_lock);
+ list_for_each_entry(nacl, &tpg->acl_node_list, acl_list) {
+ spin_unlock_bh(&tpg->acl_node_lock);
+
+ spin_lock_irq(&nacl->device_list_lock);
+ for (i = 0; i < TRANSPORT_MAX_LUNS_PER_TPG; i++) {
+ deve = &nacl->device_list[i];
+ if (lun != deve->se_lun)
+ continue;
+ spin_unlock_irq(&nacl->device_list_lock);
+
+ core_update_device_list_for_node(lun, NULL,
+ deve->mapped_lun, TRANSPORT_LUNFLAGS_NO_ACCESS,
+ nacl, tpg, 0);
+
+ spin_lock_irq(&nacl->device_list_lock);
+ }
+ spin_unlock_irq(&nacl->device_list_lock);
+
+ spin_lock_bh(&tpg->acl_node_lock);
+ }
+ spin_unlock_bh(&tpg->acl_node_lock);
+
+ return;
+}
+
+static struct se_port *core_alloc_port(struct se_device *dev)
+{
+ struct se_port *port, *port_tmp;
+
+ port = kzalloc(sizeof(struct se_port), GFP_KERNEL);
+ if (!(port)) {
+ printk(KERN_ERR "Unable to allocate struct se_port\n");
+ return NULL;
+ }
+ INIT_LIST_HEAD(&port->sep_alua_list);
+ INIT_LIST_HEAD(&port->sep_list);
+ atomic_set(&port->sep_tg_pt_secondary_offline, 0);
+ spin_lock_init(&port->sep_alua_lock);
+ mutex_init(&port->sep_tg_pt_md_mutex);
+
+ spin_lock(&dev->se_port_lock);
+ if (dev->dev_port_count == 0x0000ffff) {
+ printk(KERN_WARNING "Reached dev->dev_port_count =="
+ " 0x0000ffff\n");
+ spin_unlock(&dev->se_port_lock);
+ return NULL;
+ }
+again:
+ /*
+ * Allocate the next RELATIVE TARGET PORT IDENTIFER for this struct se_device
+ * Here is the table from spc4r17 section 7.7.3.8.
+ *
+ * Table 473 -- RELATIVE TARGET PORT IDENTIFIER field
+ *
+ * Code Description
+ * 0h Reserved
+ * 1h Relative port 1, historically known as port A
+ * 2h Relative port 2, historically known as port B
+ * 3h to FFFFh Relative port 3 through 65 535
+ */
+ port->sep_rtpi = dev->dev_rpti_counter++;
+ if (!(port->sep_rtpi))
+ goto again;
+
+ list_for_each_entry(port_tmp, &dev->dev_sep_list, sep_list) {
+ /*
+ * Make sure RELATIVE TARGET PORT IDENTIFER is unique
+ * for 16-bit wrap..
+ */
+ if (port->sep_rtpi == port_tmp->sep_rtpi)
+ goto again;
+ }
+ spin_unlock(&dev->se_port_lock);
+
+ return port;
+}
+
+static void core_export_port(
+ struct se_device *dev,
+ struct se_portal_group *tpg,
+ struct se_port *port,
+ struct se_lun *lun)
+{
+ struct se_subsystem_dev *su_dev = SU_DEV(dev);
+ struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem = NULL;
+
+ spin_lock(&dev->se_port_lock);
+ spin_lock(&lun->lun_sep_lock);
+ port->sep_tpg = tpg;
+ port->sep_lun = lun;
+ lun->lun_sep = port;
+ spin_unlock(&lun->lun_sep_lock);
+
+ list_add_tail(&port->sep_list, &dev->dev_sep_list);
+ spin_unlock(&dev->se_port_lock);
+
+ if (T10_ALUA(su_dev)->alua_type == SPC3_ALUA_EMULATED) {
+ tg_pt_gp_mem = core_alua_allocate_tg_pt_gp_mem(port);
+ if (IS_ERR(tg_pt_gp_mem) || !tg_pt_gp_mem) {
+ printk(KERN_ERR "Unable to allocate t10_alua_tg_pt"
+ "_gp_member_t\n");
+ return;
+ }
+ spin_lock(&tg_pt_gp_mem->tg_pt_gp_mem_lock);
+ __core_alua_attach_tg_pt_gp_mem(tg_pt_gp_mem,
+ T10_ALUA(su_dev)->default_tg_pt_gp);
+ spin_unlock(&tg_pt_gp_mem->tg_pt_gp_mem_lock);
+ printk(KERN_INFO "%s/%s: Adding to default ALUA Target Port"
+ " Group: alua/default_tg_pt_gp\n",
+ TRANSPORT(dev)->name, TPG_TFO(tpg)->get_fabric_name());
+ }
+
+ dev->dev_port_count++;
+ port->sep_index = port->sep_rtpi; /* RELATIVE TARGET PORT IDENTIFER */
+}
+
+/*
+ * Called with struct se_device->se_port_lock spinlock held.
+ */
+static void core_release_port(struct se_device *dev, struct se_port *port)
+{
+ /*
+ * Wait for any port reference for PR ALL_TG_PT=1 operation
+ * to complete in __core_scsi3_alloc_registration()
+ */
+ spin_unlock(&dev->se_port_lock);
+ if (atomic_read(&port->sep_tg_pt_ref_cnt))
+ cpu_relax();
+ spin_lock(&dev->se_port_lock);
+
+ core_alua_free_tg_pt_gp_mem(port);
+
+ list_del(&port->sep_list);
+ dev->dev_port_count--;
+ kfree(port);
+
+ return;
+}
+
+int core_dev_export(
+ struct se_device *dev,
+ struct se_portal_group *tpg,
+ struct se_lun *lun)
+{
+ struct se_port *port;
+
+ port = core_alloc_port(dev);
+ if (!(port))
+ return -1;
+
+ lun->lun_se_dev = dev;
+ se_dev_start(dev);
+
+ atomic_inc(&dev->dev_export_obj.obj_access_count);
+ core_export_port(dev, tpg, port, lun);
+ return 0;
+}
+
+void core_dev_unexport(
+ struct se_device *dev,
+ struct se_portal_group *tpg,
+ struct se_lun *lun)
+{
+ struct se_port *port = lun->lun_sep;
+
+ spin_lock(&lun->lun_sep_lock);
+ if (lun->lun_se_dev == NULL) {
+ spin_unlock(&lun->lun_sep_lock);
+ return;
+ }
+ spin_unlock(&lun->lun_sep_lock);
+
+ spin_lock(&dev->se_port_lock);
+ atomic_dec(&dev->dev_export_obj.obj_access_count);
+ core_release_port(dev, port);
+ spin_unlock(&dev->se_port_lock);
+
+ se_dev_stop(dev);
+ lun->lun_se_dev = NULL;
+}
+
+int transport_core_report_lun_response(struct se_cmd *se_cmd)
+{
+ struct se_dev_entry *deve;
+ struct se_lun *se_lun;
+ struct se_session *se_sess = SE_SESS(se_cmd);
+ struct se_task *se_task;
+ unsigned char *buf = (unsigned char *)T_TASK(se_cmd)->t_task_buf;
+ u32 cdb_offset = 0, lun_count = 0, offset = 8;
+ u64 i, lun;
+
+ list_for_each_entry(se_task, &T_TASK(se_cmd)->t_task_list, t_list)
+ break;
+
+ if (!(se_task)) {
+ printk(KERN_ERR "Unable to locate struct se_task for struct se_cmd\n");
+ return PYX_TRANSPORT_LU_COMM_FAILURE;
+ }
+
+ /*
+ * If no struct se_session pointer is present, this struct se_cmd is
+ * coming via a target_core_mod PASSTHROUGH op, and not through
+ * a $FABRIC_MOD. In that case, report LUN=0 only.
+ */
+ if (!(se_sess)) {
+ lun = 0;
+ buf[offset++] = ((lun >> 56) & 0xff);
+ buf[offset++] = ((lun >> 48) & 0xff);
+ buf[offset++] = ((lun >> 40) & 0xff);
+ buf[offset++] = ((lun >> 32) & 0xff);
+ buf[offset++] = ((lun >> 24) & 0xff);
+ buf[offset++] = ((lun >> 16) & 0xff);
+ buf[offset++] = ((lun >> 8) & 0xff);
+ buf[offset++] = (lun & 0xff);
+ lun_count = 1;
+ goto done;
+ }
+
+ spin_lock_irq(&SE_NODE_ACL(se_sess)->device_list_lock);
+ for (i = 0; i < TRANSPORT_MAX_LUNS_PER_TPG; i++) {
+ deve = &SE_NODE_ACL(se_sess)->device_list[i];
+ if (!(deve->lun_flags & TRANSPORT_LUNFLAGS_INITIATOR_ACCESS))
+ continue;
+ se_lun = deve->se_lun;
+ /*
+ * We determine the correct LUN LIST LENGTH even once we
+ * have reached the initial allocation length.
+ * See SPC2-R20 7.19.
+ */
+ lun_count++;
+ if ((cdb_offset + 8) >= se_cmd->data_length)
+ continue;
+
+ lun = cpu_to_be64(CMD_TFO(se_cmd)->pack_lun(deve->mapped_lun));
+ buf[offset++] = ((lun >> 56) & 0xff);
+ buf[offset++] = ((lun >> 48) & 0xff);
+ buf[offset++] = ((lun >> 40) & 0xff);
+ buf[offset++] = ((lun >> 32) & 0xff);
+ buf[offset++] = ((lun >> 24) & 0xff);
+ buf[offset++] = ((lun >> 16) & 0xff);
+ buf[offset++] = ((lun >> 8) & 0xff);
+ buf[offset++] = (lun & 0xff);
+ cdb_offset += 8;
+ }
+ spin_unlock_irq(&SE_NODE_ACL(se_sess)->device_list_lock);
+
+ /*
+ * See SPC3 r07, page 159.
+ */
+done:
+ lun_count *= 8;
+ buf[0] = ((lun_count >> 24) & 0xff);
+ buf[1] = ((lun_count >> 16) & 0xff);
+ buf[2] = ((lun_count >> 8) & 0xff);
+ buf[3] = (lun_count & 0xff);
+
+ return PYX_TRANSPORT_SENT_TO_TRANSPORT;
+}
+
+/* se_release_device_for_hba():
+ *
+ *
+ */
+void se_release_device_for_hba(struct se_device *dev)
+{
+ struct se_hba *hba = dev->se_hba;
+
+ if ((dev->dev_status & TRANSPORT_DEVICE_ACTIVATED) ||
+ (dev->dev_status & TRANSPORT_DEVICE_DEACTIVATED) ||
+ (dev->dev_status & TRANSPORT_DEVICE_SHUTDOWN) ||
+ (dev->dev_status & TRANSPORT_DEVICE_OFFLINE_ACTIVATED) ||
+ (dev->dev_status & TRANSPORT_DEVICE_OFFLINE_DEACTIVATED))
+ se_dev_stop(dev);
+
+ if (dev->dev_ptr) {
+ kthread_stop(dev->process_thread);
+ if (dev->transport->free_device)
+ dev->transport->free_device(dev->dev_ptr);
+ }
+
+ spin_lock(&hba->device_lock);
+ list_del(&dev->dev_list);
+ hba->dev_count--;
+ spin_unlock(&hba->device_lock);
+
+ core_scsi3_free_all_registrations(dev);
+ se_release_vpd_for_dev(dev);
+
+ kfree(dev->dev_status_queue_obj);
+ kfree(dev->dev_queue_obj);
+ kfree(dev);
+
+ return;
+}
+
+void se_release_vpd_for_dev(struct se_device *dev)
+{
+ struct t10_vpd *vpd, *vpd_tmp;
+
+ spin_lock(&DEV_T10_WWN(dev)->t10_vpd_lock);
+ list_for_each_entry_safe(vpd, vpd_tmp,
+ &DEV_T10_WWN(dev)->t10_vpd_list, vpd_list) {
+ list_del(&vpd->vpd_list);
+ kfree(vpd);
+ }
+ spin_unlock(&DEV_T10_WWN(dev)->t10_vpd_lock);
+
+ return;
+}
+
+/*
+ * Called with struct se_hba->device_lock held.
+ */
+void se_clear_dev_ports(struct se_device *dev)
+{
+ struct se_hba *hba = dev->se_hba;
+ struct se_lun *lun;
+ struct se_portal_group *tpg;
+ struct se_port *sep, *sep_tmp;
+
+ spin_lock(&dev->se_port_lock);
+ list_for_each_entry_safe(sep, sep_tmp, &dev->dev_sep_list, sep_list) {
+ spin_unlock(&dev->se_port_lock);
+ spin_unlock(&hba->device_lock);
+
+ lun = sep->sep_lun;
+ tpg = sep->sep_tpg;
+ spin_lock(&lun->lun_sep_lock);
+ if (lun->lun_se_dev == NULL) {
+ spin_unlock(&lun->lun_sep_lock);
+ continue;
+ }
+ spin_unlock(&lun->lun_sep_lock);
+
+ core_dev_del_lun(tpg, lun->unpacked_lun);
+
+ spin_lock(&hba->device_lock);
+ spin_lock(&dev->se_port_lock);
+ }
+ spin_unlock(&dev->se_port_lock);
+
+ return;
+}
+
+/* se_free_virtual_device():
+ *
+ * Used for IBLOCK, RAMDISK, and FILEIO Transport Drivers.
+ */
+int se_free_virtual_device(struct se_device *dev, struct se_hba *hba)
+{
+ spin_lock(&hba->device_lock);
+ se_clear_dev_ports(dev);
+ spin_unlock(&hba->device_lock);
+
+ core_alua_free_lu_gp_mem(dev);
+ se_release_device_for_hba(dev);
+
+ return 0;
+}
+
+static void se_dev_start(struct se_device *dev)
+{
+ struct se_hba *hba = dev->se_hba;
+
+ spin_lock(&hba->device_lock);
+ atomic_inc(&dev->dev_obj.obj_access_count);
+ if (atomic_read(&dev->dev_obj.obj_access_count) == 1) {
+ if (dev->dev_status & TRANSPORT_DEVICE_DEACTIVATED) {
+ dev->dev_status &= ~TRANSPORT_DEVICE_DEACTIVATED;
+ dev->dev_status |= TRANSPORT_DEVICE_ACTIVATED;
+ } else if (dev->dev_status &
+ TRANSPORT_DEVICE_OFFLINE_DEACTIVATED) {
+ dev->dev_status &=
+ ~TRANSPORT_DEVICE_OFFLINE_DEACTIVATED;
+ dev->dev_status |= TRANSPORT_DEVICE_OFFLINE_ACTIVATED;
+ }
+ }
+ spin_unlock(&hba->device_lock);
+}
+
+static void se_dev_stop(struct se_device *dev)
+{
+ struct se_hba *hba = dev->se_hba;
+
+ spin_lock(&hba->device_lock);
+ atomic_dec(&dev->dev_obj.obj_access_count);
+ if (atomic_read(&dev->dev_obj.obj_access_count) == 0) {
+ if (dev->dev_status & TRANSPORT_DEVICE_ACTIVATED) {
+ dev->dev_status &= ~TRANSPORT_DEVICE_ACTIVATED;
+ dev->dev_status |= TRANSPORT_DEVICE_DEACTIVATED;
+ } else if (dev->dev_status &
+ TRANSPORT_DEVICE_OFFLINE_ACTIVATED) {
+ dev->dev_status &= ~TRANSPORT_DEVICE_OFFLINE_ACTIVATED;
+ dev->dev_status |= TRANSPORT_DEVICE_OFFLINE_DEACTIVATED;
+ }
+ }
+ spin_unlock(&hba->device_lock);
+
+ while (atomic_read(&hba->dev_mib_access_count))
+ cpu_relax();
+}
+
+int se_dev_check_online(struct se_device *dev)
+{
+ int ret;
+
+ spin_lock_irq(&dev->dev_status_lock);
+ ret = ((dev->dev_status & TRANSPORT_DEVICE_ACTIVATED) ||
+ (dev->dev_status & TRANSPORT_DEVICE_DEACTIVATED)) ? 0 : 1;
+ spin_unlock_irq(&dev->dev_status_lock);
+
+ return ret;
+}
+
+int se_dev_check_shutdown(struct se_device *dev)
+{
+ int ret;
+
+ spin_lock_irq(&dev->dev_status_lock);
+ ret = (dev->dev_status & TRANSPORT_DEVICE_SHUTDOWN);
+ spin_unlock_irq(&dev->dev_status_lock);
+
+ return ret;
+}
+
+void se_dev_set_default_attribs(
+ struct se_device *dev,
+ struct se_dev_limits *dev_limits)
+{
+ struct queue_limits *limits = &dev_limits->limits;
+
+ DEV_ATTRIB(dev)->emulate_dpo = DA_EMULATE_DPO;
+ DEV_ATTRIB(dev)->emulate_fua_write = DA_EMULATE_FUA_WRITE;
+ DEV_ATTRIB(dev)->emulate_fua_read = DA_EMULATE_FUA_READ;
+ DEV_ATTRIB(dev)->emulate_write_cache = DA_EMULATE_WRITE_CACHE;
+ DEV_ATTRIB(dev)->emulate_ua_intlck_ctrl = DA_EMULATE_UA_INTLLCK_CTRL;
+ DEV_ATTRIB(dev)->emulate_tas = DA_EMULATE_TAS;
+ DEV_ATTRIB(dev)->emulate_tpu = DA_EMULATE_TPU;
+ DEV_ATTRIB(dev)->emulate_tpws = DA_EMULATE_TPWS;
+ DEV_ATTRIB(dev)->emulate_reservations = DA_EMULATE_RESERVATIONS;
+ DEV_ATTRIB(dev)->emulate_alua = DA_EMULATE_ALUA;
+ DEV_ATTRIB(dev)->enforce_pr_isids = DA_ENFORCE_PR_ISIDS;
+ /*
+ * The TPU=1 and TPWS=1 settings will be set in TCM/IBLOCK
+ * iblock_create_virtdevice() from struct queue_limits values
+ * if blk_queue_discard()==1
+ */
+ DEV_ATTRIB(dev)->max_unmap_lba_count = DA_MAX_UNMAP_LBA_COUNT;
+ DEV_ATTRIB(dev)->max_unmap_block_desc_count =
+ DA_MAX_UNMAP_BLOCK_DESC_COUNT;
+ DEV_ATTRIB(dev)->unmap_granularity = DA_UNMAP_GRANULARITY_DEFAULT;
+ DEV_ATTRIB(dev)->unmap_granularity_alignment =
+ DA_UNMAP_GRANULARITY_ALIGNMENT_DEFAULT;
+ /*
+ * block_size is based on subsystem plugin dependent requirements.
+ */
+ DEV_ATTRIB(dev)->hw_block_size = limits->logical_block_size;
+ DEV_ATTRIB(dev)->block_size = limits->logical_block_size;
+ /*
+ * max_sectors is based on subsystem plugin dependent requirements.
+ */
+ DEV_ATTRIB(dev)->hw_max_sectors = limits->max_hw_sectors;
+ DEV_ATTRIB(dev)->max_sectors = limits->max_sectors;
+ /*
+ * Set optimal_sectors from max_sectors, which can be lowered via
+ * configfs.
+ */
+ DEV_ATTRIB(dev)->optimal_sectors = limits->max_sectors;
+ /*
+ * queue_depth is based on subsystem plugin dependent requirements.
+ */
+ DEV_ATTRIB(dev)->hw_queue_depth = dev_limits->hw_queue_depth;
+ DEV_ATTRIB(dev)->queue_depth = dev_limits->queue_depth;
+}
+
+int se_dev_set_task_timeout(struct se_device *dev, u32 task_timeout)
+{
+ if (task_timeout > DA_TASK_TIMEOUT_MAX) {
+ printk(KERN_ERR "dev[%p]: Passed task_timeout: %u larger then"
+ " DA_TASK_TIMEOUT_MAX\n", dev, task_timeout);
+ return -1;
+ } else {
+ DEV_ATTRIB(dev)->task_timeout = task_timeout;
+ printk(KERN_INFO "dev[%p]: Set SE Device task_timeout: %u\n",
+ dev, task_timeout);
+ }
+
+ return 0;
+}
+
+int se_dev_set_max_unmap_lba_count(
+ struct se_device *dev,
+ u32 max_unmap_lba_count)
+{
+ DEV_ATTRIB(dev)->max_unmap_lba_count = max_unmap_lba_count;
+ printk(KERN_INFO "dev[%p]: Set max_unmap_lba_count: %u\n",
+ dev, DEV_ATTRIB(dev)->max_unmap_lba_count);
+ return 0;
+}
+
+int se_dev_set_max_unmap_block_desc_count(
+ struct se_device *dev,
+ u32 max_unmap_block_desc_count)
+{
+ DEV_ATTRIB(dev)->max_unmap_block_desc_count = max_unmap_block_desc_count;
+ printk(KERN_INFO "dev[%p]: Set max_unmap_block_desc_count: %u\n",
+ dev, DEV_ATTRIB(dev)->max_unmap_block_desc_count);
+ return 0;
+}
+
+int se_dev_set_unmap_granularity(
+ struct se_device *dev,
+ u32 unmap_granularity)
+{
+ DEV_ATTRIB(dev)->unmap_granularity = unmap_granularity;
+ printk(KERN_INFO "dev[%p]: Set unmap_granularity: %u\n",
+ dev, DEV_ATTRIB(dev)->unmap_granularity);
+ return 0;
+}
+
+int se_dev_set_unmap_granularity_alignment(
+ struct se_device *dev,
+ u32 unmap_granularity_alignment)
+{
+ DEV_ATTRIB(dev)->unmap_granularity_alignment = unmap_granularity_alignment;
+ printk(KERN_INFO "dev[%p]: Set unmap_granularity_alignment: %u\n",
+ dev, DEV_ATTRIB(dev)->unmap_granularity_alignment);
+ return 0;
+}
+
+int se_dev_set_emulate_dpo(struct se_device *dev, int flag)
+{
+ if ((flag != 0) && (flag != 1)) {
+ printk(KERN_ERR "Illegal value %d\n", flag);
+ return -1;
+ }
+ if (TRANSPORT(dev)->dpo_emulated == NULL) {
+ printk(KERN_ERR "TRANSPORT(dev)->dpo_emulated is NULL\n");
+ return -1;
+ }
+ if (TRANSPORT(dev)->dpo_emulated(dev) == 0) {
+ printk(KERN_ERR "TRANSPORT(dev)->dpo_emulated not supported\n");
+ return -1;
+ }
+ DEV_ATTRIB(dev)->emulate_dpo = flag;
+ printk(KERN_INFO "dev[%p]: SE Device Page Out (DPO) Emulation"
+ " bit: %d\n", dev, DEV_ATTRIB(dev)->emulate_dpo);
+ return 0;
+}
+
+int se_dev_set_emulate_fua_write(struct se_device *dev, int flag)
+{
+ if ((flag != 0) && (flag != 1)) {
+ printk(KERN_ERR "Illegal value %d\n", flag);
+ return -1;
+ }
+ if (TRANSPORT(dev)->fua_write_emulated == NULL) {
+ printk(KERN_ERR "TRANSPORT(dev)->fua_write_emulated is NULL\n");
+ return -1;
+ }
+ if (TRANSPORT(dev)->fua_write_emulated(dev) == 0) {
+ printk(KERN_ERR "TRANSPORT(dev)->fua_write_emulated not supported\n");
+ return -1;
+ }
+ DEV_ATTRIB(dev)->emulate_fua_write = flag;
+ printk(KERN_INFO "dev[%p]: SE Device Forced Unit Access WRITEs: %d\n",
+ dev, DEV_ATTRIB(dev)->emulate_fua_write);
+ return 0;
+}
+
+int se_dev_set_emulate_fua_read(struct se_device *dev, int flag)
+{
+ if ((flag != 0) && (flag != 1)) {
+ printk(KERN_ERR "Illegal value %d\n", flag);
+ return -1;
+ }
+ if (TRANSPORT(dev)->fua_read_emulated == NULL) {
+ printk(KERN_ERR "TRANSPORT(dev)->fua_read_emulated is NULL\n");
+ return -1;
+ }
+ if (TRANSPORT(dev)->fua_read_emulated(dev) == 0) {
+ printk(KERN_ERR "TRANSPORT(dev)->fua_read_emulated not supported\n");
+ return -1;
+ }
+ DEV_ATTRIB(dev)->emulate_fua_read = flag;
+ printk(KERN_INFO "dev[%p]: SE Device Forced Unit Access READs: %d\n",
+ dev, DEV_ATTRIB(dev)->emulate_fua_read);
+ return 0;
+}
+
+int se_dev_set_emulate_write_cache(struct se_device *dev, int flag)
+{
+ if ((flag != 0) && (flag != 1)) {
+ printk(KERN_ERR "Illegal value %d\n", flag);
+ return -1;
+ }
+ if (TRANSPORT(dev)->write_cache_emulated == NULL) {
+ printk(KERN_ERR "TRANSPORT(dev)->write_cache_emulated is NULL\n");
+ return -1;
+ }
+ if (TRANSPORT(dev)->write_cache_emulated(dev) == 0) {
+ printk(KERN_ERR "TRANSPORT(dev)->write_cache_emulated not supported\n");
+ return -1;
+ }
+ DEV_ATTRIB(dev)->emulate_write_cache = flag;
+ printk(KERN_INFO "dev[%p]: SE Device WRITE_CACHE_EMULATION flag: %d\n",
+ dev, DEV_ATTRIB(dev)->emulate_write_cache);
+ return 0;
+}
+
+int se_dev_set_emulate_ua_intlck_ctrl(struct se_device *dev, int flag)
+{
+ if ((flag != 0) && (flag != 1) && (flag != 2)) {
+ printk(KERN_ERR "Illegal value %d\n", flag);
+ return -1;
+ }
+
+ if (atomic_read(&dev->dev_export_obj.obj_access_count)) {
+ printk(KERN_ERR "dev[%p]: Unable to change SE Device"
+ " UA_INTRLCK_CTRL while dev_export_obj: %d count"
+ " exists\n", dev,
+ atomic_read(&dev->dev_export_obj.obj_access_count));
+ return -1;
+ }
+ DEV_ATTRIB(dev)->emulate_ua_intlck_ctrl = flag;
+ printk(KERN_INFO "dev[%p]: SE Device UA_INTRLCK_CTRL flag: %d\n",
+ dev, DEV_ATTRIB(dev)->emulate_ua_intlck_ctrl);
+
+ return 0;
+}
+
+int se_dev_set_emulate_tas(struct se_device *dev, int flag)
+{
+ if ((flag != 0) && (flag != 1)) {
+ printk(KERN_ERR "Illegal value %d\n", flag);
+ return -1;
+ }
+
+ if (atomic_read(&dev->dev_export_obj.obj_access_count)) {
+ printk(KERN_ERR "dev[%p]: Unable to change SE Device TAS while"
+ " dev_export_obj: %d count exists\n", dev,
+ atomic_read(&dev->dev_export_obj.obj_access_count));
+ return -1;
+ }
+ DEV_ATTRIB(dev)->emulate_tas = flag;
+ printk(KERN_INFO "dev[%p]: SE Device TASK_ABORTED status bit: %s\n",
+ dev, (DEV_ATTRIB(dev)->emulate_tas) ? "Enabled" : "Disabled");
+
+ return 0;
+}
+
+int se_dev_set_emulate_tpu(struct se_device *dev, int flag)
+{
+ if ((flag != 0) && (flag != 1)) {
+ printk(KERN_ERR "Illegal value %d\n", flag);
+ return -1;
+ }
+ /*
+ * We expect this value to be non-zero when generic Block Layer
+ * Discard supported is detected iblock_create_virtdevice().
+ */
+ if (!(DEV_ATTRIB(dev)->max_unmap_block_desc_count)) {
+ printk(KERN_ERR "Generic Block Discard not supported\n");
+ return -ENOSYS;
+ }
+
+ DEV_ATTRIB(dev)->emulate_tpu = flag;
+ printk(KERN_INFO "dev[%p]: SE Device Thin Provisioning UNMAP bit: %d\n",
+ dev, flag);
+ return 0;
+}
+
+int se_dev_set_emulate_tpws(struct se_device *dev, int flag)
+{
+ if ((flag != 0) && (flag != 1)) {
+ printk(KERN_ERR "Illegal value %d\n", flag);
+ return -1;
+ }
+ /*
+ * We expect this value to be non-zero when generic Block Layer
+ * Discard supported is detected iblock_create_virtdevice().
+ */
+ if (!(DEV_ATTRIB(dev)->max_unmap_block_desc_count)) {
+ printk(KERN_ERR "Generic Block Discard not supported\n");
+ return -ENOSYS;
+ }
+
+ DEV_ATTRIB(dev)->emulate_tpws = flag;
+ printk(KERN_INFO "dev[%p]: SE Device Thin Provisioning WRITE_SAME: %d\n",
+ dev, flag);
+ return 0;
+}
+
+int se_dev_set_enforce_pr_isids(struct se_device *dev, int flag)
+{
+ if ((flag != 0) && (flag != 1)) {
+ printk(KERN_ERR "Illegal value %d\n", flag);
+ return -1;
+ }
+ DEV_ATTRIB(dev)->enforce_pr_isids = flag;
+ printk(KERN_INFO "dev[%p]: SE Device enforce_pr_isids bit: %s\n", dev,
+ (DEV_ATTRIB(dev)->enforce_pr_isids) ? "Enabled" : "Disabled");
+ return 0;
+}
+
+/*
+ * Note, this can only be called on unexported SE Device Object.
+ */
+int se_dev_set_queue_depth(struct se_device *dev, u32 queue_depth)
+{
+ u32 orig_queue_depth = dev->queue_depth;
+
+ if (atomic_read(&dev->dev_export_obj.obj_access_count)) {
+ printk(KERN_ERR "dev[%p]: Unable to change SE Device TCQ while"
+ " dev_export_obj: %d count exists\n", dev,
+ atomic_read(&dev->dev_export_obj.obj_access_count));
+ return -1;
+ }
+ if (!(queue_depth)) {
+ printk(KERN_ERR "dev[%p]: Illegal ZERO value for queue"
+ "_depth\n", dev);
+ return -1;
+ }
+
+ if (TRANSPORT(dev)->transport_type == TRANSPORT_PLUGIN_PHBA_PDEV) {
+ if (queue_depth > DEV_ATTRIB(dev)->hw_queue_depth) {
+ printk(KERN_ERR "dev[%p]: Passed queue_depth: %u"
+ " exceeds TCM/SE_Device TCQ: %u\n",
+ dev, queue_depth,
+ DEV_ATTRIB(dev)->hw_queue_depth);
+ return -1;
+ }
+ } else {
+ if (queue_depth > DEV_ATTRIB(dev)->queue_depth) {
+ if (queue_depth > DEV_ATTRIB(dev)->hw_queue_depth) {
+ printk(KERN_ERR "dev[%p]: Passed queue_depth:"
+ " %u exceeds TCM/SE_Device MAX"
+ " TCQ: %u\n", dev, queue_depth,
+ DEV_ATTRIB(dev)->hw_queue_depth);
+ return -1;
+ }
+ }
+ }
+
+ DEV_ATTRIB(dev)->queue_depth = dev->queue_depth = queue_depth;
+ if (queue_depth > orig_queue_depth)
+ atomic_add(queue_depth - orig_queue_depth, &dev->depth_left);
+ else if (queue_depth < orig_queue_depth)
+ atomic_sub(orig_queue_depth - queue_depth, &dev->depth_left);
+
+ printk(KERN_INFO "dev[%p]: SE Device TCQ Depth changed to: %u\n",
+ dev, queue_depth);
+ return 0;
+}
+
+int se_dev_set_max_sectors(struct se_device *dev, u32 max_sectors)
+{
+ int force = 0; /* Force setting for VDEVS */
+
+ if (atomic_read(&dev->dev_export_obj.obj_access_count)) {
+ printk(KERN_ERR "dev[%p]: Unable to change SE Device"
+ " max_sectors while dev_export_obj: %d count exists\n",
+ dev, atomic_read(&dev->dev_export_obj.obj_access_count));
+ return -1;
+ }
+ if (!(max_sectors)) {
+ printk(KERN_ERR "dev[%p]: Illegal ZERO value for"
+ " max_sectors\n", dev);
+ return -1;
+ }
+ if (max_sectors < DA_STATUS_MAX_SECTORS_MIN) {
+ printk(KERN_ERR "dev[%p]: Passed max_sectors: %u less than"
+ " DA_STATUS_MAX_SECTORS_MIN: %u\n", dev, max_sectors,
+ DA_STATUS_MAX_SECTORS_MIN);
+ return -1;
+ }
+ if (TRANSPORT(dev)->transport_type == TRANSPORT_PLUGIN_PHBA_PDEV) {
+ if (max_sectors > DEV_ATTRIB(dev)->hw_max_sectors) {
+ printk(KERN_ERR "dev[%p]: Passed max_sectors: %u"
+ " greater than TCM/SE_Device max_sectors:"
+ " %u\n", dev, max_sectors,
+ DEV_ATTRIB(dev)->hw_max_sectors);
+ return -1;
+ }
+ } else {
+ if (!(force) && (max_sectors >
+ DEV_ATTRIB(dev)->hw_max_sectors)) {
+ printk(KERN_ERR "dev[%p]: Passed max_sectors: %u"
+ " greater than TCM/SE_Device max_sectors"
+ ": %u, use force=1 to override.\n", dev,
+ max_sectors, DEV_ATTRIB(dev)->hw_max_sectors);
+ return -1;
+ }
+ if (max_sectors > DA_STATUS_MAX_SECTORS_MAX) {
+ printk(KERN_ERR "dev[%p]: Passed max_sectors: %u"
+ " greater than DA_STATUS_MAX_SECTORS_MAX:"
+ " %u\n", dev, max_sectors,
+ DA_STATUS_MAX_SECTORS_MAX);
+ return -1;
+ }
+ }
+
+ DEV_ATTRIB(dev)->max_sectors = max_sectors;
+ printk("dev[%p]: SE Device max_sectors changed to %u\n",
+ dev, max_sectors);
+ return 0;
+}
+
+int se_dev_set_optimal_sectors(struct se_device *dev, u32 optimal_sectors)
+{
+ if (atomic_read(&dev->dev_export_obj.obj_access_count)) {
+ printk(KERN_ERR "dev[%p]: Unable to change SE Device"
+ " optimal_sectors while dev_export_obj: %d count exists\n",
+ dev, atomic_read(&dev->dev_export_obj.obj_access_count));
+ return -EINVAL;
+ }
+ if (TRANSPORT(dev)->transport_type == TRANSPORT_PLUGIN_PHBA_PDEV) {
+ printk(KERN_ERR "dev[%p]: Passed optimal_sectors cannot be"
+ " changed for TCM/pSCSI\n", dev);
+ return -EINVAL;
+ }
+ if (optimal_sectors > DEV_ATTRIB(dev)->max_sectors) {
+ printk(KERN_ERR "dev[%p]: Passed optimal_sectors %u cannot be"
+ " greater than max_sectors: %u\n", dev,
+ optimal_sectors, DEV_ATTRIB(dev)->max_sectors);
+ return -EINVAL;
+ }
+
+ DEV_ATTRIB(dev)->optimal_sectors = optimal_sectors;
+ printk(KERN_INFO "dev[%p]: SE Device optimal_sectors changed to %u\n",
+ dev, optimal_sectors);
+ return 0;
+}
+
+int se_dev_set_block_size(struct se_device *dev, u32 block_size)
+{
+ if (atomic_read(&dev->dev_export_obj.obj_access_count)) {
+ printk(KERN_ERR "dev[%p]: Unable to change SE Device block_size"
+ " while dev_export_obj: %d count exists\n", dev,
+ atomic_read(&dev->dev_export_obj.obj_access_count));
+ return -1;
+ }
+
+ if ((block_size != 512) &&
+ (block_size != 1024) &&
+ (block_size != 2048) &&
+ (block_size != 4096)) {
+ printk(KERN_ERR "dev[%p]: Illegal value for block_device: %u"
+ " for SE device, must be 512, 1024, 2048 or 4096\n",
+ dev, block_size);
+ return -1;
+ }
+
+ if (TRANSPORT(dev)->transport_type == TRANSPORT_PLUGIN_PHBA_PDEV) {
+ printk(KERN_ERR "dev[%p]: Not allowed to change block_size for"
+ " Physical Device, use for Linux/SCSI to change"
+ " block_size for underlying hardware\n", dev);
+ return -1;
+ }
+
+ DEV_ATTRIB(dev)->block_size = block_size;
+ printk(KERN_INFO "dev[%p]: SE Device block_size changed to %u\n",
+ dev, block_size);
+ return 0;
+}
+
+struct se_lun *core_dev_add_lun(
+ struct se_portal_group *tpg,
+ struct se_hba *hba,
+ struct se_device *dev,
+ u32 lun)
+{
+ struct se_lun *lun_p;
+ u32 lun_access = 0;
+
+ if (atomic_read(&dev->dev_access_obj.obj_access_count) != 0) {
+ printk(KERN_ERR "Unable to export struct se_device while dev_access_obj: %d\n",
+ atomic_read(&dev->dev_access_obj.obj_access_count));
+ return NULL;
+ }
+
+ lun_p = core_tpg_pre_addlun(tpg, lun);
+ if ((IS_ERR(lun_p)) || !(lun_p))
+ return NULL;
+
+ if (dev->dev_flags & DF_READ_ONLY)
+ lun_access = TRANSPORT_LUNFLAGS_READ_ONLY;
+ else
+ lun_access = TRANSPORT_LUNFLAGS_READ_WRITE;
+
+ if (core_tpg_post_addlun(tpg, lun_p, lun_access, dev) < 0)
+ return NULL;
+
+ printk(KERN_INFO "%s_TPG[%u]_LUN[%u] - Activated %s Logical Unit from"
+ " CORE HBA: %u\n", TPG_TFO(tpg)->get_fabric_name(),
+ TPG_TFO(tpg)->tpg_get_tag(tpg), lun_p->unpacked_lun,
+ TPG_TFO(tpg)->get_fabric_name(), hba->hba_id);
+ /*
+ * Update LUN maps for dynamically added initiators when
+ * generate_node_acl is enabled.
+ */
+ if (TPG_TFO(tpg)->tpg_check_demo_mode(tpg)) {
+ struct se_node_acl *acl;
+ spin_lock_bh(&tpg->acl_node_lock);
+ list_for_each_entry(acl, &tpg->acl_node_list, acl_list) {
+ if (acl->dynamic_node_acl) {
+ spin_unlock_bh(&tpg->acl_node_lock);
+ core_tpg_add_node_to_devs(acl, tpg);
+ spin_lock_bh(&tpg->acl_node_lock);
+ }
+ }
+ spin_unlock_bh(&tpg->acl_node_lock);
+ }
+
+ return lun_p;
+}
+
+/* core_dev_del_lun():
+ *
+ *
+ */
+int core_dev_del_lun(
+ struct se_portal_group *tpg,
+ u32 unpacked_lun)
+{
+ struct se_lun *lun;
+ int ret = 0;
+
+ lun = core_tpg_pre_dellun(tpg, unpacked_lun, &ret);
+ if (!(lun))
+ return ret;
+
+ core_tpg_post_dellun(tpg, lun);
+
+ printk(KERN_INFO "%s_TPG[%u]_LUN[%u] - Deactivated %s Logical Unit from"
+ " device object\n", TPG_TFO(tpg)->get_fabric_name(),
+ TPG_TFO(tpg)->tpg_get_tag(tpg), unpacked_lun,
+ TPG_TFO(tpg)->get_fabric_name());
+
+ return 0;
+}
+
+struct se_lun *core_get_lun_from_tpg(struct se_portal_group *tpg, u32 unpacked_lun)
+{
+ struct se_lun *lun;
+
+ spin_lock(&tpg->tpg_lun_lock);
+ if (unpacked_lun > (TRANSPORT_MAX_LUNS_PER_TPG-1)) {
+ printk(KERN_ERR "%s LUN: %u exceeds TRANSPORT_MAX_LUNS"
+ "_PER_TPG-1: %u for Target Portal Group: %hu\n",
+ TPG_TFO(tpg)->get_fabric_name(), unpacked_lun,
+ TRANSPORT_MAX_LUNS_PER_TPG-1,
+ TPG_TFO(tpg)->tpg_get_tag(tpg));
+ spin_unlock(&tpg->tpg_lun_lock);
+ return NULL;
+ }
+ lun = &tpg->tpg_lun_list[unpacked_lun];
+
+ if (lun->lun_status != TRANSPORT_LUN_STATUS_FREE) {
+ printk(KERN_ERR "%s Logical Unit Number: %u is not free on"
+ " Target Portal Group: %hu, ignoring request.\n",
+ TPG_TFO(tpg)->get_fabric_name(), unpacked_lun,
+ TPG_TFO(tpg)->tpg_get_tag(tpg));
+ spin_unlock(&tpg->tpg_lun_lock);
+ return NULL;
+ }
+ spin_unlock(&tpg->tpg_lun_lock);
+
+ return lun;
+}
+
+/* core_dev_get_lun():
+ *
+ *
+ */
+static struct se_lun *core_dev_get_lun(struct se_portal_group *tpg, u32 unpacked_lun)
+{
+ struct se_lun *lun;
+
+ spin_lock(&tpg->tpg_lun_lock);
+ if (unpacked_lun > (TRANSPORT_MAX_LUNS_PER_TPG-1)) {
+ printk(KERN_ERR "%s LUN: %u exceeds TRANSPORT_MAX_LUNS_PER"
+ "_TPG-1: %u for Target Portal Group: %hu\n",
+ TPG_TFO(tpg)->get_fabric_name(), unpacked_lun,
+ TRANSPORT_MAX_LUNS_PER_TPG-1,
+ TPG_TFO(tpg)->tpg_get_tag(tpg));
+ spin_unlock(&tpg->tpg_lun_lock);
+ return NULL;
+ }
+ lun = &tpg->tpg_lun_list[unpacked_lun];
+
+ if (lun->lun_status != TRANSPORT_LUN_STATUS_ACTIVE) {
+ printk(KERN_ERR "%s Logical Unit Number: %u is not active on"
+ " Target Portal Group: %hu, ignoring request.\n",
+ TPG_TFO(tpg)->get_fabric_name(), unpacked_lun,
+ TPG_TFO(tpg)->tpg_get_tag(tpg));
+ spin_unlock(&tpg->tpg_lun_lock);
+ return NULL;
+ }
+ spin_unlock(&tpg->tpg_lun_lock);
+
+ return lun;
+}
+
+struct se_lun_acl *core_dev_init_initiator_node_lun_acl(
+ struct se_portal_group *tpg,
+ u32 mapped_lun,
+ char *initiatorname,
+ int *ret)
+{
+ struct se_lun_acl *lacl;
+ struct se_node_acl *nacl;
+
+ if (strlen(initiatorname) > TRANSPORT_IQN_LEN) {
+ printk(KERN_ERR "%s InitiatorName exceeds maximum size.\n",
+ TPG_TFO(tpg)->get_fabric_name());
+ *ret = -EOVERFLOW;
+ return NULL;
+ }
+ nacl = core_tpg_get_initiator_node_acl(tpg, initiatorname);
+ if (!(nacl)) {
+ *ret = -EINVAL;
+ return NULL;
+ }
+ lacl = kzalloc(sizeof(struct se_lun_acl), GFP_KERNEL);
+ if (!(lacl)) {
+ printk(KERN_ERR "Unable to allocate memory for struct se_lun_acl.\n");
+ *ret = -ENOMEM;
+ return NULL;
+ }
+
+ INIT_LIST_HEAD(&lacl->lacl_list);
+ lacl->mapped_lun = mapped_lun;
+ lacl->se_lun_nacl = nacl;
+ snprintf(lacl->initiatorname, TRANSPORT_IQN_LEN, "%s", initiatorname);
+
+ return lacl;
+}
+
+int core_dev_add_initiator_node_lun_acl(
+ struct se_portal_group *tpg,
+ struct se_lun_acl *lacl,
+ u32 unpacked_lun,
+ u32 lun_access)
+{
+ struct se_lun *lun;
+ struct se_node_acl *nacl;
+
+ lun = core_dev_get_lun(tpg, unpacked_lun);
+ if (!(lun)) {
+ printk(KERN_ERR "%s Logical Unit Number: %u is not active on"
+ " Target Portal Group: %hu, ignoring request.\n",
+ TPG_TFO(tpg)->get_fabric_name(), unpacked_lun,
+ TPG_TFO(tpg)->tpg_get_tag(tpg));
+ return -EINVAL;
+ }
+
+ nacl = lacl->se_lun_nacl;
+ if (!(nacl))
+ return -EINVAL;
+
+ if ((lun->lun_access & TRANSPORT_LUNFLAGS_READ_ONLY) &&
+ (lun_access & TRANSPORT_LUNFLAGS_READ_WRITE))
+ lun_access = TRANSPORT_LUNFLAGS_READ_ONLY;
+
+ lacl->se_lun = lun;
+
+ if (core_update_device_list_for_node(lun, lacl, lacl->mapped_lun,
+ lun_access, nacl, tpg, 1) < 0)
+ return -EINVAL;
+
+ spin_lock(&lun->lun_acl_lock);
+ list_add_tail(&lacl->lacl_list, &lun->lun_acl_list);
+ atomic_inc(&lun->lun_acl_count);
+ smp_mb__after_atomic_inc();
+ spin_unlock(&lun->lun_acl_lock);
+
+ printk(KERN_INFO "%s_TPG[%hu]_LUN[%u->%u] - Added %s ACL for "
+ " InitiatorNode: %s\n", TPG_TFO(tpg)->get_fabric_name(),
+ TPG_TFO(tpg)->tpg_get_tag(tpg), unpacked_lun, lacl->mapped_lun,
+ (lun_access & TRANSPORT_LUNFLAGS_READ_WRITE) ? "RW" : "RO",
+ lacl->initiatorname);
+ /*
+ * Check to see if there are any existing persistent reservation APTPL
+ * pre-registrations that need to be enabled for this LUN ACL..
+ */
+ core_scsi3_check_aptpl_registration(lun->lun_se_dev, tpg, lun, lacl);
+ return 0;
+}
+
+/* core_dev_del_initiator_node_lun_acl():
+ *
+ *
+ */
+int core_dev_del_initiator_node_lun_acl(
+ struct se_portal_group *tpg,
+ struct se_lun *lun,
+ struct se_lun_acl *lacl)
+{
+ struct se_node_acl *nacl;
+
+ nacl = lacl->se_lun_nacl;
+ if (!(nacl))
+ return -EINVAL;
+
+ spin_lock(&lun->lun_acl_lock);
+ list_del(&lacl->lacl_list);
+ atomic_dec(&lun->lun_acl_count);
+ smp_mb__after_atomic_dec();
+ spin_unlock(&lun->lun_acl_lock);
+
+ core_update_device_list_for_node(lun, NULL, lacl->mapped_lun,
+ TRANSPORT_LUNFLAGS_NO_ACCESS, nacl, tpg, 0);
+
+ lacl->se_lun = NULL;
+
+ printk(KERN_INFO "%s_TPG[%hu]_LUN[%u] - Removed ACL for"
+ " InitiatorNode: %s Mapped LUN: %u\n",
+ TPG_TFO(tpg)->get_fabric_name(),
+ TPG_TFO(tpg)->tpg_get_tag(tpg), lun->unpacked_lun,
+ lacl->initiatorname, lacl->mapped_lun);
+
+ return 0;
+}
+
+void core_dev_free_initiator_node_lun_acl(
+ struct se_portal_group *tpg,
+ struct se_lun_acl *lacl)
+{
+ printk("%s_TPG[%hu] - Freeing ACL for %s InitiatorNode: %s"
+ " Mapped LUN: %u\n", TPG_TFO(tpg)->get_fabric_name(),
+ TPG_TFO(tpg)->tpg_get_tag(tpg),
+ TPG_TFO(tpg)->get_fabric_name(),
+ lacl->initiatorname, lacl->mapped_lun);
+
+ kfree(lacl);
+}
+
+int core_dev_setup_virtual_lun0(void)
+{
+ struct se_hba *hba;
+ struct se_device *dev;
+ struct se_subsystem_dev *se_dev = NULL;
+ struct se_subsystem_api *t;
+ char buf[16];
+ int ret;
+
+ hba = core_alloc_hba("rd_dr", 0, HBA_FLAGS_INTERNAL_USE);
+ if (IS_ERR(hba))
+ return PTR_ERR(hba);
+
+ se_global->g_lun0_hba = hba;
+ t = hba->transport;
+
+ se_dev = kzalloc(sizeof(struct se_subsystem_dev), GFP_KERNEL);
+ if (!(se_dev)) {
+ printk(KERN_ERR "Unable to allocate memory for"
+ " struct se_subsystem_dev\n");
+ ret = -ENOMEM;
+ goto out;
+ }
+ INIT_LIST_HEAD(&se_dev->g_se_dev_list);
+ INIT_LIST_HEAD(&se_dev->t10_wwn.t10_vpd_list);
+ spin_lock_init(&se_dev->t10_wwn.t10_vpd_lock);
+ INIT_LIST_HEAD(&se_dev->t10_reservation.registration_list);
+ INIT_LIST_HEAD(&se_dev->t10_reservation.aptpl_reg_list);
+ spin_lock_init(&se_dev->t10_reservation.registration_lock);
+ spin_lock_init(&se_dev->t10_reservation.aptpl_reg_lock);
+ INIT_LIST_HEAD(&se_dev->t10_alua.tg_pt_gps_list);
+ spin_lock_init(&se_dev->t10_alua.tg_pt_gps_lock);
+ spin_lock_init(&se_dev->se_dev_lock);
+ se_dev->t10_reservation.pr_aptpl_buf_len = PR_APTPL_BUF_LEN;
+ se_dev->t10_wwn.t10_sub_dev = se_dev;
+ se_dev->t10_alua.t10_sub_dev = se_dev;
+ se_dev->se_dev_attrib.da_sub_dev = se_dev;
+ se_dev->se_dev_hba = hba;
+
+ se_dev->se_dev_su_ptr = t->allocate_virtdevice(hba, "virt_lun0");
+ if (!(se_dev->se_dev_su_ptr)) {
+ printk(KERN_ERR "Unable to locate subsystem dependent pointer"
+ " from allocate_virtdevice()\n");
+ ret = -ENOMEM;
+ goto out;
+ }
+ se_global->g_lun0_su_dev = se_dev;
+
+ memset(buf, 0, 16);
+ sprintf(buf, "rd_pages=8");
+ t->set_configfs_dev_params(hba, se_dev, buf, sizeof(buf));
+
+ dev = t->create_virtdevice(hba, se_dev, se_dev->se_dev_su_ptr);
+ if (!(dev) || IS_ERR(dev)) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ se_dev->se_dev_ptr = dev;
+ se_global->g_lun0_dev = dev;
+
+ return 0;
+out:
+ se_global->g_lun0_su_dev = NULL;
+ kfree(se_dev);
+ if (se_global->g_lun0_hba) {
+ core_delete_hba(se_global->g_lun0_hba);
+ se_global->g_lun0_hba = NULL;
+ }
+ return ret;
+}
+
+
+void core_dev_release_virtual_lun0(void)
+{
+ struct se_hba *hba = se_global->g_lun0_hba;
+ struct se_subsystem_dev *su_dev = se_global->g_lun0_su_dev;
+
+ if (!(hba))
+ return;
+
+ if (se_global->g_lun0_dev)
+ se_free_virtual_device(se_global->g_lun0_dev, hba);
+
+ kfree(su_dev);
+ core_delete_hba(hba);
+}
diff --git a/drivers/target/target_core_fabric_configfs.c b/drivers/target/target_core_fabric_configfs.c
new file mode 100644
index 0000000..32b148d
--- /dev/null
+++ b/drivers/target/target_core_fabric_configfs.c
@@ -0,0 +1,996 @@
+/*******************************************************************************
+* Filename: target_core_fabric_configfs.c
+ *
+ * This file contains generic fabric module configfs infrastructure for
+ * TCM v4.x code
+ *
+ * Copyright (c) 2010 Rising Tide Systems
+ * Copyright (c) 2010 Linux-iSCSI.org
+ *
+ * Copyright (c) 2010 Nicholas A. Bellinger <nab@linux-iscsi.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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ ****************************************************************************/
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/version.h>
+#include <generated/utsrelease.h>
+#include <linux/utsname.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/namei.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/unistd.h>
+#include <linux/string.h>
+#include <linux/syscalls.h>
+#include <linux/configfs.h>
+
+#include <target/target_core_base.h>
+#include <target/target_core_device.h>
+#include <target/target_core_tpg.h>
+#include <target/target_core_transport.h>
+#include <target/target_core_fabric_ops.h>
+#include <target/target_core_fabric_configfs.h>
+#include <target/target_core_configfs.h>
+#include <target/configfs_macros.h>
+
+#include "target_core_alua.h"
+#include "target_core_hba.h"
+#include "target_core_pr.h"
+
+#define TF_CIT_SETUP(_name, _item_ops, _group_ops, _attrs) \
+static void target_fabric_setup_##_name##_cit(struct target_fabric_configfs *tf) \
+{ \
+ struct target_fabric_configfs_template *tfc = &tf->tf_cit_tmpl; \
+ struct config_item_type *cit = &tfc->tfc_##_name##_cit; \
+ \
+ cit->ct_item_ops = _item_ops; \
+ cit->ct_group_ops = _group_ops; \
+ cit->ct_attrs = _attrs; \
+ cit->ct_owner = tf->tf_module; \
+ printk("Setup generic %s\n", __stringify(_name)); \
+}
+
+/* Start of tfc_tpg_mappedlun_cit */
+
+static int target_fabric_mappedlun_link(
+ struct config_item *lun_acl_ci,
+ struct config_item *lun_ci)
+{
+ struct se_dev_entry *deve;
+ struct se_lun *lun = container_of(to_config_group(lun_ci),
+ struct se_lun, lun_group);
+ struct se_lun_acl *lacl = container_of(to_config_group(lun_acl_ci),
+ struct se_lun_acl, se_lun_group);
+ struct se_portal_group *se_tpg;
+ struct config_item *nacl_ci, *tpg_ci, *tpg_ci_s, *wwn_ci, *wwn_ci_s;
+ int ret = 0, lun_access;
+ /*
+ * Ensure that the source port exists
+ */
+ if (!(lun->lun_sep) || !(lun->lun_sep->sep_tpg)) {
+ printk(KERN_ERR "Source se_lun->lun_sep or lun->lun_sep->sep"
+ "_tpg does not exist\n");
+ return -EINVAL;
+ }
+ se_tpg = lun->lun_sep->sep_tpg;
+
+ nacl_ci = &lun_acl_ci->ci_parent->ci_group->cg_item;
+ tpg_ci = &nacl_ci->ci_group->cg_item;
+ wwn_ci = &tpg_ci->ci_group->cg_item;
+ tpg_ci_s = &lun_ci->ci_parent->ci_group->cg_item;
+ wwn_ci_s = &tpg_ci_s->ci_group->cg_item;
+ /*
+ * Make sure the SymLink is going to the same $FABRIC/$WWN/tpgt_$TPGT
+ */
+ if (strcmp(config_item_name(wwn_ci), config_item_name(wwn_ci_s))) {
+ printk(KERN_ERR "Illegal Initiator ACL SymLink outside of %s\n",
+ config_item_name(wwn_ci));
+ return -EINVAL;
+ }
+ if (strcmp(config_item_name(tpg_ci), config_item_name(tpg_ci_s))) {
+ printk(KERN_ERR "Illegal Initiator ACL Symlink outside of %s"
+ " TPGT: %s\n", config_item_name(wwn_ci),
+ config_item_name(tpg_ci));
+ return -EINVAL;
+ }
+ /*
+ * If this struct se_node_acl was dynamically generated with
+ * tpg_1/attrib/generate_node_acls=1, use the existing deve->lun_flags,
+ * which be will write protected (READ-ONLY) when
+ * tpg_1/attrib/demo_mode_write_protect=1
+ */
+ spin_lock_irq(&lacl->se_lun_nacl->device_list_lock);
+ deve = &lacl->se_lun_nacl->device_list[lacl->mapped_lun];
+ if (deve->lun_flags & TRANSPORT_LUNFLAGS_INITIATOR_ACCESS)
+ lun_access = deve->lun_flags;
+ else
+ lun_access =
+ (TPG_TFO(se_tpg)->tpg_check_prod_mode_write_protect(
+ se_tpg)) ? TRANSPORT_LUNFLAGS_READ_ONLY :
+ TRANSPORT_LUNFLAGS_READ_WRITE;
+ spin_unlock_irq(&lacl->se_lun_nacl->device_list_lock);
+ /*
+ * Determine the actual mapped LUN value user wants..
+ *
+ * This value is what the SCSI Initiator actually sees the
+ * iscsi/$IQN/$TPGT/lun/lun_* as on their SCSI Initiator Ports.
+ */
+ ret = core_dev_add_initiator_node_lun_acl(se_tpg, lacl,
+ lun->unpacked_lun, lun_access);
+
+ return (ret < 0) ? -EINVAL : 0;
+}
+
+static int target_fabric_mappedlun_unlink(
+ struct config_item *lun_acl_ci,
+ struct config_item *lun_ci)
+{
+ struct se_lun *lun;
+ struct se_lun_acl *lacl = container_of(to_config_group(lun_acl_ci),
+ struct se_lun_acl, se_lun_group);
+ struct se_node_acl *nacl = lacl->se_lun_nacl;
+ struct se_dev_entry *deve = &nacl->device_list[lacl->mapped_lun];
+ struct se_portal_group *se_tpg;
+ /*
+ * Determine if the underlying MappedLUN has already been released..
+ */
+ if (!(deve->se_lun))
+ return 0;
+
+ lun = container_of(to_config_group(lun_ci), struct se_lun, lun_group);
+ se_tpg = lun->lun_sep->sep_tpg;
+
+ core_dev_del_initiator_node_lun_acl(se_tpg, lun, lacl);
+ return 0;
+}
+
+CONFIGFS_EATTR_STRUCT(target_fabric_mappedlun, se_lun_acl);
+#define TCM_MAPPEDLUN_ATTR(_name, _mode) \
+static struct target_fabric_mappedlun_attribute target_fabric_mappedlun_##_name = \
+ __CONFIGFS_EATTR(_name, _mode, \
+ target_fabric_mappedlun_show_##_name, \
+ target_fabric_mappedlun_store_##_name);
+
+static ssize_t target_fabric_mappedlun_show_write_protect(
+ struct se_lun_acl *lacl,
+ char *page)
+{
+ struct se_node_acl *se_nacl = lacl->se_lun_nacl;
+ struct se_dev_entry *deve;
+ ssize_t len;
+
+ spin_lock_irq(&se_nacl->device_list_lock);
+ deve = &se_nacl->device_list[lacl->mapped_lun];
+ len = sprintf(page, "%d\n",
+ (deve->lun_flags & TRANSPORT_LUNFLAGS_READ_ONLY) ?
+ 1 : 0);
+ spin_unlock_irq(&se_nacl->device_list_lock);
+
+ return len;
+}
+
+static ssize_t target_fabric_mappedlun_store_write_protect(
+ struct se_lun_acl *lacl,
+ const char *page,
+ size_t count)
+{
+ struct se_node_acl *se_nacl = lacl->se_lun_nacl;
+ struct se_portal_group *se_tpg = se_nacl->se_tpg;
+ unsigned long op;
+
+ if (strict_strtoul(page, 0, &op))
+ return -EINVAL;
+
+ if ((op != 1) && (op != 0))
+ return -EINVAL;
+
+ core_update_device_list_access(lacl->mapped_lun, (op) ?
+ TRANSPORT_LUNFLAGS_READ_ONLY :
+ TRANSPORT_LUNFLAGS_READ_WRITE,
+ lacl->se_lun_nacl);
+
+ printk(KERN_INFO "%s_ConfigFS: Changed Initiator ACL: %s"
+ " Mapped LUN: %u Write Protect bit to %s\n",
+ TPG_TFO(se_tpg)->get_fabric_name(),
+ lacl->initiatorname, lacl->mapped_lun, (op) ? "ON" : "OFF");
+
+ return count;
+
+}
+
+TCM_MAPPEDLUN_ATTR(write_protect, S_IRUGO | S_IWUSR);
+
+CONFIGFS_EATTR_OPS(target_fabric_mappedlun, se_lun_acl, se_lun_group);
+
+static struct configfs_attribute *target_fabric_mappedlun_attrs[] = {
+ &target_fabric_mappedlun_write_protect.attr,
+ NULL,
+};
+
+static struct configfs_item_operations target_fabric_mappedlun_item_ops = {
+ .show_attribute = target_fabric_mappedlun_attr_show,
+ .store_attribute = target_fabric_mappedlun_attr_store,
+ .allow_link = target_fabric_mappedlun_link,
+ .drop_link = target_fabric_mappedlun_unlink,
+};
+
+TF_CIT_SETUP(tpg_mappedlun, &target_fabric_mappedlun_item_ops, NULL,
+ target_fabric_mappedlun_attrs);
+
+/* End of tfc_tpg_mappedlun_cit */
+
+/* Start of tfc_tpg_nacl_attrib_cit */
+
+CONFIGFS_EATTR_OPS(target_fabric_nacl_attrib, se_node_acl, acl_attrib_group);
+
+static struct configfs_item_operations target_fabric_nacl_attrib_item_ops = {
+ .show_attribute = target_fabric_nacl_attrib_attr_show,
+ .store_attribute = target_fabric_nacl_attrib_attr_store,
+};
+
+TF_CIT_SETUP(tpg_nacl_attrib, &target_fabric_nacl_attrib_item_ops, NULL, NULL);
+
+/* End of tfc_tpg_nacl_attrib_cit */
+
+/* Start of tfc_tpg_nacl_auth_cit */
+
+CONFIGFS_EATTR_OPS(target_fabric_nacl_auth, se_node_acl, acl_auth_group);
+
+static struct configfs_item_operations target_fabric_nacl_auth_item_ops = {
+ .show_attribute = target_fabric_nacl_auth_attr_show,
+ .store_attribute = target_fabric_nacl_auth_attr_store,
+};
+
+TF_CIT_SETUP(tpg_nacl_auth, &target_fabric_nacl_auth_item_ops, NULL, NULL);
+
+/* End of tfc_tpg_nacl_auth_cit */
+
+/* Start of tfc_tpg_nacl_param_cit */
+
+CONFIGFS_EATTR_OPS(target_fabric_nacl_param, se_node_acl, acl_param_group);
+
+static struct configfs_item_operations target_fabric_nacl_param_item_ops = {
+ .show_attribute = target_fabric_nacl_param_attr_show,
+ .store_attribute = target_fabric_nacl_param_attr_store,
+};
+
+TF_CIT_SETUP(tpg_nacl_param, &target_fabric_nacl_param_item_ops, NULL, NULL);
+
+/* End of tfc_tpg_nacl_param_cit */
+
+/* Start of tfc_tpg_nacl_base_cit */
+
+CONFIGFS_EATTR_OPS(target_fabric_nacl_base, se_node_acl, acl_group);
+
+static struct config_group *target_fabric_make_mappedlun(
+ struct config_group *group,
+ const char *name)
+{
+ struct se_node_acl *se_nacl = container_of(group,
+ struct se_node_acl, acl_group);
+ struct se_portal_group *se_tpg = se_nacl->se_tpg;
+ struct target_fabric_configfs *tf = se_tpg->se_tpg_wwn->wwn_tf;
+ struct se_lun_acl *lacl;
+ struct config_item *acl_ci;
+ char *buf;
+ unsigned long mapped_lun;
+ int ret = 0;
+
+ acl_ci = &group->cg_item;
+ if (!(acl_ci)) {
+ printk(KERN_ERR "Unable to locatel acl_ci\n");
+ return NULL;
+ }
+
+ buf = kzalloc(strlen(name) + 1, GFP_KERNEL);
+ if (!(buf)) {
+ printk(KERN_ERR "Unable to allocate memory for name buf\n");
+ return ERR_PTR(-ENOMEM);
+ }
+ snprintf(buf, strlen(name) + 1, "%s", name);
+ /*
+ * Make sure user is creating iscsi/$IQN/$TPGT/acls/$INITIATOR/lun_$ID.
+ */
+ if (strstr(buf, "lun_") != buf) {
+ printk(KERN_ERR "Unable to locate \"lun_\" from buf: %s"
+ " name: %s\n", buf, name);
+ ret = -EINVAL;
+ goto out;
+ }
+ /*
+ * Determine the Mapped LUN value. This is what the SCSI Initiator
+ * Port will actually see.
+ */
+ if (strict_strtoul(buf + 4, 0, &mapped_lun) || mapped_lun > UINT_MAX) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ lacl = core_dev_init_initiator_node_lun_acl(se_tpg, mapped_lun,
+ config_item_name(acl_ci), &ret);
+ if (!(lacl))
+ goto out;
+
+ config_group_init_type_name(&lacl->se_lun_group, name,
+ &TF_CIT_TMPL(tf)->tfc_tpg_mappedlun_cit);
+
+ kfree(buf);
+ return &lacl->se_lun_group;
+out:
+ kfree(buf);
+ return ERR_PTR(ret);
+}
+
+static void target_fabric_drop_mappedlun(
+ struct config_group *group,
+ struct config_item *item)
+{
+ struct se_lun_acl *lacl = container_of(to_config_group(item),
+ struct se_lun_acl, se_lun_group);
+ struct se_portal_group *se_tpg = lacl->se_lun_nacl->se_tpg;
+
+ config_item_put(item);
+ core_dev_free_initiator_node_lun_acl(se_tpg, lacl);
+}
+
+static struct configfs_item_operations target_fabric_nacl_base_item_ops = {
+ .show_attribute = target_fabric_nacl_base_attr_show,
+ .store_attribute = target_fabric_nacl_base_attr_store,
+};
+
+static struct configfs_group_operations target_fabric_nacl_base_group_ops = {
+ .make_group = target_fabric_make_mappedlun,
+ .drop_item = target_fabric_drop_mappedlun,
+};
+
+TF_CIT_SETUP(tpg_nacl_base, &target_fabric_nacl_base_item_ops,
+ &target_fabric_nacl_base_group_ops, NULL);
+
+/* End of tfc_tpg_nacl_base_cit */
+
+/* Start of tfc_tpg_nacl_cit */
+
+static struct config_group *target_fabric_make_nodeacl(
+ struct config_group *group,
+ const char *name)
+{
+ struct se_portal_group *se_tpg = container_of(group,
+ struct se_portal_group, tpg_acl_group);
+ struct target_fabric_configfs *tf = se_tpg->se_tpg_wwn->wwn_tf;
+ struct se_node_acl *se_nacl;
+ struct config_group *nacl_cg;
+
+ if (!(tf->tf_ops.fabric_make_nodeacl)) {
+ printk(KERN_ERR "tf->tf_ops.fabric_make_nodeacl is NULL\n");
+ return ERR_PTR(-ENOSYS);
+ }
+
+ se_nacl = tf->tf_ops.fabric_make_nodeacl(se_tpg, group, name);
+ if (IS_ERR(se_nacl))
+ return ERR_PTR(PTR_ERR(se_nacl));
+
+ nacl_cg = &se_nacl->acl_group;
+ nacl_cg->default_groups = se_nacl->acl_default_groups;
+ nacl_cg->default_groups[0] = &se_nacl->acl_attrib_group;
+ nacl_cg->default_groups[1] = &se_nacl->acl_auth_group;
+ nacl_cg->default_groups[2] = &se_nacl->acl_param_group;
+ nacl_cg->default_groups[3] = NULL;
+
+ config_group_init_type_name(&se_nacl->acl_group, name,
+ &TF_CIT_TMPL(tf)->tfc_tpg_nacl_base_cit);
+ config_group_init_type_name(&se_nacl->acl_attrib_group, "attrib",
+ &TF_CIT_TMPL(tf)->tfc_tpg_nacl_attrib_cit);
+ config_group_init_type_name(&se_nacl->acl_auth_group, "auth",
+ &TF_CIT_TMPL(tf)->tfc_tpg_nacl_auth_cit);
+ config_group_init_type_name(&se_nacl->acl_param_group, "param",
+ &TF_CIT_TMPL(tf)->tfc_tpg_nacl_param_cit);
+
+ return &se_nacl->acl_group;
+}
+
+static void target_fabric_drop_nodeacl(
+ struct config_group *group,
+ struct config_item *item)
+{
+ struct se_portal_group *se_tpg = container_of(group,
+ struct se_portal_group, tpg_acl_group);
+ struct target_fabric_configfs *tf = se_tpg->se_tpg_wwn->wwn_tf;
+ struct se_node_acl *se_nacl = container_of(to_config_group(item),
+ struct se_node_acl, acl_group);
+ struct config_item *df_item;
+ struct config_group *nacl_cg;
+ int i;
+
+ nacl_cg = &se_nacl->acl_group;
+ for (i = 0; nacl_cg->default_groups[i]; i++) {
+ df_item = &nacl_cg->default_groups[i]->cg_item;
+ nacl_cg->default_groups[i] = NULL;
+ config_item_put(df_item);
+ }
+
+ config_item_put(item);
+ tf->tf_ops.fabric_drop_nodeacl(se_nacl);
+}
+
+static struct configfs_group_operations target_fabric_nacl_group_ops = {
+ .make_group = target_fabric_make_nodeacl,
+ .drop_item = target_fabric_drop_nodeacl,
+};
+
+TF_CIT_SETUP(tpg_nacl, NULL, &target_fabric_nacl_group_ops, NULL);
+
+/* End of tfc_tpg_nacl_cit */
+
+/* Start of tfc_tpg_np_base_cit */
+
+CONFIGFS_EATTR_OPS(target_fabric_np_base, se_tpg_np, tpg_np_group);
+
+static struct configfs_item_operations target_fabric_np_base_item_ops = {
+ .show_attribute = target_fabric_np_base_attr_show,
+ .store_attribute = target_fabric_np_base_attr_store,
+};
+
+TF_CIT_SETUP(tpg_np_base, &target_fabric_np_base_item_ops, NULL, NULL);
+
+/* End of tfc_tpg_np_base_cit */
+
+/* Start of tfc_tpg_np_cit */
+
+static struct config_group *target_fabric_make_np(
+ struct config_group *group,
+ const char *name)
+{
+ struct se_portal_group *se_tpg = container_of(group,
+ struct se_portal_group, tpg_np_group);
+ struct target_fabric_configfs *tf = se_tpg->se_tpg_wwn->wwn_tf;
+ struct se_tpg_np *se_tpg_np;
+
+ if (!(tf->tf_ops.fabric_make_np)) {
+ printk(KERN_ERR "tf->tf_ops.fabric_make_np is NULL\n");
+ return ERR_PTR(-ENOSYS);
+ }
+
+ se_tpg_np = tf->tf_ops.fabric_make_np(se_tpg, group, name);
+ if (!(se_tpg_np) || IS_ERR(se_tpg_np))
+ return ERR_PTR(-EINVAL);
+
+ config_group_init_type_name(&se_tpg_np->tpg_np_group, name,
+ &TF_CIT_TMPL(tf)->tfc_tpg_np_base_cit);
+
+ return &se_tpg_np->tpg_np_group;
+}
+
+static void target_fabric_drop_np(
+ struct config_group *group,
+ struct config_item *item)
+{
+ struct se_portal_group *se_tpg = container_of(group,
+ struct se_portal_group, tpg_np_group);
+ struct target_fabric_configfs *tf = se_tpg->se_tpg_wwn->wwn_tf;
+ struct se_tpg_np *se_tpg_np = container_of(to_config_group(item),
+ struct se_tpg_np, tpg_np_group);
+
+ config_item_put(item);
+ tf->tf_ops.fabric_drop_np(se_tpg_np);
+}
+
+static struct configfs_group_operations target_fabric_np_group_ops = {
+ .make_group = &target_fabric_make_np,
+ .drop_item = &target_fabric_drop_np,
+};
+
+TF_CIT_SETUP(tpg_np, NULL, &target_fabric_np_group_ops, NULL);
+
+/* End of tfc_tpg_np_cit */
+
+/* Start of tfc_tpg_port_cit */
+
+CONFIGFS_EATTR_STRUCT(target_fabric_port, se_lun);
+#define TCM_PORT_ATTR(_name, _mode) \
+static struct target_fabric_port_attribute target_fabric_port_##_name = \
+ __CONFIGFS_EATTR(_name, _mode, \
+ target_fabric_port_show_attr_##_name, \
+ target_fabric_port_store_attr_##_name);
+
+#define TCM_PORT_ATTOR_RO(_name) \
+ __CONFIGFS_EATTR_RO(_name, \
+ target_fabric_port_show_attr_##_name);
+
+/*
+ * alua_tg_pt_gp
+ */
+static ssize_t target_fabric_port_show_attr_alua_tg_pt_gp(
+ struct se_lun *lun,
+ char *page)
+{
+ if (!(lun))
+ return -ENODEV;
+
+ if (!(lun->lun_sep))
+ return -ENODEV;
+
+ return core_alua_show_tg_pt_gp_info(lun->lun_sep, page);
+}
+
+static ssize_t target_fabric_port_store_attr_alua_tg_pt_gp(
+ struct se_lun *lun,
+ const char *page,
+ size_t count)
+{
+ if (!(lun))
+ return -ENODEV;
+
+ if (!(lun->lun_sep))
+ return -ENODEV;
+
+ return core_alua_store_tg_pt_gp_info(lun->lun_sep, page, count);
+}
+
+TCM_PORT_ATTR(alua_tg_pt_gp, S_IRUGO | S_IWUSR);
+
+/*
+ * alua_tg_pt_offline
+ */
+static ssize_t target_fabric_port_show_attr_alua_tg_pt_offline(
+ struct se_lun *lun,
+ char *page)
+{
+ if (!(lun))
+ return -ENODEV;
+
+ if (!(lun->lun_sep))
+ return -ENODEV;
+
+ return core_alua_show_offline_bit(lun, page);
+}
+
+static ssize_t target_fabric_port_store_attr_alua_tg_pt_offline(
+ struct se_lun *lun,
+ const char *page,
+ size_t count)
+{
+ if (!(lun))
+ return -ENODEV;
+
+ if (!(lun->lun_sep))
+ return -ENODEV;
+
+ return core_alua_store_offline_bit(lun, page, count);
+}
+
+TCM_PORT_ATTR(alua_tg_pt_offline, S_IRUGO | S_IWUSR);
+
+/*
+ * alua_tg_pt_status
+ */
+static ssize_t target_fabric_port_show_attr_alua_tg_pt_status(
+ struct se_lun *lun,
+ char *page)
+{
+ if (!(lun))
+ return -ENODEV;
+
+ if (!(lun->lun_sep))
+ return -ENODEV;
+
+ return core_alua_show_secondary_status(lun, page);
+}
+
+static ssize_t target_fabric_port_store_attr_alua_tg_pt_status(
+ struct se_lun *lun,
+ const char *page,
+ size_t count)
+{
+ if (!(lun))
+ return -ENODEV;
+
+ if (!(lun->lun_sep))
+ return -ENODEV;
+
+ return core_alua_store_secondary_status(lun, page, count);
+}
+
+TCM_PORT_ATTR(alua_tg_pt_status, S_IRUGO | S_IWUSR);
+
+/*
+ * alua_tg_pt_write_md
+ */
+static ssize_t target_fabric_port_show_attr_alua_tg_pt_write_md(
+ struct se_lun *lun,
+ char *page)
+{
+ if (!(lun))
+ return -ENODEV;
+
+ if (!(lun->lun_sep))
+ return -ENODEV;
+
+ return core_alua_show_secondary_write_metadata(lun, page);
+}
+
+static ssize_t target_fabric_port_store_attr_alua_tg_pt_write_md(
+ struct se_lun *lun,
+ const char *page,
+ size_t count)
+{
+ if (!(lun))
+ return -ENODEV;
+
+ if (!(lun->lun_sep))
+ return -ENODEV;
+
+ return core_alua_store_secondary_write_metadata(lun, page, count);
+}
+
+TCM_PORT_ATTR(alua_tg_pt_write_md, S_IRUGO | S_IWUSR);
+
+
+static struct configfs_attribute *target_fabric_port_attrs[] = {
+ &target_fabric_port_alua_tg_pt_gp.attr,
+ &target_fabric_port_alua_tg_pt_offline.attr,
+ &target_fabric_port_alua_tg_pt_status.attr,
+ &target_fabric_port_alua_tg_pt_write_md.attr,
+ NULL,
+};
+
+CONFIGFS_EATTR_OPS(target_fabric_port, se_lun, lun_group);
+
+static int target_fabric_port_link(
+ struct config_item *lun_ci,
+ struct config_item *se_dev_ci)
+{
+ struct config_item *tpg_ci;
+ struct se_device *dev;
+ struct se_lun *lun = container_of(to_config_group(lun_ci),
+ struct se_lun, lun_group);
+ struct se_lun *lun_p;
+ struct se_portal_group *se_tpg;
+ struct se_subsystem_dev *se_dev = container_of(
+ to_config_group(se_dev_ci), struct se_subsystem_dev,
+ se_dev_group);
+ struct target_fabric_configfs *tf;
+ int ret;
+
+ tpg_ci = &lun_ci->ci_parent->ci_group->cg_item;
+ se_tpg = container_of(to_config_group(tpg_ci),
+ struct se_portal_group, tpg_group);
+ tf = se_tpg->se_tpg_wwn->wwn_tf;
+
+ if (lun->lun_se_dev != NULL) {
+ printk(KERN_ERR "Port Symlink already exists\n");
+ return -EEXIST;
+ }
+
+ dev = se_dev->se_dev_ptr;
+ if (!(dev)) {
+ printk(KERN_ERR "Unable to locate struct se_device pointer from"
+ " %s\n", config_item_name(se_dev_ci));
+ ret = -ENODEV;
+ goto out;
+ }
+
+ lun_p = core_dev_add_lun(se_tpg, dev->se_hba, dev,
+ lun->unpacked_lun);
+ if ((IS_ERR(lun_p)) || !(lun_p)) {
+ printk(KERN_ERR "core_dev_add_lun() failed\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (tf->tf_ops.fabric_post_link) {
+ /*
+ * Call the optional fabric_post_link() to allow a
+ * fabric module to setup any additional state once
+ * core_dev_add_lun() has been called..
+ */
+ tf->tf_ops.fabric_post_link(se_tpg, lun);
+ }
+
+ return 0;
+out:
+ return ret;
+}
+
+static int target_fabric_port_unlink(
+ struct config_item *lun_ci,
+ struct config_item *se_dev_ci)
+{
+ struct se_lun *lun = container_of(to_config_group(lun_ci),
+ struct se_lun, lun_group);
+ struct se_portal_group *se_tpg = lun->lun_sep->sep_tpg;
+ struct target_fabric_configfs *tf = se_tpg->se_tpg_wwn->wwn_tf;
+
+ if (tf->tf_ops.fabric_pre_unlink) {
+ /*
+ * Call the optional fabric_pre_unlink() to allow a
+ * fabric module to release any additional stat before
+ * core_dev_del_lun() is called.
+ */
+ tf->tf_ops.fabric_pre_unlink(se_tpg, lun);
+ }
+
+ core_dev_del_lun(se_tpg, lun->unpacked_lun);
+ return 0;
+}
+
+static struct configfs_item_operations target_fabric_port_item_ops = {
+ .show_attribute = target_fabric_port_attr_show,
+ .store_attribute = target_fabric_port_attr_store,
+ .allow_link = target_fabric_port_link,
+ .drop_link = target_fabric_port_unlink,
+};
+
+TF_CIT_SETUP(tpg_port, &target_fabric_port_item_ops, NULL, target_fabric_port_attrs);
+
+/* End of tfc_tpg_port_cit */
+
+/* Start of tfc_tpg_lun_cit */
+
+static struct config_group *target_fabric_make_lun(
+ struct config_group *group,
+ const char *name)
+{
+ struct se_lun *lun;
+ struct se_portal_group *se_tpg = container_of(group,
+ struct se_portal_group, tpg_lun_group);
+ struct target_fabric_configfs *tf = se_tpg->se_tpg_wwn->wwn_tf;
+ unsigned long unpacked_lun;
+
+ if (strstr(name, "lun_") != name) {
+ printk(KERN_ERR "Unable to locate \'_\" in"
+ " \"lun_$LUN_NUMBER\"\n");
+ return ERR_PTR(-EINVAL);
+ }
+ if (strict_strtoul(name + 4, 0, &unpacked_lun) || unpacked_lun > UINT_MAX)
+ return ERR_PTR(-EINVAL);
+
+ lun = core_get_lun_from_tpg(se_tpg, unpacked_lun);
+ if (!(lun))
+ return ERR_PTR(-EINVAL);
+
+ config_group_init_type_name(&lun->lun_group, name,
+ &TF_CIT_TMPL(tf)->tfc_tpg_port_cit);
+
+ return &lun->lun_group;
+}
+
+static void target_fabric_drop_lun(
+ struct config_group *group,
+ struct config_item *item)
+{
+ config_item_put(item);
+}
+
+static struct configfs_group_operations target_fabric_lun_group_ops = {
+ .make_group = &target_fabric_make_lun,
+ .drop_item = &target_fabric_drop_lun,
+};
+
+TF_CIT_SETUP(tpg_lun, NULL, &target_fabric_lun_group_ops, NULL);
+
+/* End of tfc_tpg_lun_cit */
+
+/* Start of tfc_tpg_attrib_cit */
+
+CONFIGFS_EATTR_OPS(target_fabric_tpg_attrib, se_portal_group, tpg_attrib_group);
+
+static struct configfs_item_operations target_fabric_tpg_attrib_item_ops = {
+ .show_attribute = target_fabric_tpg_attrib_attr_show,
+ .store_attribute = target_fabric_tpg_attrib_attr_store,
+};
+
+TF_CIT_SETUP(tpg_attrib, &target_fabric_tpg_attrib_item_ops, NULL, NULL);
+
+/* End of tfc_tpg_attrib_cit */
+
+/* Start of tfc_tpg_param_cit */
+
+CONFIGFS_EATTR_OPS(target_fabric_tpg_param, se_portal_group, tpg_param_group);
+
+static struct configfs_item_operations target_fabric_tpg_param_item_ops = {
+ .show_attribute = target_fabric_tpg_param_attr_show,
+ .store_attribute = target_fabric_tpg_param_attr_store,
+};
+
+TF_CIT_SETUP(tpg_param, &target_fabric_tpg_param_item_ops, NULL, NULL);
+
+/* End of tfc_tpg_param_cit */
+
+/* Start of tfc_tpg_base_cit */
+/*
+ * For use with TF_TPG_ATTR() and TF_TPG_ATTR_RO()
+ */
+CONFIGFS_EATTR_OPS(target_fabric_tpg, se_portal_group, tpg_group);
+
+static struct configfs_item_operations target_fabric_tpg_base_item_ops = {
+ .show_attribute = target_fabric_tpg_attr_show,
+ .store_attribute = target_fabric_tpg_attr_store,
+};
+
+TF_CIT_SETUP(tpg_base, &target_fabric_tpg_base_item_ops, NULL, NULL);
+
+/* End of tfc_tpg_base_cit */
+
+/* Start of tfc_tpg_cit */
+
+static struct config_group *target_fabric_make_tpg(
+ struct config_group *group,
+ const char *name)
+{
+ struct se_wwn *wwn = container_of(group, struct se_wwn, wwn_group);
+ struct target_fabric_configfs *tf = wwn->wwn_tf;
+ struct se_portal_group *se_tpg;
+
+ if (!(tf->tf_ops.fabric_make_tpg)) {
+ printk(KERN_ERR "tf->tf_ops.fabric_make_tpg is NULL\n");
+ return ERR_PTR(-ENOSYS);
+ }
+
+ se_tpg = tf->tf_ops.fabric_make_tpg(wwn, group, name);
+ if (!(se_tpg) || IS_ERR(se_tpg))
+ return ERR_PTR(-EINVAL);
+ /*
+ * Setup default groups from pre-allocated se_tpg->tpg_default_groups
+ */
+ se_tpg->tpg_group.default_groups = se_tpg->tpg_default_groups;
+ se_tpg->tpg_group.default_groups[0] = &se_tpg->tpg_lun_group;
+ se_tpg->tpg_group.default_groups[1] = &se_tpg->tpg_np_group;
+ se_tpg->tpg_group.default_groups[2] = &se_tpg->tpg_acl_group;
+ se_tpg->tpg_group.default_groups[3] = &se_tpg->tpg_attrib_group;
+ se_tpg->tpg_group.default_groups[4] = &se_tpg->tpg_param_group;
+ se_tpg->tpg_group.default_groups[5] = NULL;
+
+ config_group_init_type_name(&se_tpg->tpg_group, name,
+ &TF_CIT_TMPL(tf)->tfc_tpg_base_cit);
+ config_group_init_type_name(&se_tpg->tpg_lun_group, "lun",
+ &TF_CIT_TMPL(tf)->tfc_tpg_lun_cit);
+ config_group_init_type_name(&se_tpg->tpg_np_group, "np",
+ &TF_CIT_TMPL(tf)->tfc_tpg_np_cit);
+ config_group_init_type_name(&se_tpg->tpg_acl_group, "acls",
+ &TF_CIT_TMPL(tf)->tfc_tpg_nacl_cit);
+ config_group_init_type_name(&se_tpg->tpg_attrib_group, "attrib",
+ &TF_CIT_TMPL(tf)->tfc_tpg_attrib_cit);
+ config_group_init_type_name(&se_tpg->tpg_param_group, "param",
+ &TF_CIT_TMPL(tf)->tfc_tpg_param_cit);
+
+ return &se_tpg->tpg_group;
+}
+
+static void target_fabric_drop_tpg(
+ struct config_group *group,
+ struct config_item *item)
+{
+ struct se_wwn *wwn = container_of(group, struct se_wwn, wwn_group);
+ struct target_fabric_configfs *tf = wwn->wwn_tf;
+ struct se_portal_group *se_tpg = container_of(to_config_group(item),
+ struct se_portal_group, tpg_group);
+ struct config_group *tpg_cg = &se_tpg->tpg_group;
+ struct config_item *df_item;
+ int i;
+ /*
+ * Release default groups, but do not release tpg_cg->default_groups
+ * memory as it is statically allocated at se_tpg->tpg_default_groups.
+ */
+ for (i = 0; tpg_cg->default_groups[i]; i++) {
+ df_item = &tpg_cg->default_groups[i]->cg_item;
+ tpg_cg->default_groups[i] = NULL;
+ config_item_put(df_item);
+ }
+
+ config_item_put(item);
+ tf->tf_ops.fabric_drop_tpg(se_tpg);
+}
+
+static struct configfs_group_operations target_fabric_tpg_group_ops = {
+ .make_group = target_fabric_make_tpg,
+ .drop_item = target_fabric_drop_tpg,
+};
+
+TF_CIT_SETUP(tpg, NULL, &target_fabric_tpg_group_ops, NULL);
+
+/* End of tfc_tpg_cit */
+
+/* Start of tfc_wwn_cit */
+
+static struct config_group *target_fabric_make_wwn(
+ struct config_group *group,
+ const char *name)
+{
+ struct target_fabric_configfs *tf = container_of(group,
+ struct target_fabric_configfs, tf_group);
+ struct se_wwn *wwn;
+
+ if (!(tf->tf_ops.fabric_make_wwn)) {
+ printk(KERN_ERR "tf->tf_ops.fabric_make_wwn is NULL\n");
+ return ERR_PTR(-ENOSYS);
+ }
+
+ wwn = tf->tf_ops.fabric_make_wwn(tf, group, name);
+ if (!(wwn) || IS_ERR(wwn))
+ return ERR_PTR(-EINVAL);
+
+ wwn->wwn_tf = tf;
+ config_group_init_type_name(&wwn->wwn_group, name,
+ &TF_CIT_TMPL(tf)->tfc_tpg_cit);
+
+ return &wwn->wwn_group;
+}
+
+static void target_fabric_drop_wwn(
+ struct config_group *group,
+ struct config_item *item)
+{
+ struct target_fabric_configfs *tf = container_of(group,
+ struct target_fabric_configfs, tf_group);
+ struct se_wwn *wwn = container_of(to_config_group(item),
+ struct se_wwn, wwn_group);
+
+ config_item_put(item);
+ tf->tf_ops.fabric_drop_wwn(wwn);
+}
+
+static struct configfs_group_operations target_fabric_wwn_group_ops = {
+ .make_group = target_fabric_make_wwn,
+ .drop_item = target_fabric_drop_wwn,
+};
+/*
+ * For use with TF_WWN_ATTR() and TF_WWN_ATTR_RO()
+ */
+CONFIGFS_EATTR_OPS(target_fabric_wwn, target_fabric_configfs, tf_group);
+
+static struct configfs_item_operations target_fabric_wwn_item_ops = {
+ .show_attribute = target_fabric_wwn_attr_show,
+ .store_attribute = target_fabric_wwn_attr_store,
+};
+
+TF_CIT_SETUP(wwn, &target_fabric_wwn_item_ops, &target_fabric_wwn_group_ops, NULL);
+
+/* End of tfc_wwn_cit */
+
+/* Start of tfc_discovery_cit */
+
+CONFIGFS_EATTR_OPS(target_fabric_discovery, target_fabric_configfs,
+ tf_disc_group);
+
+static struct configfs_item_operations target_fabric_discovery_item_ops = {
+ .show_attribute = target_fabric_discovery_attr_show,
+ .store_attribute = target_fabric_discovery_attr_store,
+};
+
+TF_CIT_SETUP(discovery, &target_fabric_discovery_item_ops, NULL, NULL);
+
+/* End of tfc_discovery_cit */
+
+int target_fabric_setup_cits(struct target_fabric_configfs *tf)
+{
+ target_fabric_setup_discovery_cit(tf);
+ target_fabric_setup_wwn_cit(tf);
+ target_fabric_setup_tpg_cit(tf);
+ target_fabric_setup_tpg_base_cit(tf);
+ target_fabric_setup_tpg_port_cit(tf);
+ target_fabric_setup_tpg_lun_cit(tf);
+ target_fabric_setup_tpg_np_cit(tf);
+ target_fabric_setup_tpg_np_base_cit(tf);
+ target_fabric_setup_tpg_attrib_cit(tf);
+ target_fabric_setup_tpg_param_cit(tf);
+ target_fabric_setup_tpg_nacl_cit(tf);
+ target_fabric_setup_tpg_nacl_base_cit(tf);
+ target_fabric_setup_tpg_nacl_attrib_cit(tf);
+ target_fabric_setup_tpg_nacl_auth_cit(tf);
+ target_fabric_setup_tpg_nacl_param_cit(tf);
+ target_fabric_setup_tpg_mappedlun_cit(tf);
+
+ return 0;
+}
diff --git a/drivers/target/target_core_fabric_lib.c b/drivers/target/target_core_fabric_lib.c
new file mode 100644
index 0000000..2628564
--- /dev/null
+++ b/drivers/target/target_core_fabric_lib.c
@@ -0,0 +1,451 @@
+/*******************************************************************************
+ * Filename: target_core_fabric_lib.c
+ *
+ * This file contains generic high level protocol identifier and PR
+ * handlers for TCM fabric modules
+ *
+ * Copyright (c) 2010 Rising Tide Systems, Inc.
+ * Copyright (c) 2010 Linux-iSCSI.org
+ *
+ * Nicholas A. Bellinger <nab@linux-iscsi.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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ ******************************************************************************/
+
+#include <linux/string.h>
+#include <linux/ctype.h>
+#include <linux/spinlock.h>
+#include <linux/smp_lock.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+
+#include <target/target_core_base.h>
+#include <target/target_core_device.h>
+#include <target/target_core_transport.h>
+#include <target/target_core_fabric_ops.h>
+#include <target/target_core_configfs.h>
+
+#include "target_core_hba.h"
+#include "target_core_pr.h"
+
+/*
+ * Handlers for Serial Attached SCSI (SAS)
+ */
+u8 sas_get_fabric_proto_ident(struct se_portal_group *se_tpg)
+{
+ /*
+ * Return a SAS Serial SCSI Protocol identifier for loopback operations
+ * This is defined in section 7.5.1 Table 362 in spc4r17
+ */
+ return 0x6;
+}
+EXPORT_SYMBOL(sas_get_fabric_proto_ident);
+
+u32 sas_get_pr_transport_id(
+ struct se_portal_group *se_tpg,
+ struct se_node_acl *se_nacl,
+ struct t10_pr_registration *pr_reg,
+ int *format_code,
+ unsigned char *buf)
+{
+ unsigned char binary, *ptr;
+ int i;
+ u32 off = 4;
+ /*
+ * Set PROTOCOL IDENTIFIER to 6h for SAS
+ */
+ buf[0] = 0x06;
+ /*
+ * From spc4r17, 7.5.4.7 TransportID for initiator ports using SCSI
+ * over SAS Serial SCSI Protocol
+ */
+ ptr = &se_nacl->initiatorname[4]; /* Skip over 'naa. prefix */
+
+ for (i = 0; i < 16; i += 2) {
+ binary = transport_asciihex_to_binaryhex(&ptr[i]);
+ buf[off++] = binary;
+ }
+ /*
+ * The SAS Transport ID is a hardcoded 24-byte length
+ */
+ return 24;
+}
+EXPORT_SYMBOL(sas_get_pr_transport_id);
+
+u32 sas_get_pr_transport_id_len(
+ struct se_portal_group *se_tpg,
+ struct se_node_acl *se_nacl,
+ struct t10_pr_registration *pr_reg,
+ int *format_code)
+{
+ *format_code = 0;
+ /*
+ * From spc4r17, 7.5.4.7 TransportID for initiator ports using SCSI
+ * over SAS Serial SCSI Protocol
+ *
+ * The SAS Transport ID is a hardcoded 24-byte length
+ */
+ return 24;
+}
+EXPORT_SYMBOL(sas_get_pr_transport_id_len);
+
+/*
+ * Used for handling SCSI fabric dependent TransportIDs in SPC-3 and above
+ * Persistent Reservation SPEC_I_PT=1 and PROUT REGISTER_AND_MOVE operations.
+ */
+char *sas_parse_pr_out_transport_id(
+ struct se_portal_group *se_tpg,
+ const char *buf,
+ u32 *out_tid_len,
+ char **port_nexus_ptr)
+{
+ /*
+ * Assume the FORMAT CODE 00b from spc4r17, 7.5.4.7 TransportID
+ * for initiator ports using SCSI over SAS Serial SCSI Protocol
+ *
+ * The TransportID for a SAS Initiator Port is of fixed size of
+ * 24 bytes, and SAS does not contain a I_T nexus identifier,
+ * so we return the **port_nexus_ptr set to NULL.
+ */
+ *port_nexus_ptr = NULL;
+ *out_tid_len = 24;
+
+ return (char *)&buf[4];
+}
+EXPORT_SYMBOL(sas_parse_pr_out_transport_id);
+
+/*
+ * Handlers for Fibre Channel Protocol (FCP)
+ */
+u8 fc_get_fabric_proto_ident(struct se_portal_group *se_tpg)
+{
+ return 0x0; /* 0 = fcp-2 per SPC4 section 7.5.1 */
+}
+EXPORT_SYMBOL(fc_get_fabric_proto_ident);
+
+u32 fc_get_pr_transport_id_len(
+ struct se_portal_group *se_tpg,
+ struct se_node_acl *se_nacl,
+ struct t10_pr_registration *pr_reg,
+ int *format_code)
+{
+ *format_code = 0;
+ /*
+ * The FC Transport ID is a hardcoded 24-byte length
+ */
+ return 24;
+}
+EXPORT_SYMBOL(fc_get_pr_transport_id_len);
+
+u32 fc_get_pr_transport_id(
+ struct se_portal_group *se_tpg,
+ struct se_node_acl *se_nacl,
+ struct t10_pr_registration *pr_reg,
+ int *format_code,
+ unsigned char *buf)
+{
+ unsigned char binary, *ptr;
+ int i;
+ u32 off = 8;
+ /*
+ * PROTOCOL IDENTIFIER is 0h for FCP-2
+ *
+ * From spc4r17, 7.5.4.2 TransportID for initiator ports using
+ * SCSI over Fibre Channel
+ *
+ * We convert the ASCII formatted N Port name into a binary
+ * encoded TransportID.
+ */
+ ptr = &se_nacl->initiatorname[0];
+
+ for (i = 0; i < 24; ) {
+ if (!(strncmp(&ptr[i], ":", 1))) {
+ i++;
+ continue;
+ }
+ binary = transport_asciihex_to_binaryhex(&ptr[i]);
+ buf[off++] = binary;
+ i += 2;
+ }
+ /*
+ * The FC Transport ID is a hardcoded 24-byte length
+ */
+ return 24;
+}
+EXPORT_SYMBOL(fc_get_pr_transport_id);
+
+char *fc_parse_pr_out_transport_id(
+ struct se_portal_group *se_tpg,
+ const char *buf,
+ u32 *out_tid_len,
+ char **port_nexus_ptr)
+{
+ /*
+ * The TransportID for a FC N Port is of fixed size of
+ * 24 bytes, and FC does not contain a I_T nexus identifier,
+ * so we return the **port_nexus_ptr set to NULL.
+ */
+ *port_nexus_ptr = NULL;
+ *out_tid_len = 24;
+
+ return (char *)&buf[8];
+}
+EXPORT_SYMBOL(fc_parse_pr_out_transport_id);
+
+/*
+ * Handlers for Internet Small Computer Systems Interface (iSCSI)
+ */
+
+u8 iscsi_get_fabric_proto_ident(struct se_portal_group *se_tpg)
+{
+ /*
+ * This value is defined for "Internet SCSI (iSCSI)"
+ * in spc4r17 section 7.5.1 Table 362
+ */
+ return 0x5;
+}
+EXPORT_SYMBOL(iscsi_get_fabric_proto_ident);
+
+u32 iscsi_get_pr_transport_id(
+ struct se_portal_group *se_tpg,
+ struct se_node_acl *se_nacl,
+ struct t10_pr_registration *pr_reg,
+ int *format_code,
+ unsigned char *buf)
+{
+ u32 off = 4, padding = 0;
+ u16 len = 0;
+
+ spin_lock_irq(&se_nacl->nacl_sess_lock);
+ /*
+ * Set PROTOCOL IDENTIFIER to 5h for iSCSI
+ */
+ buf[0] = 0x05;
+ /*
+ * From spc4r17 Section 7.5.4.6: TransportID for initiator
+ * ports using SCSI over iSCSI.
+ *
+ * The null-terminated, null-padded (see 4.4.2) ISCSI NAME field
+ * shall contain the iSCSI name of an iSCSI initiator node (see
+ * RFC 3720). The first ISCSI NAME field byte containing an ASCII
+ * null character terminates the ISCSI NAME field without regard for
+ * the specified length of the iSCSI TransportID or the contents of
+ * the ADDITIONAL LENGTH field.
+ */
+ len = sprintf(&buf[off], "%s", se_nacl->initiatorname);
+ /*
+ * Add Extra byte for NULL terminator
+ */
+ len++;
+ /*
+ * If there is ISID present with the registration and *format code == 1
+ * 1, use iSCSI Initiator port TransportID format.
+ *
+ * Otherwise use iSCSI Initiator device TransportID format that
+ * does not contain the ASCII encoded iSCSI Initiator iSID value
+ * provied by the iSCSi Initiator during the iSCSI login process.
+ */
+ if ((*format_code == 1) && (pr_reg->isid_present_at_reg)) {
+ /*
+ * Set FORMAT CODE 01b for iSCSI Initiator port TransportID
+ * format.
+ */
+ buf[0] |= 0x40;
+ /*
+ * From spc4r17 Section 7.5.4.6: TransportID for initiator
+ * ports using SCSI over iSCSI. Table 390
+ *
+ * The SEPARATOR field shall contain the five ASCII
+ * characters ",i,0x".
+ *
+ * The null-terminated, null-padded ISCSI INITIATOR SESSION ID
+ * field shall contain the iSCSI initiator session identifier
+ * (see RFC 3720) in the form of ASCII characters that are the
+ * hexadecimal digits converted from the binary iSCSI initiator
+ * session identifier value. The first ISCSI INITIATOR SESSION
+ * ID field byte containing an ASCII null character
+ */
+ buf[off+len] = 0x2c; off++; /* ASCII Character: "," */
+ buf[off+len] = 0x69; off++; /* ASCII Character: "i" */
+ buf[off+len] = 0x2c; off++; /* ASCII Character: "," */
+ buf[off+len] = 0x30; off++; /* ASCII Character: "0" */
+ buf[off+len] = 0x78; off++; /* ASCII Character: "x" */
+ len += 5;
+ buf[off+len] = pr_reg->pr_reg_isid[0]; off++;
+ buf[off+len] = pr_reg->pr_reg_isid[1]; off++;
+ buf[off+len] = pr_reg->pr_reg_isid[2]; off++;
+ buf[off+len] = pr_reg->pr_reg_isid[3]; off++;
+ buf[off+len] = pr_reg->pr_reg_isid[4]; off++;
+ buf[off+len] = pr_reg->pr_reg_isid[5]; off++;
+ buf[off+len] = '\0'; off++;
+ len += 7;
+ }
+ spin_unlock_irq(&se_nacl->nacl_sess_lock);
+ /*
+ * The ADDITIONAL LENGTH field specifies the number of bytes that follow
+ * in the TransportID. The additional length shall be at least 20 and
+ * shall be a multiple of four.
+ */
+ padding = ((-len) & 3);
+ if (padding != 0)
+ len += padding;
+
+ buf[2] = ((len >> 8) & 0xff);
+ buf[3] = (len & 0xff);
+ /*
+ * Increment value for total payload + header length for
+ * full status descriptor
+ */
+ len += 4;
+
+ return len;
+}
+EXPORT_SYMBOL(iscsi_get_pr_transport_id);
+
+u32 iscsi_get_pr_transport_id_len(
+ struct se_portal_group *se_tpg,
+ struct se_node_acl *se_nacl,
+ struct t10_pr_registration *pr_reg,
+ int *format_code)
+{
+ u32 len = 0, padding = 0;
+
+ spin_lock_irq(&se_nacl->nacl_sess_lock);
+ len = strlen(se_nacl->initiatorname);
+ /*
+ * Add extra byte for NULL terminator
+ */
+ len++;
+ /*
+ * If there is ISID present with the registration, use format code:
+ * 01b: iSCSI Initiator port TransportID format
+ *
+ * If there is not an active iSCSI session, use format code:
+ * 00b: iSCSI Initiator device TransportID format
+ */
+ if (pr_reg->isid_present_at_reg) {
+ len += 5; /* For ",i,0x" ASCII seperator */
+ len += 7; /* For iSCSI Initiator Session ID + Null terminator */
+ *format_code = 1;
+ } else
+ *format_code = 0;
+ spin_unlock_irq(&se_nacl->nacl_sess_lock);
+ /*
+ * The ADDITIONAL LENGTH field specifies the number of bytes that follow
+ * in the TransportID. The additional length shall be at least 20 and
+ * shall be a multiple of four.
+ */
+ padding = ((-len) & 3);
+ if (padding != 0)
+ len += padding;
+ /*
+ * Increment value for total payload + header length for
+ * full status descriptor
+ */
+ len += 4;
+
+ return len;
+}
+EXPORT_SYMBOL(iscsi_get_pr_transport_id_len);
+
+char *iscsi_parse_pr_out_transport_id(
+ struct se_portal_group *se_tpg,
+ const char *buf,
+ u32 *out_tid_len,
+ char **port_nexus_ptr)
+{
+ char *p;
+ u32 tid_len, padding;
+ int i;
+ u16 add_len;
+ u8 format_code = (buf[0] & 0xc0);
+ /*
+ * Check for FORMAT CODE 00b or 01b from spc4r17, section 7.5.4.6:
+ *
+ * TransportID for initiator ports using SCSI over iSCSI,
+ * from Table 388 -- iSCSI TransportID formats.
+ *
+ * 00b Initiator port is identified using the world wide unique
+ * SCSI device name of the iSCSI initiator
+ * device containing the initiator port (see table 389).
+ * 01b Initiator port is identified using the world wide unique
+ * initiator port identifier (see table 390).10b to 11b
+ * Reserved
+ */
+ if ((format_code != 0x00) && (format_code != 0x40)) {
+ printk(KERN_ERR "Illegal format code: 0x%02x for iSCSI"
+ " Initiator Transport ID\n", format_code);
+ return NULL;
+ }
+ /*
+ * If the caller wants the TransportID Length, we set that value for the
+ * entire iSCSI Tarnsport ID now.
+ */
+ if (out_tid_len != NULL) {
+ add_len = ((buf[2] >> 8) & 0xff);
+ add_len |= (buf[3] & 0xff);
+
+ tid_len = strlen((char *)&buf[4]);
+ tid_len += 4; /* Add four bytes for iSCSI Transport ID header */
+ tid_len += 1; /* Add one byte for NULL terminator */
+ padding = ((-tid_len) & 3);
+ if (padding != 0)
+ tid_len += padding;
+
+ if ((add_len + 4) != tid_len) {
+ printk(KERN_INFO "LIO-Target Extracted add_len: %hu "
+ "does not match calculated tid_len: %u,"
+ " using tid_len instead\n", add_len+4, tid_len);
+ *out_tid_len = tid_len;
+ } else
+ *out_tid_len = (add_len + 4);
+ }
+ /*
+ * Check for ',i,0x' seperator between iSCSI Name and iSCSI Initiator
+ * Session ID as defined in Table 390 - iSCSI initiator port TransportID
+ * format.
+ */
+ if (format_code == 0x40) {
+ p = strstr((char *)&buf[4], ",i,0x");
+ if (!(p)) {
+ printk(KERN_ERR "Unable to locate \",i,0x\" seperator"
+ " for Initiator port identifier: %s\n",
+ (char *)&buf[4]);
+ return NULL;
+ }
+ *p = '\0'; /* Terminate iSCSI Name */
+ p += 5; /* Skip over ",i,0x" seperator */
+
+ *port_nexus_ptr = p;
+ /*
+ * Go ahead and do the lower case conversion of the received
+ * 12 ASCII characters representing the ISID in the TransportID
+ * for comparision against the running iSCSI session's ISID from
+ * iscsi_target.c:lio_sess_get_initiator_sid()
+ */
+ for (i = 0; i < 12; i++) {
+ if (isdigit(*p)) {
+ p++;
+ continue;
+ }
+ *p = tolower(*p);
+ p++;
+ }
+ }
+
+ return (char *)&buf[4];
+}
+EXPORT_SYMBOL(iscsi_parse_pr_out_transport_id);
diff --git a/drivers/target/target_core_file.c b/drivers/target/target_core_file.c
new file mode 100644
index 0000000..0aaca88
--- /dev/null
+++ b/drivers/target/target_core_file.c
@@ -0,0 +1,688 @@
+/*******************************************************************************
+ * Filename: target_core_file.c
+ *
+ * This file contains the Storage Engine <-> FILEIO transport specific functions
+ *
+ * Copyright (c) 2005 PyX Technologies, Inc.
+ * Copyright (c) 2005-2006 SBE, Inc. All Rights Reserved.
+ * Copyright (c) 2007-2010 Rising Tide Systems
+ * Copyright (c) 2008-2010 Linux-iSCSI.org
+ *
+ * Nicholas A. Bellinger <nab@kernel.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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ ******************************************************************************/
+
+#include <linux/version.h>
+#include <linux/string.h>
+#include <linux/parser.h>
+#include <linux/timer.h>
+#include <linux/blkdev.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/smp_lock.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_host.h>
+
+#include <target/target_core_base.h>
+#include <target/target_core_device.h>
+#include <target/target_core_transport.h>
+
+#include "target_core_file.h"
+
+#if 1
+#define DEBUG_FD_CACHE(x...) printk(x)
+#else
+#define DEBUG_FD_CACHE(x...)
+#endif
+
+#if 1
+#define DEBUG_FD_FUA(x...) printk(x)
+#else
+#define DEBUG_FD_FUA(x...)
+#endif
+
+static struct se_subsystem_api fileio_template;
+
+/* fd_attach_hba(): (Part of se_subsystem_api_t template)
+ *
+ *
+ */
+static int fd_attach_hba(struct se_hba *hba, u32 host_id)
+{
+ struct fd_host *fd_host;
+
+ fd_host = kzalloc(sizeof(struct fd_host), GFP_KERNEL);
+ if (!(fd_host)) {
+ printk(KERN_ERR "Unable to allocate memory for struct fd_host\n");
+ return -1;
+ }
+
+ fd_host->fd_host_id = host_id;
+
+ atomic_set(&hba->left_queue_depth, FD_HBA_QUEUE_DEPTH);
+ atomic_set(&hba->max_queue_depth, FD_HBA_QUEUE_DEPTH);
+ hba->hba_ptr = (void *) fd_host;
+
+ printk(KERN_INFO "CORE_HBA[%d] - TCM FILEIO HBA Driver %s on Generic"
+ " Target Core Stack %s\n", hba->hba_id, FD_VERSION,
+ TARGET_CORE_MOD_VERSION);
+ printk(KERN_INFO "CORE_HBA[%d] - Attached FILEIO HBA: %u to Generic"
+ " Target Core with TCQ Depth: %d MaxSectors: %u\n",
+ hba->hba_id, fd_host->fd_host_id,
+ atomic_read(&hba->max_queue_depth), FD_MAX_SECTORS);
+
+ return 0;
+}
+
+static void fd_detach_hba(struct se_hba *hba)
+{
+ struct fd_host *fd_host = hba->hba_ptr;
+
+ printk(KERN_INFO "CORE_HBA[%d] - Detached FILEIO HBA: %u from Generic"
+ " Target Core\n", hba->hba_id, fd_host->fd_host_id);
+
+ kfree(fd_host);
+ hba->hba_ptr = NULL;
+}
+
+static void *fd_allocate_virtdevice(struct se_hba *hba, const char *name)
+{
+ struct fd_dev *fd_dev;
+ struct fd_host *fd_host = (struct fd_host *) hba->hba_ptr;
+
+ fd_dev = kzalloc(sizeof(struct fd_dev), GFP_KERNEL);
+ if (!(fd_dev)) {
+ printk(KERN_ERR "Unable to allocate memory for struct fd_dev\n");
+ return NULL;
+ }
+
+ fd_dev->fd_host = fd_host;
+
+ printk(KERN_INFO "FILEIO: Allocated fd_dev for %p\n", name);
+
+ return fd_dev;
+}
+
+/* fd_create_virtdevice(): (Part of se_subsystem_api_t template)
+ *
+ *
+ */
+static struct se_device *fd_create_virtdevice(
+ struct se_hba *hba,
+ struct se_subsystem_dev *se_dev,
+ void *p)
+{
+ char *dev_p = NULL;
+ struct se_device *dev;
+ struct se_dev_limits dev_limits;
+ struct queue_limits *limits;
+ struct fd_dev *fd_dev = (struct fd_dev *) p;
+ struct fd_host *fd_host = (struct fd_host *) hba->hba_ptr;
+ mm_segment_t old_fs;
+ struct file *file;
+ struct inode *inode = NULL;
+ int dev_flags = 0, flags;
+
+ memset(&dev_limits, 0, sizeof(struct se_dev_limits));
+
+ old_fs = get_fs();
+ set_fs(get_ds());
+ dev_p = getname(fd_dev->fd_dev_name);
+ set_fs(old_fs);
+
+ if (IS_ERR(dev_p)) {
+ printk(KERN_ERR "getname(%s) failed: %lu\n",
+ fd_dev->fd_dev_name, IS_ERR(dev_p));
+ goto fail;
+ }
+#if 0
+ if (di->no_create_file)
+ flags = O_RDWR | O_LARGEFILE;
+ else
+ flags = O_RDWR | O_CREAT | O_LARGEFILE;
+#else
+ flags = O_RDWR | O_CREAT | O_LARGEFILE;
+#endif
+/* flags |= O_DIRECT; */
+ /*
+ * If fd_buffered_io=1 has not been set explictly (the default),
+ * use O_SYNC to force FILEIO writes to disk.
+ */
+ if (!(fd_dev->fbd_flags & FDBD_USE_BUFFERED_IO))
+ flags |= O_SYNC;
+
+ file = filp_open(dev_p, flags, 0600);
+
+ if (IS_ERR(file) || !file || !file->f_dentry) {
+ printk(KERN_ERR "filp_open(%s) failed\n", dev_p);
+ goto fail;
+ }
+ fd_dev->fd_file = file;
+ /*
+ * If using a block backend with this struct file, we extract
+ * fd_dev->fd_[block,dev]_size from struct block_device.
+ *
+ * Otherwise, we use the passed fd_size= from configfs
+ */
+ inode = file->f_mapping->host;
+ if (S_ISBLK(inode->i_mode)) {
+ struct request_queue *q;
+ /*
+ * Setup the local scope queue_limits from struct request_queue->limits
+ * to pass into transport_add_device_to_core_hba() as struct se_dev_limits.
+ */
+ q = bdev_get_queue(inode->i_bdev);
+ limits = &dev_limits.limits;
+ limits->logical_block_size = bdev_logical_block_size(inode->i_bdev);
+ limits->max_hw_sectors = queue_max_hw_sectors(q);
+ limits->max_sectors = queue_max_sectors(q);
+ /*
+ * Determine the number of bytes from i_size_read() minus
+ * one (1) logical sector from underlying struct block_device
+ */
+ fd_dev->fd_block_size = bdev_logical_block_size(inode->i_bdev);
+ fd_dev->fd_dev_size = (i_size_read(file->f_mapping->host) -
+ fd_dev->fd_block_size);
+
+ printk(KERN_INFO "FILEIO: Using size: %llu bytes from struct"
+ " block_device blocks: %llu logical_block_size: %d\n",
+ fd_dev->fd_dev_size,
+ div_u64(fd_dev->fd_dev_size, fd_dev->fd_block_size),
+ fd_dev->fd_block_size);
+ } else {
+ if (!(fd_dev->fbd_flags & FBDF_HAS_SIZE)) {
+ printk(KERN_ERR "FILEIO: Missing fd_dev_size="
+ " parameter, and no backing struct"
+ " block_device\n");
+ goto fail;
+ }
+
+ limits = &dev_limits.limits;
+ limits->logical_block_size = FD_BLOCKSIZE;
+ limits->max_hw_sectors = FD_MAX_SECTORS;
+ limits->max_sectors = FD_MAX_SECTORS;
+ fd_dev->fd_block_size = FD_BLOCKSIZE;
+ }
+
+ dev_limits.hw_queue_depth = FD_MAX_DEVICE_QUEUE_DEPTH;
+ dev_limits.queue_depth = FD_DEVICE_QUEUE_DEPTH;
+
+ dev = transport_add_device_to_core_hba(hba, &fileio_template,
+ se_dev, dev_flags, (void *)fd_dev,
+ &dev_limits, "FILEIO", FD_VERSION);
+ if (!(dev))
+ goto fail;
+
+ fd_dev->fd_dev_id = fd_host->fd_host_dev_id_count++;
+ fd_dev->fd_queue_depth = dev->queue_depth;
+
+ printk(KERN_INFO "CORE_FILE[%u] - Added TCM FILEIO Device ID: %u at %s,"
+ " %llu total bytes\n", fd_host->fd_host_id, fd_dev->fd_dev_id,
+ fd_dev->fd_dev_name, fd_dev->fd_dev_size);
+
+ putname(dev_p);
+ return dev;
+fail:
+ if (fd_dev->fd_file) {
+ filp_close(fd_dev->fd_file, NULL);
+ fd_dev->fd_file = NULL;
+ }
+ putname(dev_p);
+ return NULL;
+}
+
+/* fd_free_device(): (Part of se_subsystem_api_t template)
+ *
+ *
+ */
+static void fd_free_device(void *p)
+{
+ struct fd_dev *fd_dev = (struct fd_dev *) p;
+
+ if (fd_dev->fd_file) {
+ filp_close(fd_dev->fd_file, NULL);
+ fd_dev->fd_file = NULL;
+ }
+
+ kfree(fd_dev);
+}
+
+static inline struct fd_request *FILE_REQ(struct se_task *task)
+{
+ return container_of(task, struct fd_request, fd_task);
+}
+
+
+static struct se_task *
+fd_alloc_task(struct se_cmd *cmd)
+{
+ struct fd_request *fd_req;
+
+ fd_req = kzalloc(sizeof(struct fd_request), GFP_KERNEL);
+ if (!(fd_req)) {
+ printk(KERN_ERR "Unable to allocate struct fd_request\n");
+ return NULL;
+ }
+
+ fd_req->fd_dev = SE_DEV(cmd)->dev_ptr;
+
+ return &fd_req->fd_task;
+}
+
+static int fd_do_readv(struct se_task *task)
+{
+ struct fd_request *req = FILE_REQ(task);
+ struct file *fd = req->fd_dev->fd_file;
+ struct scatterlist *sg = task->task_sg;
+ struct iovec *iov;
+ mm_segment_t old_fs;
+ loff_t pos = (task->task_lba * DEV_ATTRIB(task->se_dev)->block_size);
+ int ret = 0, i;
+
+ iov = kzalloc(sizeof(struct iovec) * task->task_sg_num, GFP_KERNEL);
+ if (!(iov)) {
+ printk(KERN_ERR "Unable to allocate fd_do_readv iov[]\n");
+ return -1;
+ }
+
+ for (i = 0; i < task->task_sg_num; i++) {
+ iov[i].iov_len = sg[i].length;
+ iov[i].iov_base = sg_virt(&sg[i]);
+ }
+
+ old_fs = get_fs();
+ set_fs(get_ds());
+ ret = vfs_readv(fd, &iov[0], task->task_sg_num, &pos);
+ set_fs(old_fs);
+
+ kfree(iov);
+ /*
+ * Return zeros and GOOD status even if the READ did not return
+ * the expected virt_size for struct file w/o a backing struct
+ * block_device.
+ */
+ if (S_ISBLK(fd->f_dentry->d_inode->i_mode)) {
+ if (ret < 0 || ret != task->task_size) {
+ printk(KERN_ERR "vfs_readv() returned %d,"
+ " expecting %d for S_ISBLK\n", ret,
+ (int)task->task_size);
+ return -1;
+ }
+ } else {
+ if (ret < 0) {
+ printk(KERN_ERR "vfs_readv() returned %d for non"
+ " S_ISBLK\n", ret);
+ return -1;
+ }
+ }
+
+ return 1;
+}
+
+static int fd_do_writev(struct se_task *task)
+{
+ struct fd_request *req = FILE_REQ(task);
+ struct file *fd = req->fd_dev->fd_file;
+ struct scatterlist *sg = task->task_sg;
+ struct iovec *iov;
+ mm_segment_t old_fs;
+ loff_t pos = (task->task_lba * DEV_ATTRIB(task->se_dev)->block_size);
+ int ret, i = 0;
+
+ iov = kzalloc(sizeof(struct iovec) * task->task_sg_num, GFP_KERNEL);
+ if (!(iov)) {
+ printk(KERN_ERR "Unable to allocate fd_do_writev iov[]\n");
+ return -1;
+ }
+
+ for (i = 0; i < task->task_sg_num; i++) {
+ iov[i].iov_len = sg[i].length;
+ iov[i].iov_base = sg_virt(&sg[i]);
+ }
+
+ old_fs = get_fs();
+ set_fs(get_ds());
+ ret = vfs_writev(fd, &iov[0], task->task_sg_num, &pos);
+ set_fs(old_fs);
+
+ kfree(iov);
+
+ if (ret < 0 || ret != task->task_size) {
+ printk(KERN_ERR "vfs_writev() returned %d\n", ret);
+ return -1;
+ }
+
+ return 1;
+}
+
+static void fd_emulate_sync_cache(struct se_task *task)
+{
+ struct se_cmd *cmd = TASK_CMD(task);
+ struct se_device *dev = cmd->se_dev;
+ struct fd_dev *fd_dev = dev->dev_ptr;
+ int immed = (cmd->t_task->t_task_cdb[1] & 0x2);
+ loff_t start, end;
+ int ret;
+
+ /*
+ * If the Immediate bit is set, queue up the GOOD response
+ * for this SYNCHRONIZE_CACHE op
+ */
+ if (immed)
+ transport_complete_sync_cache(cmd, 1);
+
+ /*
+ * Determine if we will be flushing the entire device.
+ */
+ if (cmd->t_task->t_task_lba == 0 && cmd->data_length == 0) {
+ start = 0;
+ end = LLONG_MAX;
+ } else {
+ start = cmd->t_task->t_task_lba * DEV_ATTRIB(dev)->block_size;
+ if (cmd->data_length)
+ end = start + cmd->data_length;
+ else
+ end = LLONG_MAX;
+ }
+
+ ret = vfs_fsync_range(fd_dev->fd_file, start, end, 1);
+ if (ret != 0)
+ printk(KERN_ERR "FILEIO: vfs_fsync_range() failed: %d\n", ret);
+
+ if (!immed)
+ transport_complete_sync_cache(cmd, ret == 0);
+}
+
+/*
+ * Tell TCM Core that we are capable of WriteCache emulation for
+ * an underlying struct se_device.
+ */
+static int fd_emulated_write_cache(struct se_device *dev)
+{
+ return 1;
+}
+
+static int fd_emulated_dpo(struct se_device *dev)
+{
+ return 0;
+}
+/*
+ * Tell TCM Core that we will be emulating Forced Unit Access (FUA) for WRITEs
+ * for TYPE_DISK.
+ */
+static int fd_emulated_fua_write(struct se_device *dev)
+{
+ return 1;
+}
+
+static int fd_emulated_fua_read(struct se_device *dev)
+{
+ return 0;
+}
+
+/*
+ * WRITE Force Unit Access (FUA) emulation on a per struct se_task
+ * LBA range basis..
+ */
+static void fd_emulate_write_fua(struct se_cmd *cmd, struct se_task *task)
+{
+ struct se_device *dev = cmd->se_dev;
+ struct fd_dev *fd_dev = dev->dev_ptr;
+ loff_t start = task->task_lba * DEV_ATTRIB(dev)->block_size;
+ loff_t end = start + task->task_size;
+ int ret;
+
+ DEBUG_FD_CACHE("FILEIO: FUA WRITE LBA: %llu, bytes: %u\n",
+ task->task_lba, task->task_size);
+
+ ret = vfs_fsync_range(fd_dev->fd_file, start, end, 1);
+ if (ret != 0)
+ printk(KERN_ERR "FILEIO: vfs_fsync_range() failed: %d\n", ret);
+}
+
+static int fd_do_task(struct se_task *task)
+{
+ struct se_cmd *cmd = task->task_se_cmd;
+ struct se_device *dev = cmd->se_dev;
+ int ret = 0;
+
+ /*
+ * Call vectorized fileio functions to map struct scatterlist
+ * physical memory addresses to struct iovec virtual memory.
+ */
+ if (task->task_data_direction == DMA_FROM_DEVICE) {
+ ret = fd_do_readv(task);
+ } else {
+ ret = fd_do_writev(task);
+
+ if (ret > 0 &&
+ DEV_ATTRIB(dev)->emulate_write_cache > 0 &&
+ DEV_ATTRIB(dev)->emulate_fua_write > 0 &&
+ T_TASK(cmd)->t_tasks_fua) {
+ /*
+ * We might need to be a bit smarter here
+ * and return some sense data to let the initiator
+ * know the FUA WRITE cache sync failed..?
+ */
+ fd_emulate_write_fua(cmd, task);
+ }
+
+ }
+
+ if (ret < 0)
+ return ret;
+ if (ret) {
+ task->task_scsi_status = GOOD;
+ transport_complete_task(task, 1);
+ }
+ return PYX_TRANSPORT_SENT_TO_TRANSPORT;
+}
+
+/* fd_free_task(): (Part of se_subsystem_api_t template)
+ *
+ *
+ */
+static void fd_free_task(struct se_task *task)
+{
+ struct fd_request *req = FILE_REQ(task);
+
+ kfree(req);
+}
+
+enum {
+ Opt_fd_dev_name, Opt_fd_dev_size, Opt_fd_buffered_io, Opt_err
+};
+
+static match_table_t tokens = {
+ {Opt_fd_dev_name, "fd_dev_name=%s"},
+ {Opt_fd_dev_size, "fd_dev_size=%s"},
+ {Opt_fd_buffered_io, "fd_buffered_id=%d"},
+ {Opt_err, NULL}
+};
+
+static ssize_t fd_set_configfs_dev_params(
+ struct se_hba *hba,
+ struct se_subsystem_dev *se_dev,
+ const char *page, ssize_t count)
+{
+ struct fd_dev *fd_dev = se_dev->se_dev_su_ptr;
+ char *orig, *ptr, *arg_p, *opts;
+ substring_t args[MAX_OPT_ARGS];
+ int ret = 0, arg, token;
+
+ opts = kstrdup(page, GFP_KERNEL);
+ if (!opts)
+ return -ENOMEM;
+
+ orig = opts;
+
+ while ((ptr = strsep(&opts, ",")) != NULL) {
+ if (!*ptr)
+ continue;
+
+ token = match_token(ptr, tokens, args);
+ switch (token) {
+ case Opt_fd_dev_name:
+ snprintf(fd_dev->fd_dev_name, FD_MAX_DEV_NAME,
+ "%s", match_strdup(&args[0]));
+ printk(KERN_INFO "FILEIO: Referencing Path: %s\n",
+ fd_dev->fd_dev_name);
+ fd_dev->fbd_flags |= FBDF_HAS_PATH;
+ break;
+ case Opt_fd_dev_size:
+ arg_p = match_strdup(&args[0]);
+ ret = strict_strtoull(arg_p, 0, &fd_dev->fd_dev_size);
+ if (ret < 0) {
+ printk(KERN_ERR "strict_strtoull() failed for"
+ " fd_dev_size=\n");
+ goto out;
+ }
+ printk(KERN_INFO "FILEIO: Referencing Size: %llu"
+ " bytes\n", fd_dev->fd_dev_size);
+ fd_dev->fbd_flags |= FBDF_HAS_SIZE;
+ break;
+ case Opt_fd_buffered_io:
+ match_int(args, &arg);
+ if (arg != 1) {
+ printk(KERN_ERR "bogus fd_buffered_io=%d value\n", arg);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ printk(KERN_INFO "FILEIO: Using buffered I/O"
+ " operations for struct fd_dev\n");
+
+ fd_dev->fbd_flags |= FDBD_USE_BUFFERED_IO;
+ break;
+ default:
+ break;
+ }
+ }
+
+out:
+ kfree(orig);
+ return (!ret) ? count : ret;
+}
+
+static ssize_t fd_check_configfs_dev_params(struct se_hba *hba, struct se_subsystem_dev *se_dev)
+{
+ struct fd_dev *fd_dev = (struct fd_dev *) se_dev->se_dev_su_ptr;
+
+ if (!(fd_dev->fbd_flags & FBDF_HAS_PATH)) {
+ printk(KERN_ERR "Missing fd_dev_name=\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static ssize_t fd_show_configfs_dev_params(
+ struct se_hba *hba,
+ struct se_subsystem_dev *se_dev,
+ char *b)
+{
+ struct fd_dev *fd_dev = se_dev->se_dev_su_ptr;
+ ssize_t bl = 0;
+
+ bl = sprintf(b + bl, "TCM FILEIO ID: %u", fd_dev->fd_dev_id);
+ bl += sprintf(b + bl, " File: %s Size: %llu Mode: %s\n",
+ fd_dev->fd_dev_name, fd_dev->fd_dev_size,
+ (fd_dev->fbd_flags & FDBD_USE_BUFFERED_IO) ?
+ "Buffered" : "Synchronous");
+ return bl;
+}
+
+/* fd_get_cdb(): (Part of se_subsystem_api_t template)
+ *
+ *
+ */
+static unsigned char *fd_get_cdb(struct se_task *task)
+{
+ struct fd_request *req = FILE_REQ(task);
+
+ return req->fd_scsi_cdb;
+}
+
+/* fd_get_device_rev(): (Part of se_subsystem_api_t template)
+ *
+ *
+ */
+static u32 fd_get_device_rev(struct se_device *dev)
+{
+ return SCSI_SPC_2; /* Returns SPC-3 in Initiator Data */
+}
+
+/* fd_get_device_type(): (Part of se_subsystem_api_t template)
+ *
+ *
+ */
+static u32 fd_get_device_type(struct se_device *dev)
+{
+ return TYPE_DISK;
+}
+
+static sector_t fd_get_blocks(struct se_device *dev)
+{
+ struct fd_dev *fd_dev = dev->dev_ptr;
+ unsigned long long blocks_long = div_u64(fd_dev->fd_dev_size,
+ DEV_ATTRIB(dev)->block_size);
+
+ return blocks_long;
+}
+
+static struct se_subsystem_api fileio_template = {
+ .name = "fileio",
+ .owner = THIS_MODULE,
+ .transport_type = TRANSPORT_PLUGIN_VHBA_PDEV,
+ .attach_hba = fd_attach_hba,
+ .detach_hba = fd_detach_hba,
+ .allocate_virtdevice = fd_allocate_virtdevice,
+ .create_virtdevice = fd_create_virtdevice,
+ .free_device = fd_free_device,
+ .dpo_emulated = fd_emulated_dpo,
+ .fua_write_emulated = fd_emulated_fua_write,
+ .fua_read_emulated = fd_emulated_fua_read,
+ .write_cache_emulated = fd_emulated_write_cache,
+ .alloc_task = fd_alloc_task,
+ .do_task = fd_do_task,
+ .do_sync_cache = fd_emulate_sync_cache,
+ .free_task = fd_free_task,
+ .check_configfs_dev_params = fd_check_configfs_dev_params,
+ .set_configfs_dev_params = fd_set_configfs_dev_params,
+ .show_configfs_dev_params = fd_show_configfs_dev_params,
+ .get_cdb = fd_get_cdb,
+ .get_device_rev = fd_get_device_rev,
+ .get_device_type = fd_get_device_type,
+ .get_blocks = fd_get_blocks,
+};
+
+static int __init fileio_module_init(void)
+{
+ return transport_subsystem_register(&fileio_template);
+}
+
+static void fileio_module_exit(void)
+{
+ transport_subsystem_release(&fileio_template);
+}
+
+MODULE_DESCRIPTION("TCM FILEIO subsystem plugin");
+MODULE_AUTHOR("nab@Linux-iSCSI.org");
+MODULE_LICENSE("GPL");
+
+module_init(fileio_module_init);
+module_exit(fileio_module_exit);
diff --git a/drivers/target/target_core_file.h b/drivers/target/target_core_file.h
new file mode 100644
index 0000000..ef4de2b
--- /dev/null
+++ b/drivers/target/target_core_file.h
@@ -0,0 +1,50 @@
+#ifndef TARGET_CORE_FILE_H
+#define TARGET_CORE_FILE_H
+
+#define FD_VERSION "4.0"
+
+#define FD_MAX_DEV_NAME 256
+/* Maximum queuedepth for the FILEIO HBA */
+#define FD_HBA_QUEUE_DEPTH 256
+#define FD_DEVICE_QUEUE_DEPTH 32
+#define FD_MAX_DEVICE_QUEUE_DEPTH 128
+#define FD_BLOCKSIZE 512
+#define FD_MAX_SECTORS 1024
+
+#define RRF_EMULATE_CDB 0x01
+#define RRF_GOT_LBA 0x02
+
+struct fd_request {
+ struct se_task fd_task;
+ /* SCSI CDB from iSCSI Command PDU */
+ unsigned char fd_scsi_cdb[TCM_MAX_COMMAND_SIZE];
+ /* FILEIO device */
+ struct fd_dev *fd_dev;
+} ____cacheline_aligned;
+
+#define FBDF_HAS_PATH 0x01
+#define FBDF_HAS_SIZE 0x02
+#define FDBD_USE_BUFFERED_IO 0x04
+
+struct fd_dev {
+ u32 fbd_flags;
+ unsigned char fd_dev_name[FD_MAX_DEV_NAME];
+ /* Unique Ramdisk Device ID in Ramdisk HBA */
+ u32 fd_dev_id;
+ /* Number of SG tables in sg_table_array */
+ u32 fd_table_count;
+ u32 fd_queue_depth;
+ u32 fd_block_size;
+ unsigned long long fd_dev_size;
+ struct file *fd_file;
+ /* FILEIO HBA device is connected to */
+ struct fd_host *fd_host;
+} ____cacheline_aligned;
+
+struct fd_host {
+ u32 fd_host_dev_id_count;
+ /* Unique FILEIO Host ID */
+ u32 fd_host_id;
+} ____cacheline_aligned;
+
+#endif /* TARGET_CORE_FILE_H */
diff --git a/drivers/target/target_core_hba.c b/drivers/target/target_core_hba.c
new file mode 100644
index 0000000..4bbe820
--- /dev/null
+++ b/drivers/target/target_core_hba.c
@@ -0,0 +1,185 @@
+/*******************************************************************************
+ * Filename: target_core_hba.c
+ *
+ * This file copntains the iSCSI HBA Transport related functions.
+ *
+ * Copyright (c) 2003, 2004, 2005 PyX Technologies, Inc.
+ * Copyright (c) 2005, 2006, 2007 SBE, Inc.
+ * Copyright (c) 2007-2010 Rising Tide Systems
+ * Copyright (c) 2008-2010 Linux-iSCSI.org
+ *
+ * Nicholas A. Bellinger <nab@kernel.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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ ******************************************************************************/
+
+#include <linux/net.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/smp_lock.h>
+#include <linux/in.h>
+#include <net/sock.h>
+#include <net/tcp.h>
+
+#include <target/target_core_base.h>
+#include <target/target_core_device.h>
+#include <target/target_core_device.h>
+#include <target/target_core_tpg.h>
+#include <target/target_core_transport.h>
+
+#include "target_core_hba.h"
+
+static LIST_HEAD(subsystem_list);
+static DEFINE_MUTEX(subsystem_mutex);
+
+int transport_subsystem_register(struct se_subsystem_api *sub_api)
+{
+ struct se_subsystem_api *s;
+
+ INIT_LIST_HEAD(&sub_api->sub_api_list);
+
+ mutex_lock(&subsystem_mutex);
+ list_for_each_entry(s, &subsystem_list, sub_api_list) {
+ if (!(strcmp(s->name, sub_api->name))) {
+ printk(KERN_ERR "%p is already registered with"
+ " duplicate name %s, unable to process"
+ " request\n", s, s->name);
+ mutex_unlock(&subsystem_mutex);
+ return -EEXIST;
+ }
+ }
+ list_add_tail(&sub_api->sub_api_list, &subsystem_list);
+ mutex_unlock(&subsystem_mutex);
+
+ printk(KERN_INFO "TCM: Registered subsystem plugin: %s struct module:"
+ " %p\n", sub_api->name, sub_api->owner);
+ return 0;
+}
+EXPORT_SYMBOL(transport_subsystem_register);
+
+void transport_subsystem_release(struct se_subsystem_api *sub_api)
+{
+ mutex_lock(&subsystem_mutex);
+ list_del(&sub_api->sub_api_list);
+ mutex_unlock(&subsystem_mutex);
+}
+EXPORT_SYMBOL(transport_subsystem_release);
+
+static struct se_subsystem_api *core_get_backend(const char *sub_name)
+{
+ struct se_subsystem_api *s;
+
+ mutex_lock(&subsystem_mutex);
+ list_for_each_entry(s, &subsystem_list, sub_api_list) {
+ if (!strcmp(s->name, sub_name))
+ goto found;
+ }
+ mutex_unlock(&subsystem_mutex);
+ return NULL;
+found:
+ if (s->owner && !try_module_get(s->owner))
+ s = NULL;
+ mutex_unlock(&subsystem_mutex);
+ return s;
+}
+
+struct se_hba *
+core_alloc_hba(const char *plugin_name, u32 plugin_dep_id, u32 hba_flags)
+{
+ struct se_hba *hba;
+ int ret = 0;
+
+ hba = kzalloc(sizeof(*hba), GFP_KERNEL);
+ if (!hba) {
+ printk(KERN_ERR "Unable to allocate struct se_hba\n");
+ return ERR_PTR(-ENOMEM);
+ }
+
+ INIT_LIST_HEAD(&hba->hba_dev_list);
+ spin_lock_init(&hba->device_lock);
+ spin_lock_init(&hba->hba_queue_lock);
+ mutex_init(&hba->hba_access_mutex);
+
+ hba->hba_index = scsi_get_new_index(SCSI_INST_INDEX);
+ hba->hba_flags |= hba_flags;
+
+ atomic_set(&hba->max_queue_depth, 0);
+ atomic_set(&hba->left_queue_depth, 0);
+
+ hba->transport = core_get_backend(plugin_name);
+ if (!hba->transport) {
+ ret = -EINVAL;
+ goto out_free_hba;
+ }
+
+ ret = hba->transport->attach_hba(hba, plugin_dep_id);
+ if (ret < 0)
+ goto out_module_put;
+
+ spin_lock(&se_global->hba_lock);
+ hba->hba_id = se_global->g_hba_id_counter++;
+ list_add_tail(&hba->hba_list, &se_global->g_hba_list);
+ spin_unlock(&se_global->hba_lock);
+
+ printk(KERN_INFO "CORE_HBA[%d] - Attached HBA to Generic Target"
+ " Core\n", hba->hba_id);
+
+ return hba;
+
+out_module_put:
+ if (hba->transport->owner)
+ module_put(hba->transport->owner);
+ hba->transport = NULL;
+out_free_hba:
+ kfree(hba);
+ return ERR_PTR(ret);
+}
+
+int
+core_delete_hba(struct se_hba *hba)
+{
+ struct se_device *dev, *dev_tmp;
+
+ spin_lock(&hba->device_lock);
+ list_for_each_entry_safe(dev, dev_tmp, &hba->hba_dev_list, dev_list) {
+
+ se_clear_dev_ports(dev);
+ spin_unlock(&hba->device_lock);
+
+ se_release_device_for_hba(dev);
+
+ spin_lock(&hba->device_lock);
+ }
+ spin_unlock(&hba->device_lock);
+
+ hba->transport->detach_hba(hba);
+
+ spin_lock(&se_global->hba_lock);
+ list_del(&hba->hba_list);
+ spin_unlock(&se_global->hba_lock);
+
+ printk(KERN_INFO "CORE_HBA[%d] - Detached HBA from Generic Target"
+ " Core\n", hba->hba_id);
+
+ if (hba->transport->owner)
+ module_put(hba->transport->owner);
+
+ hba->transport = NULL;
+ kfree(hba);
+ return 0;
+}
diff --git a/drivers/target/target_core_hba.h b/drivers/target/target_core_hba.h
new file mode 100644
index 0000000..bb0fea5
--- /dev/null
+++ b/drivers/target/target_core_hba.h
@@ -0,0 +1,7 @@
+#ifndef TARGET_CORE_HBA_H
+#define TARGET_CORE_HBA_H
+
+extern struct se_hba *core_alloc_hba(const char *, u32, u32);
+extern int core_delete_hba(struct se_hba *);
+
+#endif /* TARGET_CORE_HBA_H */
diff --git a/drivers/target/target_core_iblock.c b/drivers/target/target_core_iblock.c
new file mode 100644
index 0000000..c6e0d75
--- /dev/null
+++ b/drivers/target/target_core_iblock.c
@@ -0,0 +1,808 @@
+/*******************************************************************************
+ * Filename: target_core_iblock.c
+ *
+ * This file contains the Storage Engine <-> Linux BlockIO transport
+ * specific functions.
+ *
+ * Copyright (c) 2003, 2004, 2005 PyX Technologies, Inc.
+ * Copyright (c) 2005, 2006, 2007 SBE, Inc.
+ * Copyright (c) 2007-2010 Rising Tide Systems
+ * Copyright (c) 2008-2010 Linux-iSCSI.org
+ *
+ * Nicholas A. Bellinger <nab@kernel.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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ ******************************************************************************/
+
+#include <linux/version.h>
+#include <linux/string.h>
+#include <linux/parser.h>
+#include <linux/timer.h>
+#include <linux/fs.h>
+#include <linux/blkdev.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/smp_lock.h>
+#include <linux/bio.h>
+#include <linux/genhd.h>
+#include <linux/file.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_host.h>
+
+#include <target/target_core_base.h>
+#include <target/target_core_device.h>
+#include <target/target_core_transport.h>
+
+#include "target_core_iblock.h"
+
+#if 0
+#define DEBUG_IBLOCK(x...) printk(x)
+#else
+#define DEBUG_IBLOCK(x...)
+#endif
+
+static struct se_subsystem_api iblock_template;
+
+static void iblock_bio_done(struct bio *, int);
+
+/* iblock_attach_hba(): (Part of se_subsystem_api_t template)
+ *
+ *
+ */
+static int iblock_attach_hba(struct se_hba *hba, u32 host_id)
+{
+ struct iblock_hba *ib_host;
+
+ ib_host = kzalloc(sizeof(struct iblock_hba), GFP_KERNEL);
+ if (!(ib_host)) {
+ printk(KERN_ERR "Unable to allocate memory for"
+ " struct iblock_hba\n");
+ return -ENOMEM;
+ }
+
+ ib_host->iblock_host_id = host_id;
+
+ atomic_set(&hba->left_queue_depth, IBLOCK_HBA_QUEUE_DEPTH);
+ atomic_set(&hba->max_queue_depth, IBLOCK_HBA_QUEUE_DEPTH);
+ hba->hba_ptr = (void *) ib_host;
+
+ printk(KERN_INFO "CORE_HBA[%d] - TCM iBlock HBA Driver %s on"
+ " Generic Target Core Stack %s\n", hba->hba_id,
+ IBLOCK_VERSION, TARGET_CORE_MOD_VERSION);
+
+ printk(KERN_INFO "CORE_HBA[%d] - Attached iBlock HBA: %u to Generic"
+ " Target Core TCQ Depth: %d\n", hba->hba_id,
+ ib_host->iblock_host_id, atomic_read(&hba->max_queue_depth));
+
+ return 0;
+}
+
+static void iblock_detach_hba(struct se_hba *hba)
+{
+ struct iblock_hba *ib_host = hba->hba_ptr;
+
+ printk(KERN_INFO "CORE_HBA[%d] - Detached iBlock HBA: %u from Generic"
+ " Target Core\n", hba->hba_id, ib_host->iblock_host_id);
+
+ kfree(ib_host);
+ hba->hba_ptr = NULL;
+}
+
+static void *iblock_allocate_virtdevice(struct se_hba *hba, const char *name)
+{
+ struct iblock_dev *ib_dev = NULL;
+ struct iblock_hba *ib_host = hba->hba_ptr;
+
+ ib_dev = kzalloc(sizeof(struct iblock_dev), GFP_KERNEL);
+ if (!(ib_dev)) {
+ printk(KERN_ERR "Unable to allocate struct iblock_dev\n");
+ return NULL;
+ }
+ ib_dev->ibd_host = ib_host;
+
+ printk(KERN_INFO "IBLOCK: Allocated ib_dev for %s\n", name);
+
+ return ib_dev;
+}
+
+static struct se_device *iblock_create_virtdevice(
+ struct se_hba *hba,
+ struct se_subsystem_dev *se_dev,
+ void *p)
+{
+ struct iblock_dev *ib_dev = p;
+ struct se_device *dev;
+ struct se_dev_limits dev_limits;
+ struct block_device *bd = NULL;
+ struct request_queue *q;
+ struct queue_limits *limits;
+ u32 dev_flags = 0;
+
+ if (!(ib_dev)) {
+ printk(KERN_ERR "Unable to locate struct iblock_dev parameter\n");
+ return 0;
+ }
+ memset(&dev_limits, 0, sizeof(struct se_dev_limits));
+ /*
+ * These settings need to be made tunable..
+ */
+ ib_dev->ibd_bio_set = bioset_create(32, 64);
+ if (!(ib_dev->ibd_bio_set)) {
+ printk(KERN_ERR "IBLOCK: Unable to create bioset()\n");
+ return 0;
+ }
+ printk(KERN_INFO "IBLOCK: Created bio_set()\n");
+ /*
+ * iblock_check_configfs_dev_params() ensures that ib_dev->ibd_udev_path
+ * must already have been set in order for echo 1 > $HBA/$DEV/enable to run.
+ */
+ printk(KERN_INFO "IBLOCK: Claiming struct block_device: %s\n",
+ ib_dev->ibd_udev_path);
+
+ bd = blkdev_get_by_path(ib_dev->ibd_udev_path,
+ FMODE_WRITE|FMODE_READ|FMODE_EXCL, ib_dev);
+ if (!(bd))
+ goto failed;
+ /*
+ * Setup the local scope queue_limits from struct request_queue->limits
+ * to pass into transport_add_device_to_core_hba() as struct se_dev_limits.
+ */
+ q = bdev_get_queue(bd);
+ limits = &dev_limits.limits;
+ limits->logical_block_size = bdev_logical_block_size(bd);
+ limits->max_hw_sectors = queue_max_hw_sectors(q);
+ limits->max_sectors = queue_max_sectors(q);
+ dev_limits.hw_queue_depth = IBLOCK_MAX_DEVICE_QUEUE_DEPTH;
+ dev_limits.queue_depth = IBLOCK_DEVICE_QUEUE_DEPTH;
+
+ ib_dev->ibd_major = MAJOR(bd->bd_dev);
+ ib_dev->ibd_minor = MINOR(bd->bd_dev);
+ ib_dev->ibd_bd = bd;
+
+ dev = transport_add_device_to_core_hba(hba,
+ &iblock_template, se_dev, dev_flags, (void *)ib_dev,
+ &dev_limits, "IBLOCK", IBLOCK_VERSION);
+ if (!(dev))
+ goto failed;
+
+ ib_dev->ibd_depth = dev->queue_depth;
+
+ /*
+ * Check if the underlying struct block_device request_queue supports
+ * the QUEUE_FLAG_DISCARD bit for UNMAP/WRITE_SAME in SCSI + TRIM
+ * in ATA and we need to set TPE=1
+ */
+ if (blk_queue_discard(bdev_get_queue(bd))) {
+ struct request_queue *q = bdev_get_queue(bd);
+
+ DEV_ATTRIB(dev)->max_unmap_lba_count =
+ q->limits.max_discard_sectors;
+ /*
+ * Currently hardcoded to 1 in Linux/SCSI code..
+ */
+ DEV_ATTRIB(dev)->max_unmap_block_desc_count = 1;
+ DEV_ATTRIB(dev)->unmap_granularity =
+ q->limits.discard_granularity;
+ DEV_ATTRIB(dev)->unmap_granularity_alignment =
+ q->limits.discard_alignment;
+
+ printk(KERN_INFO "IBLOCK: BLOCK Discard support available,"
+ " disabled by default\n");
+ }
+
+ return dev;
+
+failed:
+ if (ib_dev->ibd_bio_set) {
+ bioset_free(ib_dev->ibd_bio_set);
+ ib_dev->ibd_bio_set = NULL;
+ }
+ ib_dev->ibd_bd = NULL;
+ ib_dev->ibd_major = 0;
+ ib_dev->ibd_minor = 0;
+ return NULL;
+}
+
+static void iblock_free_device(void *p)
+{
+ struct iblock_dev *ib_dev = p;
+
+ blkdev_put(ib_dev->ibd_bd, FMODE_WRITE|FMODE_READ|FMODE_EXCL);
+ bioset_free(ib_dev->ibd_bio_set);
+ kfree(ib_dev);
+}
+
+static inline struct iblock_req *IBLOCK_REQ(struct se_task *task)
+{
+ return container_of(task, struct iblock_req, ib_task);
+}
+
+static struct se_task *
+iblock_alloc_task(struct se_cmd *cmd)
+{
+ struct iblock_req *ib_req;
+
+ ib_req = kzalloc(sizeof(struct iblock_req), GFP_KERNEL);
+ if (!(ib_req)) {
+ printk(KERN_ERR "Unable to allocate memory for struct iblock_req\n");
+ return NULL;
+ }
+
+ ib_req->ib_dev = SE_DEV(cmd)->dev_ptr;
+ atomic_set(&ib_req->ib_bio_cnt, 0);
+ return &ib_req->ib_task;
+}
+
+static unsigned long long iblock_emulate_read_cap_with_block_size(
+ struct se_device *dev,
+ struct block_device *bd,
+ struct request_queue *q)
+{
+ unsigned long long blocks_long = (div_u64(i_size_read(bd->bd_inode),
+ bdev_logical_block_size(bd)) - 1);
+ u32 block_size = bdev_logical_block_size(bd);
+
+ if (block_size == DEV_ATTRIB(dev)->block_size)
+ return blocks_long;
+
+ switch (block_size) {
+ case 4096:
+ switch (DEV_ATTRIB(dev)->block_size) {
+ case 2048:
+ blocks_long <<= 1;
+ break;
+ case 1024:
+ blocks_long <<= 2;
+ break;
+ case 512:
+ blocks_long <<= 3;
+ default:
+ break;
+ }
+ break;
+ case 2048:
+ switch (DEV_ATTRIB(dev)->block_size) {
+ case 4096:
+ blocks_long >>= 1;
+ break;
+ case 1024:
+ blocks_long <<= 1;
+ break;
+ case 512:
+ blocks_long <<= 2;
+ break;
+ default:
+ break;
+ }
+ break;
+ case 1024:
+ switch (DEV_ATTRIB(dev)->block_size) {
+ case 4096:
+ blocks_long >>= 2;
+ break;
+ case 2048:
+ blocks_long >>= 1;
+ break;
+ case 512:
+ blocks_long <<= 1;
+ break;
+ default:
+ break;
+ }
+ break;
+ case 512:
+ switch (DEV_ATTRIB(dev)->block_size) {
+ case 4096:
+ blocks_long >>= 3;
+ break;
+ case 2048:
+ blocks_long >>= 2;
+ break;
+ case 1024:
+ blocks_long >>= 1;
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+
+ return blocks_long;
+}
+
+/*
+ * Emulate SYCHRONIZE_CACHE_*
+ */
+static void iblock_emulate_sync_cache(struct se_task *task)
+{
+ struct se_cmd *cmd = TASK_CMD(task);
+ struct iblock_dev *ib_dev = cmd->se_dev->dev_ptr;
+ int immed = (T_TASK(cmd)->t_task_cdb[1] & 0x2);
+ sector_t error_sector;
+ int ret;
+
+ /*
+ * If the Immediate bit is set, queue up the GOOD response
+ * for this SYNCHRONIZE_CACHE op
+ */
+ if (immed)
+ transport_complete_sync_cache(cmd, 1);
+
+ /*
+ * blkdev_issue_flush() does not support a specifying a range, so
+ * we have to flush the entire cache.
+ */
+ ret = blkdev_issue_flush(ib_dev->ibd_bd, GFP_KERNEL, &error_sector);
+ if (ret != 0) {
+ printk(KERN_ERR "IBLOCK: block_issue_flush() failed: %d "
+ " error_sector: %llu\n", ret,
+ (unsigned long long)error_sector);
+ }
+
+ if (!immed)
+ transport_complete_sync_cache(cmd, ret == 0);
+}
+
+/*
+ * Tell TCM Core that we are capable of WriteCache emulation for
+ * an underlying struct se_device.
+ */
+static int iblock_emulated_write_cache(struct se_device *dev)
+{
+ return 1;
+}
+
+static int iblock_emulated_dpo(struct se_device *dev)
+{
+ return 0;
+}
+
+/*
+ * Tell TCM Core that we will be emulating Forced Unit Access (FUA) for WRITEs
+ * for TYPE_DISK.
+ */
+static int iblock_emulated_fua_write(struct se_device *dev)
+{
+ return 1;
+}
+
+static int iblock_emulated_fua_read(struct se_device *dev)
+{
+ return 0;
+}
+
+static int iblock_do_task(struct se_task *task)
+{
+ struct se_device *dev = task->task_se_cmd->se_dev;
+ struct iblock_req *req = IBLOCK_REQ(task);
+ struct iblock_dev *ibd = (struct iblock_dev *)req->ib_dev;
+ struct request_queue *q = bdev_get_queue(ibd->ibd_bd);
+ struct bio *bio = req->ib_bio, *nbio = NULL;
+ int rw;
+
+ if (task->task_data_direction == DMA_TO_DEVICE) {
+ /*
+ * Force data to disk if we pretend to not have a volatile
+ * write cache, or the initiator set the Force Unit Access bit.
+ */
+ if (DEV_ATTRIB(dev)->emulate_write_cache == 0 ||
+ (DEV_ATTRIB(dev)->emulate_fua_write > 0 &&
+ T_TASK(task->task_se_cmd)->t_tasks_fua))
+ rw = WRITE_FUA;
+ else
+ rw = WRITE;
+ } else {
+ rw = READ;
+ }
+
+ while (bio) {
+ nbio = bio->bi_next;
+ bio->bi_next = NULL;
+ DEBUG_IBLOCK("Calling submit_bio() task: %p bio: %p"
+ " bio->bi_sector: %llu\n", task, bio, bio->bi_sector);
+
+ submit_bio(rw, bio);
+ bio = nbio;
+ }
+
+ if (q->unplug_fn)
+ q->unplug_fn(q);
+ return PYX_TRANSPORT_SENT_TO_TRANSPORT;
+}
+
+static int iblock_do_discard(struct se_device *dev, sector_t lba, u32 range)
+{
+ struct iblock_dev *ibd = dev->dev_ptr;
+ struct block_device *bd = ibd->ibd_bd;
+ int barrier = 0;
+
+ return blkdev_issue_discard(bd, lba, range, GFP_KERNEL, barrier);
+}
+
+static void iblock_free_task(struct se_task *task)
+{
+ struct iblock_req *req = IBLOCK_REQ(task);
+ struct bio *bio, *hbio = req->ib_bio;
+ /*
+ * We only release the bio(s) here if iblock_bio_done() has not called
+ * bio_put() -> iblock_bio_destructor().
+ */
+ while (hbio != NULL) {
+ bio = hbio;
+ hbio = hbio->bi_next;
+ bio->bi_next = NULL;
+ bio_put(bio);
+ }
+
+ kfree(req);
+}
+
+enum {
+ Opt_udev_path, Opt_force, Opt_err
+};
+
+static match_table_t tokens = {
+ {Opt_udev_path, "udev_path=%s"},
+ {Opt_force, "force=%d"},
+ {Opt_err, NULL}
+};
+
+static ssize_t iblock_set_configfs_dev_params(struct se_hba *hba,
+ struct se_subsystem_dev *se_dev,
+ const char *page, ssize_t count)
+{
+ struct iblock_dev *ib_dev = se_dev->se_dev_su_ptr;
+ char *orig, *ptr, *opts;
+ substring_t args[MAX_OPT_ARGS];
+ int ret = 0, arg, token;
+
+ opts = kstrdup(page, GFP_KERNEL);
+ if (!opts)
+ return -ENOMEM;
+
+ orig = opts;
+
+ while ((ptr = strsep(&opts, ",")) != NULL) {
+ if (!*ptr)
+ continue;
+
+ token = match_token(ptr, tokens, args);
+ switch (token) {
+ case Opt_udev_path:
+ if (ib_dev->ibd_bd) {
+ printk(KERN_ERR "Unable to set udev_path= while"
+ " ib_dev->ibd_bd exists\n");
+ ret = -EEXIST;
+ goto out;
+ }
+
+ ret = snprintf(ib_dev->ibd_udev_path, SE_UDEV_PATH_LEN,
+ "%s", match_strdup(&args[0]));
+ printk(KERN_INFO "IBLOCK: Referencing UDEV path: %s\n",
+ ib_dev->ibd_udev_path);
+ ib_dev->ibd_flags |= IBDF_HAS_UDEV_PATH;
+ break;
+ case Opt_force:
+ match_int(args, &arg);
+ ib_dev->ibd_force = arg;
+ printk(KERN_INFO "IBLOCK: Set force=%d\n",
+ ib_dev->ibd_force);
+ break;
+ default:
+ break;
+ }
+ }
+
+out:
+ kfree(orig);
+ return (!ret) ? count : ret;
+}
+
+static ssize_t iblock_check_configfs_dev_params(
+ struct se_hba *hba,
+ struct se_subsystem_dev *se_dev)
+{
+ struct iblock_dev *ibd = se_dev->se_dev_su_ptr;
+
+ if (!(ibd->ibd_flags & IBDF_HAS_UDEV_PATH)) {
+ printk(KERN_ERR "Missing udev_path= parameters for IBLOCK\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static ssize_t iblock_show_configfs_dev_params(
+ struct se_hba *hba,
+ struct se_subsystem_dev *se_dev,
+ char *b)
+{
+ struct iblock_dev *ibd = se_dev->se_dev_su_ptr;
+ struct block_device *bd = ibd->ibd_bd;
+ char buf[BDEVNAME_SIZE];
+ ssize_t bl = 0;
+
+ if (bd)
+ bl += sprintf(b + bl, "iBlock device: %s",
+ bdevname(bd, buf));
+ if (ibd->ibd_flags & IBDF_HAS_UDEV_PATH) {
+ bl += sprintf(b + bl, " UDEV PATH: %s\n",
+ ibd->ibd_udev_path);
+ } else
+ bl += sprintf(b + bl, "\n");
+
+ bl += sprintf(b + bl, " ");
+ if (bd) {
+ bl += sprintf(b + bl, "Major: %d Minor: %d %s\n",
+ ibd->ibd_major, ibd->ibd_minor, (!bd->bd_contains) ?
+ "" : (bd->bd_holder == (struct iblock_dev *)ibd) ?
+ "CLAIMED: IBLOCK" : "CLAIMED: OS");
+ } else {
+ bl += sprintf(b + bl, "Major: %d Minor: %d\n",
+ ibd->ibd_major, ibd->ibd_minor);
+ }
+
+ return bl;
+}
+
+static void iblock_bio_destructor(struct bio *bio)
+{
+ struct se_task *task = bio->bi_private;
+ struct iblock_dev *ib_dev = task->se_dev->dev_ptr;
+
+ bio_free(bio, ib_dev->ibd_bio_set);
+}
+
+static struct bio *iblock_get_bio(
+ struct se_task *task,
+ struct iblock_req *ib_req,
+ struct iblock_dev *ib_dev,
+ int *ret,
+ sector_t lba,
+ u32 sg_num)
+{
+ struct bio *bio;
+
+ bio = bio_alloc_bioset(GFP_NOIO, sg_num, ib_dev->ibd_bio_set);
+ if (!(bio)) {
+ printk(KERN_ERR "Unable to allocate memory for bio\n");
+ *ret = PYX_TRANSPORT_OUT_OF_MEMORY_RESOURCES;
+ return NULL;
+ }
+
+ DEBUG_IBLOCK("Allocated bio: %p task_sg_num: %u using ibd_bio_set:"
+ " %p\n", bio, task->task_sg_num, ib_dev->ibd_bio_set);
+ DEBUG_IBLOCK("Allocated bio: %p task_size: %u\n", bio, task->task_size);
+
+ bio->bi_bdev = ib_dev->ibd_bd;
+ bio->bi_private = (void *) task;
+ bio->bi_destructor = iblock_bio_destructor;
+ bio->bi_end_io = &iblock_bio_done;
+ bio->bi_sector = lba;
+ atomic_inc(&ib_req->ib_bio_cnt);
+
+ DEBUG_IBLOCK("Set bio->bi_sector: %llu\n", bio->bi_sector);
+ DEBUG_IBLOCK("Set ib_req->ib_bio_cnt: %d\n",
+ atomic_read(&ib_req->ib_bio_cnt));
+ return bio;
+}
+
+static int iblock_map_task_SG(struct se_task *task)
+{
+ struct se_cmd *cmd = task->task_se_cmd;
+ struct se_device *dev = SE_DEV(cmd);
+ struct iblock_dev *ib_dev = task->se_dev->dev_ptr;
+ struct iblock_req *ib_req = IBLOCK_REQ(task);
+ struct bio *bio = NULL, *hbio = NULL, *tbio = NULL;
+ struct scatterlist *sg;
+ int ret = 0;
+ u32 i, sg_num = task->task_sg_num;
+ sector_t block_lba;
+ /*
+ * Do starting conversion up from non 512-byte blocksize with
+ * struct se_task SCSI blocksize into Linux/Block 512 units for BIO.
+ */
+ if (DEV_ATTRIB(dev)->block_size == 4096)
+ block_lba = (task->task_lba << 3);
+ else if (DEV_ATTRIB(dev)->block_size == 2048)
+ block_lba = (task->task_lba << 2);
+ else if (DEV_ATTRIB(dev)->block_size == 1024)
+ block_lba = (task->task_lba << 1);
+ else if (DEV_ATTRIB(dev)->block_size == 512)
+ block_lba = task->task_lba;
+ else {
+ printk(KERN_ERR "Unsupported SCSI -> BLOCK LBA conversion:"
+ " %u\n", DEV_ATTRIB(dev)->block_size);
+ return PYX_TRANSPORT_LU_COMM_FAILURE;
+ }
+
+ bio = iblock_get_bio(task, ib_req, ib_dev, &ret, block_lba, sg_num);
+ if (!(bio))
+ return ret;
+
+ ib_req->ib_bio = bio;
+ hbio = tbio = bio;
+ /*
+ * Use fs/bio.c:bio_add_pages() to setup the bio_vec maplist
+ * from TCM struct se_mem -> task->task_sg -> struct scatterlist memory.
+ */
+ for_each_sg(task->task_sg, sg, task->task_sg_num, i) {
+ DEBUG_IBLOCK("task: %p bio: %p Calling bio_add_page(): page:"
+ " %p len: %u offset: %u\n", task, bio, sg_page(sg),
+ sg->length, sg->offset);
+again:
+ ret = bio_add_page(bio, sg_page(sg), sg->length, sg->offset);
+ if (ret != sg->length) {
+
+ DEBUG_IBLOCK("*** Set bio->bi_sector: %llu\n",
+ bio->bi_sector);
+ DEBUG_IBLOCK("** task->task_size: %u\n",
+ task->task_size);
+ DEBUG_IBLOCK("*** bio->bi_max_vecs: %u\n",
+ bio->bi_max_vecs);
+ DEBUG_IBLOCK("*** bio->bi_vcnt: %u\n",
+ bio->bi_vcnt);
+
+ bio = iblock_get_bio(task, ib_req, ib_dev, &ret,
+ block_lba, sg_num);
+ if (!(bio))
+ goto fail;
+
+ tbio = tbio->bi_next = bio;
+ DEBUG_IBLOCK("-----------------> Added +1 bio: %p to"
+ " list, Going to again\n", bio);
+ goto again;
+ }
+ /* Always in 512 byte units for Linux/Block */
+ block_lba += sg->length >> IBLOCK_LBA_SHIFT;
+ sg_num--;
+ DEBUG_IBLOCK("task: %p bio-add_page() passed!, decremented"
+ " sg_num to %u\n", task, sg_num);
+ DEBUG_IBLOCK("task: %p bio_add_page() passed!, increased lba"
+ " to %llu\n", task, block_lba);
+ DEBUG_IBLOCK("task: %p bio_add_page() passed!, bio->bi_vcnt:"
+ " %u\n", task, bio->bi_vcnt);
+ }
+
+ return 0;
+fail:
+ while (hbio) {
+ bio = hbio;
+ hbio = hbio->bi_next;
+ bio->bi_next = NULL;
+ bio_put(bio);
+ }
+ return ret;
+}
+
+static unsigned char *iblock_get_cdb(struct se_task *task)
+{
+ return IBLOCK_REQ(task)->ib_scsi_cdb;
+}
+
+static u32 iblock_get_device_rev(struct se_device *dev)
+{
+ return SCSI_SPC_2; /* Returns SPC-3 in Initiator Data */
+}
+
+static u32 iblock_get_device_type(struct se_device *dev)
+{
+ return TYPE_DISK;
+}
+
+static sector_t iblock_get_blocks(struct se_device *dev)
+{
+ struct iblock_dev *ibd = dev->dev_ptr;
+ struct block_device *bd = ibd->ibd_bd;
+ struct request_queue *q = bdev_get_queue(bd);
+
+ return iblock_emulate_read_cap_with_block_size(dev, bd, q);
+}
+
+static void iblock_bio_done(struct bio *bio, int err)
+{
+ struct se_task *task = bio->bi_private;
+ struct iblock_req *ibr = IBLOCK_REQ(task);
+ /*
+ * Set -EIO if !BIO_UPTODATE and the passed is still err=0
+ */
+ if (!(test_bit(BIO_UPTODATE, &bio->bi_flags)) && !(err))
+ err = -EIO;
+
+ if (err != 0) {
+ printk(KERN_ERR "test_bit(BIO_UPTODATE) failed for bio: %p,"
+ " err: %d\n", bio, err);
+ /*
+ * Bump the ib_bio_err_cnt and release bio.
+ */
+ atomic_inc(&ibr->ib_bio_err_cnt);
+ smp_mb__after_atomic_inc();
+ bio_put(bio);
+ /*
+ * Wait to complete the task until the last bio as completed.
+ */
+ if (!(atomic_dec_and_test(&ibr->ib_bio_cnt)))
+ return;
+
+ ibr->ib_bio = NULL;
+ transport_complete_task(task, 0);
+ return;
+ }
+ DEBUG_IBLOCK("done[%p] bio: %p task_lba: %llu bio_lba: %llu err=%d\n",
+ task, bio, task->task_lba, bio->bi_sector, err);
+ /*
+ * bio_put() will call iblock_bio_destructor() to release the bio back
+ * to ibr->ib_bio_set.
+ */
+ bio_put(bio);
+ /*
+ * Wait to complete the task until the last bio as completed.
+ */
+ if (!(atomic_dec_and_test(&ibr->ib_bio_cnt)))
+ return;
+ /*
+ * Return GOOD status for task if zero ib_bio_err_cnt exists.
+ */
+ ibr->ib_bio = NULL;
+ transport_complete_task(task, (!atomic_read(&ibr->ib_bio_err_cnt)));
+}
+
+static struct se_subsystem_api iblock_template = {
+ .name = "iblock",
+ .owner = THIS_MODULE,
+ .transport_type = TRANSPORT_PLUGIN_VHBA_PDEV,
+ .map_task_SG = iblock_map_task_SG,
+ .attach_hba = iblock_attach_hba,
+ .detach_hba = iblock_detach_hba,
+ .allocate_virtdevice = iblock_allocate_virtdevice,
+ .create_virtdevice = iblock_create_virtdevice,
+ .free_device = iblock_free_device,
+ .dpo_emulated = iblock_emulated_dpo,
+ .fua_write_emulated = iblock_emulated_fua_write,
+ .fua_read_emulated = iblock_emulated_fua_read,
+ .write_cache_emulated = iblock_emulated_write_cache,
+ .alloc_task = iblock_alloc_task,
+ .do_task = iblock_do_task,
+ .do_discard = iblock_do_discard,
+ .do_sync_cache = iblock_emulate_sync_cache,
+ .free_task = iblock_free_task,
+ .check_configfs_dev_params = iblock_check_configfs_dev_params,
+ .set_configfs_dev_params = iblock_set_configfs_dev_params,
+ .show_configfs_dev_params = iblock_show_configfs_dev_params,
+ .get_cdb = iblock_get_cdb,
+ .get_device_rev = iblock_get_device_rev,
+ .get_device_type = iblock_get_device_type,
+ .get_blocks = iblock_get_blocks,
+};
+
+static int __init iblock_module_init(void)
+{
+ return transport_subsystem_register(&iblock_template);
+}
+
+static void iblock_module_exit(void)
+{
+ transport_subsystem_release(&iblock_template);
+}
+
+MODULE_DESCRIPTION("TCM IBLOCK subsystem plugin");
+MODULE_AUTHOR("nab@Linux-iSCSI.org");
+MODULE_LICENSE("GPL");
+
+module_init(iblock_module_init);
+module_exit(iblock_module_exit);
diff --git a/drivers/target/target_core_iblock.h b/drivers/target/target_core_iblock.h
new file mode 100644
index 0000000..64c1f4d
--- /dev/null
+++ b/drivers/target/target_core_iblock.h
@@ -0,0 +1,40 @@
+#ifndef TARGET_CORE_IBLOCK_H
+#define TARGET_CORE_IBLOCK_H
+
+#define IBLOCK_VERSION "4.0"
+
+#define IBLOCK_HBA_QUEUE_DEPTH 512
+#define IBLOCK_DEVICE_QUEUE_DEPTH 32
+#define IBLOCK_MAX_DEVICE_QUEUE_DEPTH 128
+#define IBLOCK_MAX_CDBS 16
+#define IBLOCK_LBA_SHIFT 9
+
+struct iblock_req {
+ struct se_task ib_task;
+ unsigned char ib_scsi_cdb[TCM_MAX_COMMAND_SIZE];
+ atomic_t ib_bio_cnt;
+ atomic_t ib_bio_err_cnt;
+ struct bio *ib_bio;
+ struct iblock_dev *ib_dev;
+} ____cacheline_aligned;
+
+#define IBDF_HAS_UDEV_PATH 0x01
+#define IBDF_HAS_FORCE 0x02
+
+struct iblock_dev {
+ unsigned char ibd_udev_path[SE_UDEV_PATH_LEN];
+ int ibd_force;
+ int ibd_major;
+ int ibd_minor;
+ u32 ibd_depth;
+ u32 ibd_flags;
+ struct bio_set *ibd_bio_set;
+ struct block_device *ibd_bd;
+ struct iblock_hba *ibd_host;
+} ____cacheline_aligned;
+
+struct iblock_hba {
+ int iblock_host_id;
+} ____cacheline_aligned;
+
+#endif /* TARGET_CORE_IBLOCK_H */
diff --git a/drivers/target/target_core_mib.c b/drivers/target/target_core_mib.c
new file mode 100644
index 0000000..d5a48aa
--- /dev/null
+++ b/drivers/target/target_core_mib.c
@@ -0,0 +1,1078 @@
+/*******************************************************************************
+ * Filename: target_core_mib.c
+ *
+ * Copyright (c) 2006-2007 SBE, Inc. All Rights Reserved.
+ * Copyright (c) 2007-2010 Rising Tide Systems
+ * Copyright (c) 2008-2010 Linux-iSCSI.org
+ *
+ * Nicholas A. Bellinger <nab@linux-iscsi.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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ ******************************************************************************/
+
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/string.h>
+#include <linux/version.h>
+#include <generated/utsrelease.h>
+#include <linux/utsname.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+#include <linux/blkdev.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
+
+#include <target/target_core_base.h>
+#include <target/target_core_transport.h>
+#include <target/target_core_fabric_ops.h>
+#include <target/target_core_configfs.h>
+
+#include "target_core_hba.h"
+#include "target_core_mib.h"
+
+/* SCSI mib table index */
+static struct scsi_index_table scsi_index_table;
+
+#ifndef INITIAL_JIFFIES
+#define INITIAL_JIFFIES ((unsigned long)(unsigned int) (-300*HZ))
+#endif
+
+/* SCSI Instance Table */
+#define SCSI_INST_SW_INDEX 1
+#define SCSI_TRANSPORT_INDEX 1
+
+#define NONE "None"
+#define ISPRINT(a) ((a >= ' ') && (a <= '~'))
+
+static inline int list_is_first(const struct list_head *list,
+ const struct list_head *head)
+{
+ return list->prev == head;
+}
+
+static void *locate_hba_start(
+ struct seq_file *seq,
+ loff_t *pos)
+{
+ spin_lock(&se_global->g_device_lock);
+ return seq_list_start(&se_global->g_se_dev_list, *pos);
+}
+
+static void *locate_hba_next(
+ struct seq_file *seq,
+ void *v,
+ loff_t *pos)
+{
+ return seq_list_next(v, &se_global->g_se_dev_list, pos);
+}
+
+static void locate_hba_stop(struct seq_file *seq, void *v)
+{
+ spin_unlock(&se_global->g_device_lock);
+}
+
+/****************************************************************************
+ * SCSI MIB Tables
+ ****************************************************************************/
+
+/*
+ * SCSI Instance Table
+ */
+static void *scsi_inst_seq_start(
+ struct seq_file *seq,
+ loff_t *pos)
+{
+ spin_lock(&se_global->hba_lock);
+ return seq_list_start(&se_global->g_hba_list, *pos);
+}
+
+static void *scsi_inst_seq_next(
+ struct seq_file *seq,
+ void *v,
+ loff_t *pos)
+{
+ return seq_list_next(v, &se_global->g_hba_list, pos);
+}
+
+static void scsi_inst_seq_stop(struct seq_file *seq, void *v)
+{
+ spin_unlock(&se_global->hba_lock);
+}
+
+static int scsi_inst_seq_show(struct seq_file *seq, void *v)
+{
+ struct se_hba *hba = list_entry(v, struct se_hba, hba_list);
+
+ if (list_is_first(&hba->hba_list, &se_global->g_hba_list))
+ seq_puts(seq, "inst sw_indx\n");
+
+ seq_printf(seq, "%u %u\n", hba->hba_index, SCSI_INST_SW_INDEX);
+ seq_printf(seq, "plugin: %s version: %s\n",
+ hba->transport->name, TARGET_CORE_VERSION);
+
+ return 0;
+}
+
+static const struct seq_operations scsi_inst_seq_ops = {
+ .start = scsi_inst_seq_start,
+ .next = scsi_inst_seq_next,
+ .stop = scsi_inst_seq_stop,
+ .show = scsi_inst_seq_show
+};
+
+static int scsi_inst_seq_open(struct inode *inode, struct file *file)
+{
+ return seq_open(file, &scsi_inst_seq_ops);
+}
+
+static const struct file_operations scsi_inst_seq_fops = {
+ .owner = THIS_MODULE,
+ .open = scsi_inst_seq_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
+
+/*
+ * SCSI Device Table
+ */
+static void *scsi_dev_seq_start(struct seq_file *seq, loff_t *pos)
+{
+ return locate_hba_start(seq, pos);
+}
+
+static void *scsi_dev_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+ return locate_hba_next(seq, v, pos);
+}
+
+static void scsi_dev_seq_stop(struct seq_file *seq, void *v)
+{
+ locate_hba_stop(seq, v);
+}
+
+static int scsi_dev_seq_show(struct seq_file *seq, void *v)
+{
+ struct se_hba *hba;
+ struct se_subsystem_dev *se_dev = list_entry(v, struct se_subsystem_dev,
+ g_se_dev_list);
+ struct se_device *dev = se_dev->se_dev_ptr;
+ char str[28];
+ int k;
+
+ if (list_is_first(&se_dev->g_se_dev_list, &se_global->g_se_dev_list))
+ seq_puts(seq, "inst indx role ports\n");
+
+ if (!(dev))
+ return 0;
+
+ hba = dev->se_hba;
+ if (!(hba)) {
+ /* Log error ? */
+ return 0;
+ }
+
+ seq_printf(seq, "%u %u %s %u\n", hba->hba_index,
+ dev->dev_index, "Target", dev->dev_port_count);
+
+ memcpy(&str[0], (void *)DEV_T10_WWN(dev), 28);
+
+ /* vendor */
+ for (k = 0; k < 8; k++)
+ str[k] = ISPRINT(DEV_T10_WWN(dev)->vendor[k]) ?
+ DEV_T10_WWN(dev)->vendor[k] : 0x20;
+ str[k] = 0x20;
+
+ /* model */
+ for (k = 0; k < 16; k++)
+ str[k+9] = ISPRINT(DEV_T10_WWN(dev)->model[k]) ?
+ DEV_T10_WWN(dev)->model[k] : 0x20;
+ str[k + 9] = 0;
+
+ seq_printf(seq, "dev_alias: %s\n", str);
+
+ return 0;
+}
+
+static const struct seq_operations scsi_dev_seq_ops = {
+ .start = scsi_dev_seq_start,
+ .next = scsi_dev_seq_next,
+ .stop = scsi_dev_seq_stop,
+ .show = scsi_dev_seq_show
+};
+
+static int scsi_dev_seq_open(struct inode *inode, struct file *file)
+{
+ return seq_open(file, &scsi_dev_seq_ops);
+}
+
+static const struct file_operations scsi_dev_seq_fops = {
+ .owner = THIS_MODULE,
+ .open = scsi_dev_seq_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
+
+/*
+ * SCSI Port Table
+ */
+static void *scsi_port_seq_start(struct seq_file *seq, loff_t *pos)
+{
+ return locate_hba_start(seq, pos);
+}
+
+static void *scsi_port_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+ return locate_hba_next(seq, v, pos);
+}
+
+static void scsi_port_seq_stop(struct seq_file *seq, void *v)
+{
+ locate_hba_stop(seq, v);
+}
+
+static int scsi_port_seq_show(struct seq_file *seq, void *v)
+{
+ struct se_hba *hba;
+ struct se_subsystem_dev *se_dev = list_entry(v, struct se_subsystem_dev,
+ g_se_dev_list);
+ struct se_device *dev = se_dev->se_dev_ptr;
+ struct se_port *sep, *sep_tmp;
+
+ if (list_is_first(&se_dev->g_se_dev_list, &se_global->g_se_dev_list))
+ seq_puts(seq, "inst device indx role busy_count\n");
+
+ if (!(dev))
+ return 0;
+
+ hba = dev->se_hba;
+ if (!(hba)) {
+ /* Log error ? */
+ return 0;
+ }
+
+ /* FIXME: scsiPortBusyStatuses count */
+ spin_lock(&dev->se_port_lock);
+ list_for_each_entry_safe(sep, sep_tmp, &dev->dev_sep_list, sep_list) {
+ seq_printf(seq, "%u %u %u %s%u %u\n", hba->hba_index,
+ dev->dev_index, sep->sep_index, "Device",
+ dev->dev_index, 0);
+ }
+ spin_unlock(&dev->se_port_lock);
+
+ return 0;
+}
+
+static const struct seq_operations scsi_port_seq_ops = {
+ .start = scsi_port_seq_start,
+ .next = scsi_port_seq_next,
+ .stop = scsi_port_seq_stop,
+ .show = scsi_port_seq_show
+};
+
+static int scsi_port_seq_open(struct inode *inode, struct file *file)
+{
+ return seq_open(file, &scsi_port_seq_ops);
+}
+
+static const struct file_operations scsi_port_seq_fops = {
+ .owner = THIS_MODULE,
+ .open = scsi_port_seq_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
+
+/*
+ * SCSI Transport Table
+ */
+static void *scsi_transport_seq_start(struct seq_file *seq, loff_t *pos)
+{
+ return locate_hba_start(seq, pos);
+}
+
+static void *scsi_transport_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+ return locate_hba_next(seq, v, pos);
+}
+
+static void scsi_transport_seq_stop(struct seq_file *seq, void *v)
+{
+ locate_hba_stop(seq, v);
+}
+
+static int scsi_transport_seq_show(struct seq_file *seq, void *v)
+{
+ struct se_hba *hba;
+ struct se_subsystem_dev *se_dev = list_entry(v, struct se_subsystem_dev,
+ g_se_dev_list);
+ struct se_device *dev = se_dev->se_dev_ptr;
+ struct se_port *se, *se_tmp;
+ struct se_portal_group *tpg;
+ struct t10_wwn *wwn;
+ char buf[64];
+
+ if (list_is_first(&se_dev->g_se_dev_list, &se_global->g_se_dev_list))
+ seq_puts(seq, "inst device indx dev_name\n");
+
+ if (!(dev))
+ return 0;
+
+ hba = dev->se_hba;
+ if (!(hba)) {
+ /* Log error ? */
+ return 0;
+ }
+
+ wwn = DEV_T10_WWN(dev);
+
+ spin_lock(&dev->se_port_lock);
+ list_for_each_entry_safe(se, se_tmp, &dev->dev_sep_list, sep_list) {
+ tpg = se->sep_tpg;
+ sprintf(buf, "scsiTransport%s",
+ TPG_TFO(tpg)->get_fabric_name());
+
+ seq_printf(seq, "%u %s %u %s+%s\n",
+ hba->hba_index, /* scsiTransportIndex */
+ buf, /* scsiTransportType */
+ (TPG_TFO(tpg)->tpg_get_inst_index != NULL) ?
+ TPG_TFO(tpg)->tpg_get_inst_index(tpg) :
+ 0,
+ TPG_TFO(tpg)->tpg_get_wwn(tpg),
+ (strlen(wwn->unit_serial)) ?
+ /* scsiTransportDevName */
+ wwn->unit_serial : wwn->vendor);
+ }
+ spin_unlock(&dev->se_port_lock);
+
+ return 0;
+}
+
+static const struct seq_operations scsi_transport_seq_ops = {
+ .start = scsi_transport_seq_start,
+ .next = scsi_transport_seq_next,
+ .stop = scsi_transport_seq_stop,
+ .show = scsi_transport_seq_show
+};
+
+static int scsi_transport_seq_open(struct inode *inode, struct file *file)
+{
+ return seq_open(file, &scsi_transport_seq_ops);
+}
+
+static const struct file_operations scsi_transport_seq_fops = {
+ .owner = THIS_MODULE,
+ .open = scsi_transport_seq_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
+
+/*
+ * SCSI Target Device Table
+ */
+static void *scsi_tgt_dev_seq_start(struct seq_file *seq, loff_t *pos)
+{
+ return locate_hba_start(seq, pos);
+}
+
+static void *scsi_tgt_dev_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+ return locate_hba_next(seq, v, pos);
+}
+
+static void scsi_tgt_dev_seq_stop(struct seq_file *seq, void *v)
+{
+ locate_hba_stop(seq, v);
+}
+
+
+#define LU_COUNT 1 /* for now */
+static int scsi_tgt_dev_seq_show(struct seq_file *seq, void *v)
+{
+ struct se_hba *hba;
+ struct se_subsystem_dev *se_dev = list_entry(v, struct se_subsystem_dev,
+ g_se_dev_list);
+ struct se_device *dev = se_dev->se_dev_ptr;
+ int non_accessible_lus = 0;
+ char status[16];
+
+ if (list_is_first(&se_dev->g_se_dev_list, &se_global->g_se_dev_list))
+ seq_puts(seq, "inst indx num_LUs status non_access_LUs"
+ " resets\n");
+
+ if (!(dev))
+ return 0;
+
+ hba = dev->se_hba;
+ if (!(hba)) {
+ /* Log error ? */
+ return 0;
+ }
+
+ switch (dev->dev_status) {
+ case TRANSPORT_DEVICE_ACTIVATED:
+ strcpy(status, "activated");
+ break;
+ case TRANSPORT_DEVICE_DEACTIVATED:
+ strcpy(status, "deactivated");
+ non_accessible_lus = 1;
+ break;
+ case TRANSPORT_DEVICE_SHUTDOWN:
+ strcpy(status, "shutdown");
+ non_accessible_lus = 1;
+ break;
+ case TRANSPORT_DEVICE_OFFLINE_ACTIVATED:
+ case TRANSPORT_DEVICE_OFFLINE_DEACTIVATED:
+ strcpy(status, "offline");
+ non_accessible_lus = 1;
+ break;
+ default:
+ sprintf(status, "unknown(%d)", dev->dev_status);
+ non_accessible_lus = 1;
+ }
+
+ seq_printf(seq, "%u %u %u %s %u %u\n",
+ hba->hba_index, dev->dev_index, LU_COUNT,
+ status, non_accessible_lus, dev->num_resets);
+
+ return 0;
+}
+
+static const struct seq_operations scsi_tgt_dev_seq_ops = {
+ .start = scsi_tgt_dev_seq_start,
+ .next = scsi_tgt_dev_seq_next,
+ .stop = scsi_tgt_dev_seq_stop,
+ .show = scsi_tgt_dev_seq_show
+};
+
+static int scsi_tgt_dev_seq_open(struct inode *inode, struct file *file)
+{
+ return seq_open(file, &scsi_tgt_dev_seq_ops);
+}
+
+static const struct file_operations scsi_tgt_dev_seq_fops = {
+ .owner = THIS_MODULE,
+ .open = scsi_tgt_dev_seq_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
+
+/*
+ * SCSI Target Port Table
+ */
+static void *scsi_tgt_port_seq_start(struct seq_file *seq, loff_t *pos)
+{
+ return locate_hba_start(seq, pos);
+}
+
+static void *scsi_tgt_port_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+ return locate_hba_next(seq, v, pos);
+}
+
+static void scsi_tgt_port_seq_stop(struct seq_file *seq, void *v)
+{
+ locate_hba_stop(seq, v);
+}
+
+static int scsi_tgt_port_seq_show(struct seq_file *seq, void *v)
+{
+ struct se_hba *hba;
+ struct se_subsystem_dev *se_dev = list_entry(v, struct se_subsystem_dev,
+ g_se_dev_list);
+ struct se_device *dev = se_dev->se_dev_ptr;
+ struct se_port *sep, *sep_tmp;
+ struct se_portal_group *tpg;
+ u32 rx_mbytes, tx_mbytes;
+ unsigned long long num_cmds;
+ char buf[64];
+
+ if (list_is_first(&se_dev->g_se_dev_list, &se_global->g_se_dev_list))
+ seq_puts(seq, "inst device indx name port_index in_cmds"
+ " write_mbytes read_mbytes hs_in_cmds\n");
+
+ if (!(dev))
+ return 0;
+
+ hba = dev->se_hba;
+ if (!(hba)) {
+ /* Log error ? */
+ return 0;
+ }
+
+ spin_lock(&dev->se_port_lock);
+ list_for_each_entry_safe(sep, sep_tmp, &dev->dev_sep_list, sep_list) {
+ tpg = sep->sep_tpg;
+ sprintf(buf, "%sPort#",
+ TPG_TFO(tpg)->get_fabric_name());
+
+ seq_printf(seq, "%u %u %u %s%d %s%s%d ",
+ hba->hba_index,
+ dev->dev_index,
+ sep->sep_index,
+ buf, sep->sep_index,
+ TPG_TFO(tpg)->tpg_get_wwn(tpg), "+t+",
+ TPG_TFO(tpg)->tpg_get_tag(tpg));
+
+ spin_lock(&sep->sep_lun->lun_sep_lock);
+ num_cmds = sep->sep_stats.cmd_pdus;
+ rx_mbytes = (sep->sep_stats.rx_data_octets >> 20);
+ tx_mbytes = (sep->sep_stats.tx_data_octets >> 20);
+ spin_unlock(&sep->sep_lun->lun_sep_lock);
+
+ seq_printf(seq, "%llu %u %u %u\n", num_cmds,
+ rx_mbytes, tx_mbytes, 0);
+ }
+ spin_unlock(&dev->se_port_lock);
+
+ return 0;
+}
+
+static const struct seq_operations scsi_tgt_port_seq_ops = {
+ .start = scsi_tgt_port_seq_start,
+ .next = scsi_tgt_port_seq_next,
+ .stop = scsi_tgt_port_seq_stop,
+ .show = scsi_tgt_port_seq_show
+};
+
+static int scsi_tgt_port_seq_open(struct inode *inode, struct file *file)
+{
+ return seq_open(file, &scsi_tgt_port_seq_ops);
+}
+
+static const struct file_operations scsi_tgt_port_seq_fops = {
+ .owner = THIS_MODULE,
+ .open = scsi_tgt_port_seq_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
+
+/*
+ * SCSI Authorized Initiator Table:
+ * It contains the SCSI Initiators authorized to be attached to one of the
+ * local Target ports.
+ * Iterates through all active TPGs and extracts the info from the ACLs
+ */
+static void *scsi_auth_intr_seq_start(struct seq_file *seq, loff_t *pos)
+{
+ spin_lock_bh(&se_global->se_tpg_lock);
+ return seq_list_start(&se_global->g_se_tpg_list, *pos);
+}
+
+static void *scsi_auth_intr_seq_next(struct seq_file *seq, void *v,
+ loff_t *pos)
+{
+ return seq_list_next(v, &se_global->g_se_tpg_list, pos);
+}
+
+static void scsi_auth_intr_seq_stop(struct seq_file *seq, void *v)
+{
+ spin_unlock_bh(&se_global->se_tpg_lock);
+}
+
+static int scsi_auth_intr_seq_show(struct seq_file *seq, void *v)
+{
+ struct se_portal_group *se_tpg = list_entry(v, struct se_portal_group,
+ se_tpg_list);
+ struct se_dev_entry *deve;
+ struct se_lun *lun;
+ struct se_node_acl *se_nacl;
+ int j;
+
+ if (list_is_first(&se_tpg->se_tpg_list,
+ &se_global->g_se_tpg_list))
+ seq_puts(seq, "inst dev port indx dev_or_port intr_name "
+ "map_indx att_count num_cmds read_mbytes "
+ "write_mbytes hs_num_cmds creation_time row_status\n");
+
+ if (!(se_tpg))
+ return 0;
+
+ spin_lock(&se_tpg->acl_node_lock);
+ list_for_each_entry(se_nacl, &se_tpg->acl_node_list, acl_list) {
+
+ atomic_inc(&se_nacl->mib_ref_count);
+ smp_mb__after_atomic_inc();
+ spin_unlock(&se_tpg->acl_node_lock);
+
+ spin_lock_irq(&se_nacl->device_list_lock);
+ for (j = 0; j < TRANSPORT_MAX_LUNS_PER_TPG; j++) {
+ deve = &se_nacl->device_list[j];
+ if (!(deve->lun_flags &
+ TRANSPORT_LUNFLAGS_INITIATOR_ACCESS) ||
+ (!deve->se_lun))
+ continue;
+ lun = deve->se_lun;
+ if (!lun->lun_se_dev)
+ continue;
+
+ seq_printf(seq, "%u %u %u %u %u %s %u %u %u %u %u %u"
+ " %u %s\n",
+ /* scsiInstIndex */
+ (TPG_TFO(se_tpg)->tpg_get_inst_index != NULL) ?
+ TPG_TFO(se_tpg)->tpg_get_inst_index(se_tpg) :
+ 0,
+ /* scsiDeviceIndex */
+ lun->lun_se_dev->dev_index,
+ /* scsiAuthIntrTgtPortIndex */
+ TPG_TFO(se_tpg)->tpg_get_tag(se_tpg),
+ /* scsiAuthIntrIndex */
+ se_nacl->acl_index,
+ /* scsiAuthIntrDevOrPort */
+ 1,
+ /* scsiAuthIntrName */
+ se_nacl->initiatorname[0] ?
+ se_nacl->initiatorname : NONE,
+ /* FIXME: scsiAuthIntrLunMapIndex */
+ 0,
+ /* scsiAuthIntrAttachedTimes */
+ deve->attach_count,
+ /* scsiAuthIntrOutCommands */
+ deve->total_cmds,
+ /* scsiAuthIntrReadMegaBytes */
+ (u32)(deve->read_bytes >> 20),
+ /* scsiAuthIntrWrittenMegaBytes */
+ (u32)(deve->write_bytes >> 20),
+ /* FIXME: scsiAuthIntrHSOutCommands */
+ 0,
+ /* scsiAuthIntrLastCreation */
+ (u32)(((u32)deve->creation_time -
+ INITIAL_JIFFIES) * 100 / HZ),
+ /* FIXME: scsiAuthIntrRowStatus */
+ "Ready");
+ }
+ spin_unlock_irq(&se_nacl->device_list_lock);
+
+ spin_lock(&se_tpg->acl_node_lock);
+ atomic_dec(&se_nacl->mib_ref_count);
+ smp_mb__after_atomic_dec();
+ }
+ spin_unlock(&se_tpg->acl_node_lock);
+
+ return 0;
+}
+
+static const struct seq_operations scsi_auth_intr_seq_ops = {
+ .start = scsi_auth_intr_seq_start,
+ .next = scsi_auth_intr_seq_next,
+ .stop = scsi_auth_intr_seq_stop,
+ .show = scsi_auth_intr_seq_show
+};
+
+static int scsi_auth_intr_seq_open(struct inode *inode, struct file *file)
+{
+ return seq_open(file, &scsi_auth_intr_seq_ops);
+}
+
+static const struct file_operations scsi_auth_intr_seq_fops = {
+ .owner = THIS_MODULE,
+ .open = scsi_auth_intr_seq_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
+
+/*
+ * SCSI Attached Initiator Port Table:
+ * It lists the SCSI Initiators attached to one of the local Target ports.
+ * Iterates through all active TPGs and use active sessions from each TPG
+ * to list the info fo this table.
+ */
+static void *scsi_att_intr_port_seq_start(struct seq_file *seq, loff_t *pos)
+{
+ spin_lock_bh(&se_global->se_tpg_lock);
+ return seq_list_start(&se_global->g_se_tpg_list, *pos);
+}
+
+static void *scsi_att_intr_port_seq_next(struct seq_file *seq, void *v,
+ loff_t *pos)
+{
+ return seq_list_next(v, &se_global->g_se_tpg_list, pos);
+}
+
+static void scsi_att_intr_port_seq_stop(struct seq_file *seq, void *v)
+{
+ spin_unlock_bh(&se_global->se_tpg_lock);
+}
+
+static int scsi_att_intr_port_seq_show(struct seq_file *seq, void *v)
+{
+ struct se_portal_group *se_tpg = list_entry(v, struct se_portal_group,
+ se_tpg_list);
+ struct se_dev_entry *deve;
+ struct se_lun *lun;
+ struct se_node_acl *se_nacl;
+ struct se_session *se_sess;
+ unsigned char buf[64];
+ int j;
+
+ if (list_is_first(&se_tpg->se_tpg_list,
+ &se_global->g_se_tpg_list))
+ seq_puts(seq, "inst dev port indx port_auth_indx port_name"
+ " port_ident\n");
+
+ if (!(se_tpg))
+ return 0;
+
+ spin_lock(&se_tpg->session_lock);
+ list_for_each_entry(se_sess, &se_tpg->tpg_sess_list, sess_list) {
+ if ((TPG_TFO(se_tpg)->sess_logged_in(se_sess)) ||
+ (!se_sess->se_node_acl) ||
+ (!se_sess->se_node_acl->device_list))
+ continue;
+
+ atomic_inc(&se_sess->mib_ref_count);
+ smp_mb__after_atomic_inc();
+ se_nacl = se_sess->se_node_acl;
+ atomic_inc(&se_nacl->mib_ref_count);
+ smp_mb__after_atomic_inc();
+ spin_unlock(&se_tpg->session_lock);
+
+ spin_lock_irq(&se_nacl->device_list_lock);
+ for (j = 0; j < TRANSPORT_MAX_LUNS_PER_TPG; j++) {
+ deve = &se_nacl->device_list[j];
+ if (!(deve->lun_flags &
+ TRANSPORT_LUNFLAGS_INITIATOR_ACCESS) ||
+ (!deve->se_lun))
+ continue;
+
+ lun = deve->se_lun;
+ if (!lun->lun_se_dev)
+ continue;
+
+ memset(buf, 0, 64);
+ if (TPG_TFO(se_tpg)->sess_get_initiator_sid != NULL)
+ TPG_TFO(se_tpg)->sess_get_initiator_sid(
+ se_sess, (unsigned char *)&buf[0], 64);
+
+ seq_printf(seq, "%u %u %u %u %u %s+i+%s\n",
+ /* scsiInstIndex */
+ (TPG_TFO(se_tpg)->tpg_get_inst_index != NULL) ?
+ TPG_TFO(se_tpg)->tpg_get_inst_index(se_tpg) :
+ 0,
+ /* scsiDeviceIndex */
+ lun->lun_se_dev->dev_index,
+ /* scsiPortIndex */
+ TPG_TFO(se_tpg)->tpg_get_tag(se_tpg),
+ /* scsiAttIntrPortIndex */
+ (TPG_TFO(se_tpg)->sess_get_index != NULL) ?
+ TPG_TFO(se_tpg)->sess_get_index(se_sess) :
+ 0,
+ /* scsiAttIntrPortAuthIntrIdx */
+ se_nacl->acl_index,
+ /* scsiAttIntrPortName */
+ se_nacl->initiatorname[0] ?
+ se_nacl->initiatorname : NONE,
+ /* scsiAttIntrPortIdentifier */
+ buf);
+ }
+ spin_unlock_irq(&se_nacl->device_list_lock);
+
+ spin_lock(&se_tpg->session_lock);
+ atomic_dec(&se_nacl->mib_ref_count);
+ smp_mb__after_atomic_dec();
+ atomic_dec(&se_sess->mib_ref_count);
+ smp_mb__after_atomic_dec();
+ }
+ spin_unlock(&se_tpg->session_lock);
+
+ return 0;
+}
+
+static const struct seq_operations scsi_att_intr_port_seq_ops = {
+ .start = scsi_att_intr_port_seq_start,
+ .next = scsi_att_intr_port_seq_next,
+ .stop = scsi_att_intr_port_seq_stop,
+ .show = scsi_att_intr_port_seq_show
+};
+
+static int scsi_att_intr_port_seq_open(struct inode *inode, struct file *file)
+{
+ return seq_open(file, &scsi_att_intr_port_seq_ops);
+}
+
+static const struct file_operations scsi_att_intr_port_seq_fops = {
+ .owner = THIS_MODULE,
+ .open = scsi_att_intr_port_seq_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
+
+/*
+ * SCSI Logical Unit Table
+ */
+static void *scsi_lu_seq_start(struct seq_file *seq, loff_t *pos)
+{
+ return locate_hba_start(seq, pos);
+}
+
+static void *scsi_lu_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+ return locate_hba_next(seq, v, pos);
+}
+
+static void scsi_lu_seq_stop(struct seq_file *seq, void *v)
+{
+ locate_hba_stop(seq, v);
+}
+
+#define SCSI_LU_INDEX 1
+static int scsi_lu_seq_show(struct seq_file *seq, void *v)
+{
+ struct se_hba *hba;
+ struct se_subsystem_dev *se_dev = list_entry(v, struct se_subsystem_dev,
+ g_se_dev_list);
+ struct se_device *dev = se_dev->se_dev_ptr;
+ int j;
+ char str[28];
+
+ if (list_is_first(&se_dev->g_se_dev_list, &se_global->g_se_dev_list))
+ seq_puts(seq, "inst dev indx LUN lu_name vend prod rev"
+ " dev_type status state-bit num_cmds read_mbytes"
+ " write_mbytes resets full_stat hs_num_cmds creation_time\n");
+
+ if (!(dev))
+ return 0;
+
+ hba = dev->se_hba;
+ if (!(hba)) {
+ /* Log error ? */
+ return 0;
+ }
+
+ /* Fix LU state, if we can read it from the device */
+ seq_printf(seq, "%u %u %u %llu %s", hba->hba_index,
+ dev->dev_index, SCSI_LU_INDEX,
+ (unsigned long long)0, /* FIXME: scsiLuDefaultLun */
+ (strlen(DEV_T10_WWN(dev)->unit_serial)) ?
+ /* scsiLuWwnName */
+ (char *)&DEV_T10_WWN(dev)->unit_serial[0] :
+ "None");
+
+ memcpy(&str[0], (void *)DEV_T10_WWN(dev), 28);
+ /* scsiLuVendorId */
+ for (j = 0; j < 8; j++)
+ str[j] = ISPRINT(DEV_T10_WWN(dev)->vendor[j]) ?
+ DEV_T10_WWN(dev)->vendor[j] : 0x20;
+ str[8] = 0;
+ seq_printf(seq, " %s", str);
+
+ /* scsiLuProductId */
+ for (j = 0; j < 16; j++)
+ str[j] = ISPRINT(DEV_T10_WWN(dev)->model[j]) ?
+ DEV_T10_WWN(dev)->model[j] : 0x20;
+ str[16] = 0;
+ seq_printf(seq, " %s", str);
+
+ /* scsiLuRevisionId */
+ for (j = 0; j < 4; j++)
+ str[j] = ISPRINT(DEV_T10_WWN(dev)->revision[j]) ?
+ DEV_T10_WWN(dev)->revision[j] : 0x20;
+ str[4] = 0;
+ seq_printf(seq, " %s", str);
+
+ seq_printf(seq, " %u %s %s %llu %u %u %u %u %u %u\n",
+ /* scsiLuPeripheralType */
+ TRANSPORT(dev)->get_device_type(dev),
+ (dev->dev_status == TRANSPORT_DEVICE_ACTIVATED) ?
+ "available" : "notavailable", /* scsiLuStatus */
+ "exposed", /* scsiLuState */
+ (unsigned long long)dev->num_cmds,
+ /* scsiLuReadMegaBytes */
+ (u32)(dev->read_bytes >> 20),
+ /* scsiLuWrittenMegaBytes */
+ (u32)(dev->write_bytes >> 20),
+ dev->num_resets, /* scsiLuInResets */
+ 0, /* scsiLuOutTaskSetFullStatus */
+ 0, /* scsiLuHSInCommands */
+ (u32)(((u32)dev->creation_time - INITIAL_JIFFIES) *
+ 100 / HZ));
+
+ return 0;
+}
+
+static const struct seq_operations scsi_lu_seq_ops = {
+ .start = scsi_lu_seq_start,
+ .next = scsi_lu_seq_next,
+ .stop = scsi_lu_seq_stop,
+ .show = scsi_lu_seq_show
+};
+
+static int scsi_lu_seq_open(struct inode *inode, struct file *file)
+{
+ return seq_open(file, &scsi_lu_seq_ops);
+}
+
+static const struct file_operations scsi_lu_seq_fops = {
+ .owner = THIS_MODULE,
+ .open = scsi_lu_seq_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
+
+/****************************************************************************/
+
+/*
+ * Remove proc fs entries
+ */
+void remove_scsi_target_mib(void)
+{
+ remove_proc_entry("scsi_target/mib/scsi_inst", NULL);
+ remove_proc_entry("scsi_target/mib/scsi_dev", NULL);
+ remove_proc_entry("scsi_target/mib/scsi_port", NULL);
+ remove_proc_entry("scsi_target/mib/scsi_transport", NULL);
+ remove_proc_entry("scsi_target/mib/scsi_tgt_dev", NULL);
+ remove_proc_entry("scsi_target/mib/scsi_tgt_port", NULL);
+ remove_proc_entry("scsi_target/mib/scsi_auth_intr", NULL);
+ remove_proc_entry("scsi_target/mib/scsi_att_intr_port", NULL);
+ remove_proc_entry("scsi_target/mib/scsi_lu", NULL);
+ remove_proc_entry("scsi_target/mib", NULL);
+}
+
+/*
+ * Create proc fs entries for the mib tables
+ */
+int init_scsi_target_mib(void)
+{
+ struct proc_dir_entry *dir_entry;
+ struct proc_dir_entry *scsi_inst_entry;
+ struct proc_dir_entry *scsi_dev_entry;
+ struct proc_dir_entry *scsi_port_entry;
+ struct proc_dir_entry *scsi_transport_entry;
+ struct proc_dir_entry *scsi_tgt_dev_entry;
+ struct proc_dir_entry *scsi_tgt_port_entry;
+ struct proc_dir_entry *scsi_auth_intr_entry;
+ struct proc_dir_entry *scsi_att_intr_port_entry;
+ struct proc_dir_entry *scsi_lu_entry;
+
+ dir_entry = proc_mkdir("scsi_target/mib", NULL);
+ if (!(dir_entry)) {
+ printk(KERN_ERR "proc_mkdir() failed.\n");
+ return -1;
+ }
+
+ scsi_inst_entry =
+ create_proc_entry("scsi_target/mib/scsi_inst", 0, NULL);
+ if (scsi_inst_entry)
+ scsi_inst_entry->proc_fops = &scsi_inst_seq_fops;
+ else
+ goto error;
+
+ scsi_dev_entry =
+ create_proc_entry("scsi_target/mib/scsi_dev", 0, NULL);
+ if (scsi_dev_entry)
+ scsi_dev_entry->proc_fops = &scsi_dev_seq_fops;
+ else
+ goto error;
+
+ scsi_port_entry =
+ create_proc_entry("scsi_target/mib/scsi_port", 0, NULL);
+ if (scsi_port_entry)
+ scsi_port_entry->proc_fops = &scsi_port_seq_fops;
+ else
+ goto error;
+
+ scsi_transport_entry =
+ create_proc_entry("scsi_target/mib/scsi_transport", 0, NULL);
+ if (scsi_transport_entry)
+ scsi_transport_entry->proc_fops = &scsi_transport_seq_fops;
+ else
+ goto error;
+
+ scsi_tgt_dev_entry =
+ create_proc_entry("scsi_target/mib/scsi_tgt_dev", 0, NULL);
+ if (scsi_tgt_dev_entry)
+ scsi_tgt_dev_entry->proc_fops = &scsi_tgt_dev_seq_fops;
+ else
+ goto error;
+
+ scsi_tgt_port_entry =
+ create_proc_entry("scsi_target/mib/scsi_tgt_port", 0, NULL);
+ if (scsi_tgt_port_entry)
+ scsi_tgt_port_entry->proc_fops = &scsi_tgt_port_seq_fops;
+ else
+ goto error;
+
+ scsi_auth_intr_entry =
+ create_proc_entry("scsi_target/mib/scsi_auth_intr", 0, NULL);
+ if (scsi_auth_intr_entry)
+ scsi_auth_intr_entry->proc_fops = &scsi_auth_intr_seq_fops;
+ else
+ goto error;
+
+ scsi_att_intr_port_entry =
+ create_proc_entry("scsi_target/mib/scsi_att_intr_port", 0, NULL);
+ if (scsi_att_intr_port_entry)
+ scsi_att_intr_port_entry->proc_fops =
+ &scsi_att_intr_port_seq_fops;
+ else
+ goto error;
+
+ scsi_lu_entry = create_proc_entry("scsi_target/mib/scsi_lu", 0, NULL);
+ if (scsi_lu_entry)
+ scsi_lu_entry->proc_fops = &scsi_lu_seq_fops;
+ else
+ goto error;
+
+ return 0;
+
+error:
+ printk(KERN_ERR "create_proc_entry() failed.\n");
+ remove_scsi_target_mib();
+ return -1;
+}
+
+/*
+ * Initialize the index table for allocating unique row indexes to various mib
+ * tables
+ */
+void init_scsi_index_table(void)
+{
+ memset(&scsi_index_table, 0, sizeof(struct scsi_index_table));
+ spin_lock_init(&scsi_index_table.lock);
+}
+
+/*
+ * Allocate a new row index for the entry type specified
+ */
+u32 scsi_get_new_index(scsi_index_t type)
+{
+ u32 new_index;
+
+ if ((type < 0) || (type >= SCSI_INDEX_TYPE_MAX)) {
+ printk(KERN_ERR "Invalid index type %d\n", type);
+ return -1;
+ }
+
+ spin_lock(&scsi_index_table.lock);
+ new_index = ++scsi_index_table.scsi_mib_index[type];
+ if (new_index == 0)
+ new_index = ++scsi_index_table.scsi_mib_index[type];
+ spin_unlock(&scsi_index_table.lock);
+
+ return new_index;
+}
+EXPORT_SYMBOL(scsi_get_new_index);
diff --git a/drivers/target/target_core_mib.h b/drivers/target/target_core_mib.h
new file mode 100644
index 0000000..2772046
--- /dev/null
+++ b/drivers/target/target_core_mib.h
@@ -0,0 +1,28 @@
+#ifndef TARGET_CORE_MIB_H
+#define TARGET_CORE_MIB_H
+
+typedef enum {
+ SCSI_INST_INDEX,
+ SCSI_DEVICE_INDEX,
+ SCSI_AUTH_INTR_INDEX,
+ SCSI_INDEX_TYPE_MAX
+} scsi_index_t;
+
+struct scsi_index_table {
+ spinlock_t lock;
+ u32 scsi_mib_index[SCSI_INDEX_TYPE_MAX];
+} ____cacheline_aligned;
+
+/* SCSI Port stats */
+struct scsi_port_stats {
+ u64 cmd_pdus;
+ u64 tx_data_octets;
+ u64 rx_data_octets;
+} ____cacheline_aligned;
+
+extern int init_scsi_target_mib(void);
+extern void remove_scsi_target_mib(void);
+extern void init_scsi_index_table(void);
+extern u32 scsi_get_new_index(scsi_index_t);
+
+#endif /*** TARGET_CORE_MIB_H ***/
diff --git a/drivers/target/target_core_pr.c b/drivers/target/target_core_pr.c
new file mode 100644
index 0000000..2521f75
--- /dev/null
+++ b/drivers/target/target_core_pr.c
@@ -0,0 +1,4252 @@
+/*******************************************************************************
+ * Filename: target_core_pr.c
+ *
+ * This file contains SPC-3 compliant persistent reservations and
+ * legacy SPC-2 reservations with compatible reservation handling (CRH=1)
+ *
+ * Copyright (c) 2009, 2010 Rising Tide Systems
+ * Copyright (c) 2009, 2010 Linux-iSCSI.org
+ *
+ * Nicholas A. Bellinger <nab@kernel.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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ ******************************************************************************/
+
+#include <linux/version.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/list.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <asm/unaligned.h>
+
+#include <target/target_core_base.h>
+#include <target/target_core_device.h>
+#include <target/target_core_tmr.h>
+#include <target/target_core_tpg.h>
+#include <target/target_core_transport.h>
+#include <target/target_core_fabric_ops.h>
+#include <target/target_core_configfs.h>
+
+#include "target_core_hba.h"
+#include "target_core_pr.h"
+#include "target_core_ua.h"
+
+/*
+ * Used for Specify Initiator Ports Capable Bit (SPEC_I_PT)
+ */
+struct pr_transport_id_holder {
+ int dest_local_nexus;
+ struct t10_pr_registration *dest_pr_reg;
+ struct se_portal_group *dest_tpg;
+ struct se_node_acl *dest_node_acl;
+ struct se_dev_entry *dest_se_deve;
+ struct list_head dest_list;
+};
+
+int core_pr_dump_initiator_port(
+ struct t10_pr_registration *pr_reg,
+ char *buf,
+ u32 size)
+{
+ if (!(pr_reg->isid_present_at_reg))
+ return 0;
+
+ snprintf(buf, size, ",i,0x%s", &pr_reg->pr_reg_isid[0]);
+ return 1;
+}
+
+static void __core_scsi3_complete_pro_release(struct se_device *, struct se_node_acl *,
+ struct t10_pr_registration *, int);
+
+static int core_scsi2_reservation_seq_non_holder(
+ struct se_cmd *cmd,
+ unsigned char *cdb,
+ u32 pr_reg_type)
+{
+ switch (cdb[0]) {
+ case INQUIRY:
+ case RELEASE:
+ case RELEASE_10:
+ return 0;
+ default:
+ return 1;
+ }
+
+ return 1;
+}
+
+static int core_scsi2_reservation_check(struct se_cmd *cmd, u32 *pr_reg_type)
+{
+ struct se_device *dev = cmd->se_dev;
+ struct se_session *sess = cmd->se_sess;
+ int ret;
+
+ if (!(sess))
+ return 0;
+
+ spin_lock(&dev->dev_reservation_lock);
+ if (!dev->dev_reserved_node_acl || !sess) {
+ spin_unlock(&dev->dev_reservation_lock);
+ return 0;
+ }
+ if (dev->dev_reserved_node_acl != sess->se_node_acl) {
+ spin_unlock(&dev->dev_reservation_lock);
+ return -1;
+ }
+ if (!(dev->dev_flags & DF_SPC2_RESERVATIONS_WITH_ISID)) {
+ spin_unlock(&dev->dev_reservation_lock);
+ return 0;
+ }
+ ret = (dev->dev_res_bin_isid == sess->sess_bin_isid) ? 0 : -1;
+ spin_unlock(&dev->dev_reservation_lock);
+
+ return ret;
+}
+
+static int core_scsi2_reservation_release(struct se_cmd *cmd)
+{
+ struct se_device *dev = cmd->se_dev;
+ struct se_session *sess = cmd->se_sess;
+ struct se_portal_group *tpg = sess->se_tpg;
+
+ if (!(sess) || !(tpg))
+ return 0;
+
+ spin_lock(&dev->dev_reservation_lock);
+ if (!dev->dev_reserved_node_acl || !sess) {
+ spin_unlock(&dev->dev_reservation_lock);
+ return 0;
+ }
+
+ if (dev->dev_reserved_node_acl != sess->se_node_acl) {
+ spin_unlock(&dev->dev_reservation_lock);
+ return 0;
+ }
+ dev->dev_reserved_node_acl = NULL;
+ dev->dev_flags &= ~DF_SPC2_RESERVATIONS;
+ if (dev->dev_flags & DF_SPC2_RESERVATIONS_WITH_ISID) {
+ dev->dev_res_bin_isid = 0;
+ dev->dev_flags &= ~DF_SPC2_RESERVATIONS_WITH_ISID;
+ }
+ printk(KERN_INFO "SCSI-2 Released reservation for %s LUN: %u ->"
+ " MAPPED LUN: %u for %s\n", TPG_TFO(tpg)->get_fabric_name(),
+ SE_LUN(cmd)->unpacked_lun, cmd->se_deve->mapped_lun,
+ sess->se_node_acl->initiatorname);
+ spin_unlock(&dev->dev_reservation_lock);
+
+ return 0;
+}
+
+static int core_scsi2_reservation_reserve(struct se_cmd *cmd)
+{
+ struct se_device *dev = cmd->se_dev;
+ struct se_session *sess = cmd->se_sess;
+ struct se_portal_group *tpg = sess->se_tpg;
+
+ if ((T_TASK(cmd)->t_task_cdb[1] & 0x01) &&
+ (T_TASK(cmd)->t_task_cdb[1] & 0x02)) {
+ printk(KERN_ERR "LongIO and Obselete Bits set, returning"
+ " ILLEGAL_REQUEST\n");
+ return PYX_TRANSPORT_ILLEGAL_REQUEST;
+ }
+ /*
+ * This is currently the case for target_core_mod passthrough struct se_cmd
+ * ops
+ */
+ if (!(sess) || !(tpg))
+ return 0;
+
+ spin_lock(&dev->dev_reservation_lock);
+ if (dev->dev_reserved_node_acl &&
+ (dev->dev_reserved_node_acl != sess->se_node_acl)) {
+ printk(KERN_ERR "SCSI-2 RESERVATION CONFLIFT for %s fabric\n",
+ TPG_TFO(tpg)->get_fabric_name());
+ printk(KERN_ERR "Original reserver LUN: %u %s\n",
+ SE_LUN(cmd)->unpacked_lun,
+ dev->dev_reserved_node_acl->initiatorname);
+ printk(KERN_ERR "Current attempt - LUN: %u -> MAPPED LUN: %u"
+ " from %s \n", SE_LUN(cmd)->unpacked_lun,
+ cmd->se_deve->mapped_lun,
+ sess->se_node_acl->initiatorname);
+ spin_unlock(&dev->dev_reservation_lock);
+ return PYX_TRANSPORT_RESERVATION_CONFLICT;
+ }
+
+ dev->dev_reserved_node_acl = sess->se_node_acl;
+ dev->dev_flags |= DF_SPC2_RESERVATIONS;
+ if (sess->sess_bin_isid != 0) {
+ dev->dev_res_bin_isid = sess->sess_bin_isid;
+ dev->dev_flags |= DF_SPC2_RESERVATIONS_WITH_ISID;
+ }
+ printk(KERN_INFO "SCSI-2 Reserved %s LUN: %u -> MAPPED LUN: %u"
+ " for %s\n", TPG_TFO(tpg)->get_fabric_name(),
+ SE_LUN(cmd)->unpacked_lun, cmd->se_deve->mapped_lun,
+ sess->se_node_acl->initiatorname);
+ spin_unlock(&dev->dev_reservation_lock);
+
+ return 0;
+}
+
+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 *);
+
+/*
+ * Setup in target_core_transport.c:transport_generic_cmd_sequencer()
+ * and called via struct se_cmd->transport_emulate_cdb() in TCM processing
+ * thread context.
+ */
+int core_scsi2_emulate_crh(struct se_cmd *cmd)
+{
+ struct se_session *se_sess = cmd->se_sess;
+ struct se_subsystem_dev *su_dev = cmd->se_dev->se_sub_dev;
+ struct t10_pr_registration *pr_reg;
+ struct t10_reservation_template *pr_tmpl = &su_dev->t10_reservation;
+ unsigned char *cdb = &T_TASK(cmd)->t_task_cdb[0];
+ int crh = (T10_RES(su_dev)->res_type == SPC3_PERSISTENT_RESERVATIONS);
+ int conflict = 0;
+
+ if (!(se_sess))
+ return 0;
+
+ if (!(crh))
+ goto after_crh;
+
+ pr_reg = core_scsi3_locate_pr_reg(cmd->se_dev, se_sess->se_node_acl,
+ se_sess);
+ if (pr_reg) {
+ /*
+ * From spc4r17 5.7.3 Exceptions to SPC-2 RESERVE and RELEASE
+ * behavior
+ *
+ * A RESERVE(6) or RESERVE(10) command shall complete with GOOD
+ * status, but no reservation shall be established and the
+ * persistent reservation shall not be changed, if the command
+ * is received from a) and b) below.
+ *
+ * A RELEASE(6) or RELEASE(10) command shall complete with GOOD
+ * status, but the persistent reservation shall not be released,
+ * if the command is received from a) and b)
+ *
+ * a) An I_T nexus that is a persistent reservation holder; or
+ * b) An I_T nexus that is registered if a registrants only or
+ * all registrants type persistent reservation is present.
+ *
+ * In all other cases, a RESERVE(6) command, RESERVE(10) command,
+ * RELEASE(6) command, or RELEASE(10) command shall be processed
+ * as defined in SPC-2.
+ */
+ if (pr_reg->pr_res_holder) {
+ core_scsi3_put_pr_reg(pr_reg);
+ return 0;
+ }
+ 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);
+ return 0;
+ }
+ core_scsi3_put_pr_reg(pr_reg);
+ conflict = 1;
+ } else {
+ /*
+ * Following spc2r20 5.5.1 Reservations overview:
+ *
+ * If a logical unit has executed a PERSISTENT RESERVE OUT
+ * command with the REGISTER or the REGISTER AND IGNORE
+ * EXISTING KEY service action and is still registered by any
+ * initiator, all RESERVE commands and all RELEASE commands
+ * regardless of initiator shall conflict and shall terminate
+ * with a RESERVATION CONFLICT status.
+ */
+ spin_lock(&pr_tmpl->registration_lock);
+ conflict = (list_empty(&pr_tmpl->registration_list)) ? 0 : 1;
+ spin_unlock(&pr_tmpl->registration_lock);
+ }
+
+ if (conflict) {
+ printk(KERN_ERR "Received legacy SPC-2 RESERVE/RELEASE"
+ " while active SPC-3 registrations exist,"
+ " returning RESERVATION_CONFLICT\n");
+ return PYX_TRANSPORT_RESERVATION_CONFLICT;
+ }
+
+after_crh:
+ if ((cdb[0] == RESERVE) || (cdb[0] == RESERVE_10))
+ return core_scsi2_reservation_reserve(cmd);
+ else if ((cdb[0] == RELEASE) || (cdb[0] == RELEASE_10))
+ return core_scsi2_reservation_release(cmd);
+ else
+ return PYX_TRANSPORT_INVALID_CDB_FIELD;
+}
+
+/*
+ * Begin SPC-3/SPC-4 Persistent Reservations emulation support
+ *
+ * This function is called by those initiator ports who are *NOT*
+ * the active PR reservation holder when a reservation is present.
+ */
+static int core_scsi3_pr_seq_non_holder(
+ struct se_cmd *cmd,
+ unsigned char *cdb,
+ u32 pr_reg_type)
+{
+ struct se_dev_entry *se_deve;
+ struct se_session *se_sess = SE_SESS(cmd);
+ int other_cdb = 0, ignore_reg;
+ int registered_nexus = 0, ret = 1; /* Conflict by default */
+ int all_reg = 0, reg_only = 0; /* ALL_REG, REG_ONLY */
+ int we = 0; /* Write Exclusive */
+ int legacy = 0; /* Act like a legacy device and return
+ * RESERVATION CONFLICT on some CDBs */
+ /*
+ * A legacy SPC-2 reservation is being held.
+ */
+ if (cmd->se_dev->dev_flags & DF_SPC2_RESERVATIONS)
+ return core_scsi2_reservation_seq_non_holder(cmd,
+ cdb, pr_reg_type);
+
+ se_deve = &se_sess->se_node_acl->device_list[cmd->orig_fe_lun];
+ /*
+ * Determine if the registration should be ignored due to
+ * non-matching ISIDs in core_scsi3_pr_reservation_check().
+ */
+ ignore_reg = (pr_reg_type & 0x80000000);
+ if (ignore_reg)
+ pr_reg_type &= ~0x80000000;
+
+ switch (pr_reg_type) {
+ case PR_TYPE_WRITE_EXCLUSIVE:
+ we = 1;
+ case PR_TYPE_EXCLUSIVE_ACCESS:
+ /*
+ * Some commands are only allowed for the persistent reservation
+ * holder.
+ */
+ if ((se_deve->def_pr_registered) && !(ignore_reg))
+ registered_nexus = 1;
+ break;
+ case PR_TYPE_WRITE_EXCLUSIVE_REGONLY:
+ we = 1;
+ case PR_TYPE_EXCLUSIVE_ACCESS_REGONLY:
+ /*
+ * Some commands are only allowed for registered I_T Nexuses.
+ */
+ reg_only = 1;
+ if ((se_deve->def_pr_registered) && !(ignore_reg))
+ registered_nexus = 1;
+ break;
+ case PR_TYPE_WRITE_EXCLUSIVE_ALLREG:
+ we = 1;
+ case PR_TYPE_EXCLUSIVE_ACCESS_ALLREG:
+ /*
+ * Each registered I_T Nexus is a reservation holder.
+ */
+ all_reg = 1;
+ if ((se_deve->def_pr_registered) && !(ignore_reg))
+ registered_nexus = 1;
+ break;
+ default:
+ return -1;
+ }
+ /*
+ * Referenced from spc4r17 table 45 for *NON* PR holder access
+ */
+ switch (cdb[0]) {
+ case SECURITY_PROTOCOL_IN:
+ if (registered_nexus)
+ return 0;
+ ret = (we) ? 0 : 1;
+ break;
+ case MODE_SENSE:
+ case MODE_SENSE_10:
+ case READ_ATTRIBUTE:
+ case READ_BUFFER:
+ case RECEIVE_DIAGNOSTIC:
+ if (legacy) {
+ ret = 1;
+ break;
+ }
+ if (registered_nexus) {
+ ret = 0;
+ break;
+ }
+ ret = (we) ? 0 : 1; /* Allowed Write Exclusive */
+ break;
+ case PERSISTENT_RESERVE_OUT:
+ /*
+ * This follows PERSISTENT_RESERVE_OUT service actions that
+ * are allowed in the presence of various reservations.
+ * See spc4r17, table 46
+ */
+ switch (cdb[1] & 0x1f) {
+ case PRO_CLEAR:
+ case PRO_PREEMPT:
+ case PRO_PREEMPT_AND_ABORT:
+ ret = (registered_nexus) ? 0 : 1;
+ break;
+ case PRO_REGISTER:
+ case PRO_REGISTER_AND_IGNORE_EXISTING_KEY:
+ ret = 0;
+ break;
+ case PRO_REGISTER_AND_MOVE:
+ case PRO_RESERVE:
+ ret = 1;
+ break;
+ case PRO_RELEASE:
+ ret = (registered_nexus) ? 0 : 1;
+ break;
+ default:
+ printk(KERN_ERR "Unknown PERSISTENT_RESERVE_OUT service"
+ " action: 0x%02x\n", cdb[1] & 0x1f);
+ return -1;
+ }
+ break;
+ case RELEASE:
+ case RELEASE_10:
+ /* Handled by CRH=1 in core_scsi2_emulate_crh() */
+ ret = 0;
+ break;
+ case RESERVE:
+ case RESERVE_10:
+ /* Handled by CRH=1 in core_scsi2_emulate_crh() */
+ ret = 0;
+ break;
+ case TEST_UNIT_READY:
+ ret = (legacy) ? 1 : 0; /* Conflict for legacy */
+ break;
+ case MAINTENANCE_IN:
+ switch (cdb[1] & 0x1f) {
+ case MI_MANAGEMENT_PROTOCOL_IN:
+ if (registered_nexus) {
+ ret = 0;
+ break;
+ }
+ ret = (we) ? 0 : 1; /* Allowed Write Exclusive */
+ break;
+ case MI_REPORT_SUPPORTED_OPERATION_CODES:
+ case MI_REPORT_SUPPORTED_TASK_MANAGEMENT_FUNCTIONS:
+ if (legacy) {
+ ret = 1;
+ break;
+ }
+ if (registered_nexus) {
+ ret = 0;
+ break;
+ }
+ ret = (we) ? 0 : 1; /* Allowed Write Exclusive */
+ break;
+ case MI_REPORT_ALIASES:
+ case MI_REPORT_IDENTIFYING_INFORMATION:
+ case MI_REPORT_PRIORITY:
+ case MI_REPORT_TARGET_PGS:
+ case MI_REPORT_TIMESTAMP:
+ ret = 0; /* Allowed */
+ break;
+ default:
+ printk(KERN_ERR "Unknown MI Service Action: 0x%02x\n",
+ (cdb[1] & 0x1f));
+ return -1;
+ }
+ break;
+ case ACCESS_CONTROL_IN:
+ case ACCESS_CONTROL_OUT:
+ case INQUIRY:
+ case LOG_SENSE:
+ case READ_MEDIA_SERIAL_NUMBER:
+ case REPORT_LUNS:
+ case REQUEST_SENSE:
+ ret = 0; /*/ Allowed CDBs */
+ break;
+ default:
+ other_cdb = 1;
+ break;
+ }
+ /*
+ * Case where the CDB is explictly allowed in the above switch
+ * statement.
+ */
+ if (!(ret) && !(other_cdb)) {
+#if 0
+ printk(KERN_INFO "Allowing explict CDB: 0x%02x for %s"
+ " reservation holder\n", cdb[0],
+ core_scsi3_pr_dump_type(pr_reg_type));
+#endif
+ return ret;
+ }
+ /*
+ * Check if write exclusive initiator ports *NOT* holding the
+ * WRITE_EXCLUSIVE_* reservation.
+ */
+ if ((we) && !(registered_nexus)) {
+ if (cmd->data_direction == DMA_TO_DEVICE) {
+ /*
+ * Conflict for write exclusive
+ */
+ printk(KERN_INFO "%s Conflict for unregistered nexus"
+ " %s CDB: 0x%02x to %s reservation\n",
+ transport_dump_cmd_direction(cmd),
+ se_sess->se_node_acl->initiatorname, cdb[0],
+ core_scsi3_pr_dump_type(pr_reg_type));
+ return 1;
+ } else {
+ /*
+ * Allow non WRITE CDBs for all Write Exclusive
+ * PR TYPEs to pass for registered and
+ * non-registered_nexuxes NOT holding the reservation.
+ *
+ * We only make noise for the unregisterd nexuses,
+ * as we expect registered non-reservation holding
+ * nexuses to issue CDBs.
+ */
+#if 0
+ if (!(registered_nexus)) {
+ printk(KERN_INFO "Allowing implict CDB: 0x%02x"
+ " for %s reservation on unregistered"
+ " nexus\n", cdb[0],
+ core_scsi3_pr_dump_type(pr_reg_type));
+ }
+#endif
+ return 0;
+ }
+ } else if ((reg_only) || (all_reg)) {
+ if (registered_nexus) {
+ /*
+ * For PR_*_REG_ONLY and PR_*_ALL_REG reservations,
+ * allow commands from registered nexuses.
+ */
+#if 0
+ printk(KERN_INFO "Allowing implict CDB: 0x%02x for %s"
+ " reservation\n", cdb[0],
+ core_scsi3_pr_dump_type(pr_reg_type));
+#endif
+ return 0;
+ }
+ }
+ printk(KERN_INFO "%s Conflict for %sregistered nexus %s CDB: 0x%2x"
+ " for %s reservation\n", transport_dump_cmd_direction(cmd),
+ (registered_nexus) ? "" : "un",
+ se_sess->se_node_acl->initiatorname, cdb[0],
+ core_scsi3_pr_dump_type(pr_reg_type));
+
+ return 1; /* Conflict by default */
+}
+
+static u32 core_scsi3_pr_generation(struct se_device *dev)
+{
+ struct se_subsystem_dev *su_dev = SU_DEV(dev);
+ u32 prg;
+ /*
+ * PRGeneration field shall contain the value of a 32-bit wrapping
+ * counter mainted by the device server.
+ *
+ * Note that this is done regardless of Active Persist across
+ * Target PowerLoss (APTPL)
+ *
+ * See spc4r17 section 6.3.12 READ_KEYS service action
+ */
+ spin_lock(&dev->dev_reservation_lock);
+ prg = T10_RES(su_dev)->pr_generation++;
+ spin_unlock(&dev->dev_reservation_lock);
+
+ return prg;
+}
+
+static int core_scsi3_pr_reservation_check(
+ struct se_cmd *cmd,
+ u32 *pr_reg_type)
+{
+ struct se_device *dev = cmd->se_dev;
+ struct se_session *sess = cmd->se_sess;
+ int ret;
+
+ if (!(sess))
+ return 0;
+ /*
+ * A legacy SPC-2 reservation is being held.
+ */
+ if (dev->dev_flags & DF_SPC2_RESERVATIONS)
+ return core_scsi2_reservation_check(cmd, pr_reg_type);
+
+ spin_lock(&dev->dev_reservation_lock);
+ if (!(dev->dev_pr_res_holder)) {
+ spin_unlock(&dev->dev_reservation_lock);
+ return 0;
+ }
+ *pr_reg_type = dev->dev_pr_res_holder->pr_res_type;
+ cmd->pr_res_key = dev->dev_pr_res_holder->pr_res_key;
+ if (dev->dev_pr_res_holder->pr_reg_nacl != sess->se_node_acl) {
+ spin_unlock(&dev->dev_reservation_lock);
+ return -1;
+ }
+ if (!(dev->dev_pr_res_holder->isid_present_at_reg)) {
+ spin_unlock(&dev->dev_reservation_lock);
+ return 0;
+ }
+ ret = (dev->dev_pr_res_holder->pr_reg_bin_isid ==
+ sess->sess_bin_isid) ? 0 : -1;
+ /*
+ * Use bit in *pr_reg_type to notify ISID mismatch in
+ * core_scsi3_pr_seq_non_holder().
+ */
+ if (ret != 0)
+ *pr_reg_type |= 0x80000000;
+ spin_unlock(&dev->dev_reservation_lock);
+
+ return ret;
+}
+
+static struct t10_pr_registration *__core_scsi3_do_alloc_registration(
+ struct se_device *dev,
+ struct se_node_acl *nacl,
+ struct se_dev_entry *deve,
+ unsigned char *isid,
+ u64 sa_res_key,
+ int all_tg_pt,
+ int aptpl)
+{
+ struct se_subsystem_dev *su_dev = SU_DEV(dev);
+ struct t10_pr_registration *pr_reg;
+
+ pr_reg = kmem_cache_zalloc(t10_pr_reg_cache, GFP_ATOMIC);
+ if (!(pr_reg)) {
+ printk(KERN_ERR "Unable to allocate struct t10_pr_registration\n");
+ return NULL;
+ }
+
+ pr_reg->pr_aptpl_buf = kzalloc(T10_RES(su_dev)->pr_aptpl_buf_len,
+ GFP_ATOMIC);
+ if (!(pr_reg->pr_aptpl_buf)) {
+ printk(KERN_ERR "Unable to allocate pr_reg->pr_aptpl_buf\n");
+ kmem_cache_free(t10_pr_reg_cache, pr_reg);
+ return NULL;
+ }
+
+ INIT_LIST_HEAD(&pr_reg->pr_reg_list);
+ INIT_LIST_HEAD(&pr_reg->pr_reg_abort_list);
+ INIT_LIST_HEAD(&pr_reg->pr_reg_aptpl_list);
+ INIT_LIST_HEAD(&pr_reg->pr_reg_atp_list);
+ INIT_LIST_HEAD(&pr_reg->pr_reg_atp_mem_list);
+ atomic_set(&pr_reg->pr_res_holders, 0);
+ pr_reg->pr_reg_nacl = nacl;
+ pr_reg->pr_reg_deve = deve;
+ pr_reg->pr_res_mapped_lun = deve->mapped_lun;
+ pr_reg->pr_aptpl_target_lun = deve->se_lun->unpacked_lun;
+ pr_reg->pr_res_key = sa_res_key;
+ pr_reg->pr_reg_all_tg_pt = all_tg_pt;
+ pr_reg->pr_reg_aptpl = aptpl;
+ pr_reg->pr_reg_tg_pt_lun = deve->se_lun;
+ /*
+ * If an ISID value for this SCSI Initiator Port exists,
+ * save it to the registration now.
+ */
+ if (isid != NULL) {
+ pr_reg->pr_reg_bin_isid = get_unaligned_be64(isid);
+ snprintf(pr_reg->pr_reg_isid, PR_REG_ISID_LEN, "%s", isid);
+ pr_reg->isid_present_at_reg = 1;
+ }
+
+ return pr_reg;
+}
+
+static int core_scsi3_lunacl_depend_item(struct se_dev_entry *);
+static void core_scsi3_lunacl_undepend_item(struct se_dev_entry *);
+
+/*
+ * Function used for handling PR registrations for ALL_TG_PT=1 and ALL_TG_PT=0
+ * modes.
+ */
+static struct t10_pr_registration *__core_scsi3_alloc_registration(
+ struct se_device *dev,
+ struct se_node_acl *nacl,
+ struct se_dev_entry *deve,
+ unsigned char *isid,
+ u64 sa_res_key,
+ int all_tg_pt,
+ int aptpl)
+{
+ struct se_dev_entry *deve_tmp;
+ struct se_node_acl *nacl_tmp;
+ struct se_port *port, *port_tmp;
+ struct target_core_fabric_ops *tfo = nacl->se_tpg->se_tpg_tfo;
+ struct t10_pr_registration *pr_reg, *pr_reg_atp, *pr_reg_tmp, *pr_reg_tmp_safe;
+ int ret;
+ /*
+ * Create a registration for the I_T Nexus upon which the
+ * PROUT REGISTER was received.
+ */
+ pr_reg = __core_scsi3_do_alloc_registration(dev, nacl, deve, isid,
+ sa_res_key, all_tg_pt, aptpl);
+ if (!(pr_reg))
+ return NULL;
+ /*
+ * Return pointer to pr_reg for ALL_TG_PT=0
+ */
+ if (!(all_tg_pt))
+ return pr_reg;
+ /*
+ * Create list of matching SCSI Initiator Port registrations
+ * for ALL_TG_PT=1
+ */
+ spin_lock(&dev->se_port_lock);
+ list_for_each_entry_safe(port, port_tmp, &dev->dev_sep_list, sep_list) {
+ atomic_inc(&port->sep_tg_pt_ref_cnt);
+ smp_mb__after_atomic_inc();
+ spin_unlock(&dev->se_port_lock);
+
+ spin_lock_bh(&port->sep_alua_lock);
+ list_for_each_entry(deve_tmp, &port->sep_alua_list,
+ alua_port_list) {
+ /*
+ * This pointer will be NULL for demo mode MappedLUNs
+ * that have not been make explict via a ConfigFS
+ * MappedLUN group for the SCSI Initiator Node ACL.
+ */
+ if (!(deve_tmp->se_lun_acl))
+ continue;
+
+ nacl_tmp = deve_tmp->se_lun_acl->se_lun_nacl;
+ /*
+ * Skip the matching struct se_node_acl that is allocated
+ * above..
+ */
+ if (nacl == nacl_tmp)
+ continue;
+ /*
+ * Only perform PR registrations for target ports on
+ * the same fabric module as the REGISTER w/ ALL_TG_PT=1
+ * arrived.
+ */
+ if (tfo != nacl_tmp->se_tpg->se_tpg_tfo)
+ continue;
+ /*
+ * Look for a matching Initiator Node ACL in ASCII format
+ */
+ if (strcmp(nacl->initiatorname, nacl_tmp->initiatorname))
+ continue;
+
+ atomic_inc(&deve_tmp->pr_ref_count);
+ smp_mb__after_atomic_inc();
+ spin_unlock_bh(&port->sep_alua_lock);
+ /*
+ * Grab a configfs group dependency that is released
+ * for the exception path at label out: below, or upon
+ * completion of adding ALL_TG_PT=1 registrations in
+ * __core_scsi3_add_registration()
+ */
+ ret = core_scsi3_lunacl_depend_item(deve_tmp);
+ if (ret < 0) {
+ printk(KERN_ERR "core_scsi3_lunacl_depend"
+ "_item() failed\n");
+ atomic_dec(&port->sep_tg_pt_ref_cnt);
+ smp_mb__after_atomic_dec();
+ atomic_dec(&deve_tmp->pr_ref_count);
+ smp_mb__after_atomic_dec();
+ goto out;
+ }
+ /*
+ * Located a matching SCSI Initiator Port on a different
+ * port, allocate the pr_reg_atp and attach it to the
+ * pr_reg->pr_reg_atp_list that will be processed once
+ * the original *pr_reg is processed in
+ * __core_scsi3_add_registration()
+ */
+ pr_reg_atp = __core_scsi3_do_alloc_registration(dev,
+ nacl_tmp, deve_tmp, NULL,
+ sa_res_key, all_tg_pt, aptpl);
+ if (!(pr_reg_atp)) {
+ atomic_dec(&port->sep_tg_pt_ref_cnt);
+ smp_mb__after_atomic_dec();
+ atomic_dec(&deve_tmp->pr_ref_count);
+ smp_mb__after_atomic_dec();
+ core_scsi3_lunacl_undepend_item(deve_tmp);
+ goto out;
+ }
+
+ list_add_tail(&pr_reg_atp->pr_reg_atp_mem_list,
+ &pr_reg->pr_reg_atp_list);
+ spin_lock_bh(&port->sep_alua_lock);
+ }
+ spin_unlock_bh(&port->sep_alua_lock);
+
+ spin_lock(&dev->se_port_lock);
+ atomic_dec(&port->sep_tg_pt_ref_cnt);
+ smp_mb__after_atomic_dec();
+ }
+ spin_unlock(&dev->se_port_lock);
+
+ return pr_reg;
+out:
+ list_for_each_entry_safe(pr_reg_tmp, pr_reg_tmp_safe,
+ &pr_reg->pr_reg_atp_list, pr_reg_atp_mem_list) {
+ list_del(&pr_reg_tmp->pr_reg_atp_mem_list);
+ core_scsi3_lunacl_undepend_item(pr_reg_tmp->pr_reg_deve);
+ kmem_cache_free(t10_pr_reg_cache, pr_reg_tmp);
+ }
+ kmem_cache_free(t10_pr_reg_cache, pr_reg);
+ return NULL;
+}
+
+int core_scsi3_alloc_aptpl_registration(
+ struct t10_reservation_template *pr_tmpl,
+ u64 sa_res_key,
+ unsigned char *i_port,
+ unsigned char *isid,
+ u32 mapped_lun,
+ unsigned char *t_port,
+ u16 tpgt,
+ u32 target_lun,
+ int res_holder,
+ int all_tg_pt,
+ u8 type)
+{
+ struct t10_pr_registration *pr_reg;
+
+ if (!(i_port) || !(t_port) || !(sa_res_key)) {
+ printk(KERN_ERR "Illegal parameters for APTPL registration\n");
+ return -1;
+ }
+
+ pr_reg = kmem_cache_zalloc(t10_pr_reg_cache, GFP_KERNEL);
+ if (!(pr_reg)) {
+ printk(KERN_ERR "Unable to allocate struct t10_pr_registration\n");
+ return -1;
+ }
+ pr_reg->pr_aptpl_buf = kzalloc(pr_tmpl->pr_aptpl_buf_len, GFP_KERNEL);
+
+ INIT_LIST_HEAD(&pr_reg->pr_reg_list);
+ INIT_LIST_HEAD(&pr_reg->pr_reg_abort_list);
+ INIT_LIST_HEAD(&pr_reg->pr_reg_aptpl_list);
+ INIT_LIST_HEAD(&pr_reg->pr_reg_atp_list);
+ INIT_LIST_HEAD(&pr_reg->pr_reg_atp_mem_list);
+ atomic_set(&pr_reg->pr_res_holders, 0);
+ pr_reg->pr_reg_nacl = NULL;
+ pr_reg->pr_reg_deve = NULL;
+ pr_reg->pr_res_mapped_lun = mapped_lun;
+ pr_reg->pr_aptpl_target_lun = target_lun;
+ pr_reg->pr_res_key = sa_res_key;
+ pr_reg->pr_reg_all_tg_pt = all_tg_pt;
+ pr_reg->pr_reg_aptpl = 1;
+ pr_reg->pr_reg_tg_pt_lun = NULL;
+ pr_reg->pr_res_scope = 0; /* Always LUN_SCOPE */
+ pr_reg->pr_res_type = type;
+ /*
+ * If an ISID value had been saved in APTPL metadata for this
+ * SCSI Initiator Port, restore it now.
+ */
+ if (isid != NULL) {
+ pr_reg->pr_reg_bin_isid = get_unaligned_be64(isid);
+ snprintf(pr_reg->pr_reg_isid, PR_REG_ISID_LEN, "%s", isid);
+ pr_reg->isid_present_at_reg = 1;
+ }
+ /*
+ * Copy the i_port and t_port information from caller.
+ */
+ snprintf(pr_reg->pr_iport, PR_APTPL_MAX_IPORT_LEN, "%s", i_port);
+ snprintf(pr_reg->pr_tport, PR_APTPL_MAX_TPORT_LEN, "%s", t_port);
+ pr_reg->pr_reg_tpgt = tpgt;
+ /*
+ * Set pr_res_holder from caller, the pr_reg who is the reservation
+ * holder will get it's pointer set in core_scsi3_aptpl_reserve() once
+ * the Initiator Node LUN ACL from the fabric module is created for
+ * this registration.
+ */
+ pr_reg->pr_res_holder = res_holder;
+
+ list_add_tail(&pr_reg->pr_reg_aptpl_list, &pr_tmpl->aptpl_reg_list);
+ printk(KERN_INFO "SPC-3 PR APTPL Successfully added registration%s from"
+ " metadata\n", (res_holder) ? "+reservation" : "");
+ return 0;
+}
+
+static void core_scsi3_aptpl_reserve(
+ struct se_device *dev,
+ struct se_portal_group *tpg,
+ struct se_node_acl *node_acl,
+ struct t10_pr_registration *pr_reg)
+{
+ char i_buf[PR_REG_ISID_ID_LEN];
+ int prf_isid;
+
+ memset(i_buf, 0, PR_REG_ISID_ID_LEN);
+ prf_isid = core_pr_dump_initiator_port(pr_reg, &i_buf[0],
+ PR_REG_ISID_ID_LEN);
+
+ spin_lock(&dev->dev_reservation_lock);
+ dev->dev_pr_res_holder = pr_reg;
+ spin_unlock(&dev->dev_reservation_lock);
+
+ printk(KERN_INFO "SPC-3 PR [%s] Service Action: APTPL RESERVE created"
+ " new reservation holder TYPE: %s ALL_TG_PT: %d\n",
+ TPG_TFO(tpg)->get_fabric_name(),
+ core_scsi3_pr_dump_type(pr_reg->pr_res_type),
+ (pr_reg->pr_reg_all_tg_pt) ? 1 : 0);
+ printk(KERN_INFO "SPC-3 PR [%s] RESERVE Node: %s%s\n",
+ TPG_TFO(tpg)->get_fabric_name(), node_acl->initiatorname,
+ (prf_isid) ? &i_buf[0] : "");
+}
+
+static void __core_scsi3_add_registration(struct se_device *, struct se_node_acl *,
+ struct t10_pr_registration *, int, int);
+
+static int __core_scsi3_check_aptpl_registration(
+ struct se_device *dev,
+ struct se_portal_group *tpg,
+ struct se_lun *lun,
+ u32 target_lun,
+ struct se_node_acl *nacl,
+ struct se_dev_entry *deve)
+{
+ struct t10_pr_registration *pr_reg, *pr_reg_tmp;
+ struct t10_reservation_template *pr_tmpl = &SU_DEV(dev)->t10_reservation;
+ unsigned char i_port[PR_APTPL_MAX_IPORT_LEN];
+ unsigned char t_port[PR_APTPL_MAX_TPORT_LEN];
+ u16 tpgt;
+
+ memset(i_port, 0, PR_APTPL_MAX_IPORT_LEN);
+ memset(t_port, 0, PR_APTPL_MAX_TPORT_LEN);
+ /*
+ * Copy Initiator Port information from struct se_node_acl
+ */
+ snprintf(i_port, PR_APTPL_MAX_IPORT_LEN, "%s", nacl->initiatorname);
+ snprintf(t_port, PR_APTPL_MAX_TPORT_LEN, "%s",
+ TPG_TFO(tpg)->tpg_get_wwn(tpg));
+ tpgt = TPG_TFO(tpg)->tpg_get_tag(tpg);
+ /*
+ * Look for the matching registrations+reservation from those
+ * created from APTPL metadata. Note that multiple registrations
+ * may exist for fabrics that use ISIDs in their SCSI Initiator Port
+ * TransportIDs.
+ */
+ spin_lock(&pr_tmpl->aptpl_reg_lock);
+ list_for_each_entry_safe(pr_reg, pr_reg_tmp, &pr_tmpl->aptpl_reg_list,
+ pr_reg_aptpl_list) {
+ if (!(strcmp(pr_reg->pr_iport, i_port)) &&
+ (pr_reg->pr_res_mapped_lun == deve->mapped_lun) &&
+ !(strcmp(pr_reg->pr_tport, t_port)) &&
+ (pr_reg->pr_reg_tpgt == tpgt) &&
+ (pr_reg->pr_aptpl_target_lun == target_lun)) {
+
+ pr_reg->pr_reg_nacl = nacl;
+ pr_reg->pr_reg_deve = deve;
+ pr_reg->pr_reg_tg_pt_lun = lun;
+
+ list_del(&pr_reg->pr_reg_aptpl_list);
+ spin_unlock(&pr_tmpl->aptpl_reg_lock);
+ /*
+ * At this point all of the pointers in *pr_reg will
+ * be setup, so go ahead and add the registration.
+ */
+
+ __core_scsi3_add_registration(dev, nacl, pr_reg, 0, 0);
+ /*
+ * If this registration is the reservation holder,
+ * make that happen now..
+ */
+ if (pr_reg->pr_res_holder)
+ core_scsi3_aptpl_reserve(dev, tpg,
+ nacl, pr_reg);
+ /*
+ * Reenable pr_aptpl_active to accept new metadata
+ * updates once the SCSI device is active again..
+ */
+ spin_lock(&pr_tmpl->aptpl_reg_lock);
+ pr_tmpl->pr_aptpl_active = 1;
+ }
+ }
+ spin_unlock(&pr_tmpl->aptpl_reg_lock);
+
+ return 0;
+}
+
+int core_scsi3_check_aptpl_registration(
+ struct se_device *dev,
+ struct se_portal_group *tpg,
+ struct se_lun *lun,
+ struct se_lun_acl *lun_acl)
+{
+ struct se_subsystem_dev *su_dev = SU_DEV(dev);
+ struct se_node_acl *nacl = lun_acl->se_lun_nacl;
+ struct se_dev_entry *deve = &nacl->device_list[lun_acl->mapped_lun];
+
+ if (T10_RES(su_dev)->res_type != SPC3_PERSISTENT_RESERVATIONS)
+ return 0;
+
+ return __core_scsi3_check_aptpl_registration(dev, tpg, lun,
+ lun->unpacked_lun, nacl, deve);
+}
+
+static void __core_scsi3_dump_registration(
+ struct target_core_fabric_ops *tfo,
+ struct se_device *dev,
+ struct se_node_acl *nacl,
+ struct t10_pr_registration *pr_reg,
+ int register_type)
+{
+ struct se_portal_group *se_tpg = nacl->se_tpg;
+ char i_buf[PR_REG_ISID_ID_LEN];
+ int prf_isid;
+
+ memset(&i_buf[0], 0, PR_REG_ISID_ID_LEN);
+ prf_isid = core_pr_dump_initiator_port(pr_reg, &i_buf[0],
+ PR_REG_ISID_ID_LEN);
+
+ printk(KERN_INFO "SPC-3 PR [%s] Service Action: REGISTER%s Initiator"
+ " Node: %s%s\n", tfo->get_fabric_name(), (register_type == 2) ?
+ "_AND_MOVE" : (register_type == 1) ?
+ "_AND_IGNORE_EXISTING_KEY" : "", nacl->initiatorname,
+ (prf_isid) ? i_buf : "");
+ printk(KERN_INFO "SPC-3 PR [%s] registration on Target Port: %s,0x%04x\n",
+ tfo->get_fabric_name(), tfo->tpg_get_wwn(se_tpg),
+ tfo->tpg_get_tag(se_tpg));
+ printk(KERN_INFO "SPC-3 PR [%s] for %s TCM Subsystem %s Object Target"
+ " Port(s)\n", tfo->get_fabric_name(),
+ (pr_reg->pr_reg_all_tg_pt) ? "ALL" : "SINGLE",
+ TRANSPORT(dev)->name);
+ printk(KERN_INFO "SPC-3 PR [%s] SA Res Key: 0x%016Lx PRgeneration:"
+ " 0x%08x APTPL: %d\n", tfo->get_fabric_name(),
+ pr_reg->pr_res_key, pr_reg->pr_res_generation,
+ pr_reg->pr_reg_aptpl);
+}
+
+/*
+ * this function can be called with struct se_device->dev_reservation_lock
+ * when register_move = 1
+ */
+static void __core_scsi3_add_registration(
+ struct se_device *dev,
+ struct se_node_acl *nacl,
+ struct t10_pr_registration *pr_reg,
+ int register_type,
+ int register_move)
+{
+ struct se_subsystem_dev *su_dev = SU_DEV(dev);
+ struct target_core_fabric_ops *tfo = nacl->se_tpg->se_tpg_tfo;
+ struct t10_pr_registration *pr_reg_tmp, *pr_reg_tmp_safe;
+ struct t10_reservation_template *pr_tmpl = &SU_DEV(dev)->t10_reservation;
+
+ /*
+ * Increment PRgeneration counter for struct se_device upon a successful
+ * REGISTER, see spc4r17 section 6.3.2 READ_KEYS service action
+ *
+ * Also, when register_move = 1 for PROUT REGISTER_AND_MOVE service
+ * action, the struct se_device->dev_reservation_lock will already be held,
+ * so we do not call core_scsi3_pr_generation() which grabs the lock
+ * for the REGISTER.
+ */
+ pr_reg->pr_res_generation = (register_move) ?
+ T10_RES(su_dev)->pr_generation++ :
+ core_scsi3_pr_generation(dev);
+
+ spin_lock(&pr_tmpl->registration_lock);
+ list_add_tail(&pr_reg->pr_reg_list, &pr_tmpl->registration_list);
+ pr_reg->pr_reg_deve->def_pr_registered = 1;
+
+ __core_scsi3_dump_registration(tfo, dev, nacl, pr_reg, register_type);
+ spin_unlock(&pr_tmpl->registration_lock);
+ /*
+ * Skip extra processing for ALL_TG_PT=0 or REGISTER_AND_MOVE.
+ */
+ if (!(pr_reg->pr_reg_all_tg_pt) || (register_move))
+ return;
+ /*
+ * Walk pr_reg->pr_reg_atp_list and add registrations for ALL_TG_PT=1
+ * allocated in __core_scsi3_alloc_registration()
+ */
+ list_for_each_entry_safe(pr_reg_tmp, pr_reg_tmp_safe,
+ &pr_reg->pr_reg_atp_list, pr_reg_atp_mem_list) {
+ list_del(&pr_reg_tmp->pr_reg_atp_mem_list);
+
+ pr_reg_tmp->pr_res_generation = core_scsi3_pr_generation(dev);
+
+ spin_lock(&pr_tmpl->registration_lock);
+ list_add_tail(&pr_reg_tmp->pr_reg_list,
+ &pr_tmpl->registration_list);
+ pr_reg_tmp->pr_reg_deve->def_pr_registered = 1;
+
+ __core_scsi3_dump_registration(tfo, dev,
+ pr_reg_tmp->pr_reg_nacl, pr_reg_tmp,
+ register_type);
+ spin_unlock(&pr_tmpl->registration_lock);
+ /*
+ * Drop configfs group dependency reference from
+ * __core_scsi3_alloc_registration()
+ */
+ core_scsi3_lunacl_undepend_item(pr_reg_tmp->pr_reg_deve);
+ }
+}
+
+static int core_scsi3_alloc_registration(
+ struct se_device *dev,
+ struct se_node_acl *nacl,
+ struct se_dev_entry *deve,
+ unsigned char *isid,
+ u64 sa_res_key,
+ int all_tg_pt,
+ int aptpl,
+ int register_type,
+ int register_move)
+{
+ struct t10_pr_registration *pr_reg;
+
+ pr_reg = __core_scsi3_alloc_registration(dev, nacl, deve, isid,
+ sa_res_key, all_tg_pt, aptpl);
+ if (!(pr_reg))
+ return -1;
+
+ __core_scsi3_add_registration(dev, nacl, pr_reg,
+ register_type, register_move);
+ return 0;
+}
+
+static struct t10_pr_registration *__core_scsi3_locate_pr_reg(
+ struct se_device *dev,
+ struct se_node_acl *nacl,
+ unsigned char *isid)
+{
+ struct t10_reservation_template *pr_tmpl = &SU_DEV(dev)->t10_reservation;
+ struct t10_pr_registration *pr_reg, *pr_reg_tmp;
+ struct se_portal_group *tpg;
+
+ spin_lock(&pr_tmpl->registration_lock);
+ list_for_each_entry_safe(pr_reg, pr_reg_tmp,
+ &pr_tmpl->registration_list, pr_reg_list) {
+ /*
+ * First look for a matching struct se_node_acl
+ */
+ if (pr_reg->pr_reg_nacl != nacl)
+ continue;
+
+ tpg = pr_reg->pr_reg_nacl->se_tpg;
+ /*
+ * If this registration does NOT contain a fabric provided
+ * ISID, then we have found a match.
+ */
+ if (!(pr_reg->isid_present_at_reg)) {
+ /*
+ * Determine if this SCSI device server requires that
+ * SCSI Intiatior TransportID w/ ISIDs is enforced
+ * for fabric modules (iSCSI) requiring them.
+ */
+ if (TPG_TFO(tpg)->sess_get_initiator_sid != NULL) {
+ if (DEV_ATTRIB(dev)->enforce_pr_isids)
+ continue;
+ }
+ atomic_inc(&pr_reg->pr_res_holders);
+ smp_mb__after_atomic_inc();
+ spin_unlock(&pr_tmpl->registration_lock);
+ return pr_reg;
+ }
+ /*
+ * If the *pr_reg contains a fabric defined ISID for multi-value
+ * SCSI Initiator Port TransportIDs, then we expect a valid
+ * matching ISID to be provided by the local SCSI Initiator Port.
+ */
+ if (!(isid))
+ continue;
+ if (strcmp(isid, pr_reg->pr_reg_isid))
+ continue;
+
+ atomic_inc(&pr_reg->pr_res_holders);
+ smp_mb__after_atomic_inc();
+ spin_unlock(&pr_tmpl->registration_lock);
+ return pr_reg;
+ }
+ spin_unlock(&pr_tmpl->registration_lock);
+
+ return NULL;
+}
+
+static struct t10_pr_registration *core_scsi3_locate_pr_reg(
+ struct se_device *dev,
+ struct se_node_acl *nacl,
+ struct se_session *sess)
+{
+ struct se_portal_group *tpg = nacl->se_tpg;
+ unsigned char buf[PR_REG_ISID_LEN], *isid_ptr = NULL;
+
+ if (TPG_TFO(tpg)->sess_get_initiator_sid != NULL) {
+ memset(&buf[0], 0, PR_REG_ISID_LEN);
+ TPG_TFO(tpg)->sess_get_initiator_sid(sess, &buf[0],
+ PR_REG_ISID_LEN);
+ isid_ptr = &buf[0];
+ }
+
+ return __core_scsi3_locate_pr_reg(dev, nacl, isid_ptr);
+}
+
+static void core_scsi3_put_pr_reg(struct t10_pr_registration *pr_reg)
+{
+ atomic_dec(&pr_reg->pr_res_holders);
+ smp_mb__after_atomic_dec();
+}
+
+static int core_scsi3_check_implict_release(
+ struct se_device *dev,
+ struct t10_pr_registration *pr_reg)
+{
+ struct se_node_acl *nacl = pr_reg->pr_reg_nacl;
+ struct t10_pr_registration *pr_res_holder;
+ int ret = 0;
+
+ spin_lock(&dev->dev_reservation_lock);
+ pr_res_holder = dev->dev_pr_res_holder;
+ if (!(pr_res_holder)) {
+ spin_unlock(&dev->dev_reservation_lock);
+ return ret;
+ }
+ if (pr_res_holder == pr_reg) {
+ /*
+ * Perform an implict RELEASE if the registration that
+ * is being released is holding the reservation.
+ *
+ * From spc4r17, section 5.7.11.1:
+ *
+ * e) If the I_T nexus is the persistent reservation holder
+ * and the persistent reservation is not an all registrants
+ * type, then a PERSISTENT RESERVE OUT command with REGISTER
+ * service action or REGISTER AND IGNORE EXISTING KEY
+ * service action with the SERVICE ACTION RESERVATION KEY
+ * field set to zero (see 5.7.11.3).
+ */
+ __core_scsi3_complete_pro_release(dev, nacl, pr_reg, 0);
+ ret = 1;
+ /*
+ * For 'All Registrants' reservation types, all existing
+ * registrations are still processed as reservation holders
+ * in core_scsi3_pr_seq_non_holder() after the initial
+ * reservation holder is implictly released here.
+ */
+ } else if (pr_reg->pr_reg_all_tg_pt &&
+ (!strcmp(pr_res_holder->pr_reg_nacl->initiatorname,
+ pr_reg->pr_reg_nacl->initiatorname)) &&
+ (pr_res_holder->pr_res_key == pr_reg->pr_res_key)) {
+ printk(KERN_ERR "SPC-3 PR: Unable to perform ALL_TG_PT=1"
+ " UNREGISTER while existing reservation with matching"
+ " key 0x%016Lx is present from another SCSI Initiator"
+ " Port\n", pr_reg->pr_res_key);
+ ret = -1;
+ }
+ spin_unlock(&dev->dev_reservation_lock);
+
+ return ret;
+}
+
+/*
+ * Called with struct t10_reservation_template->registration_lock held.
+ */
+static void __core_scsi3_free_registration(
+ struct se_device *dev,
+ struct t10_pr_registration *pr_reg,
+ struct list_head *preempt_and_abort_list,
+ int dec_holders)
+{
+ struct target_core_fabric_ops *tfo =
+ pr_reg->pr_reg_nacl->se_tpg->se_tpg_tfo;
+ struct t10_reservation_template *pr_tmpl = &SU_DEV(dev)->t10_reservation;
+ char i_buf[PR_REG_ISID_ID_LEN];
+ int prf_isid;
+
+ memset(i_buf, 0, PR_REG_ISID_ID_LEN);
+ prf_isid = core_pr_dump_initiator_port(pr_reg, &i_buf[0],
+ PR_REG_ISID_ID_LEN);
+
+ pr_reg->pr_reg_deve->def_pr_registered = 0;
+ pr_reg->pr_reg_deve->pr_res_key = 0;
+ list_del(&pr_reg->pr_reg_list);
+ /*
+ * Caller accessing *pr_reg using core_scsi3_locate_pr_reg(),
+ * so call core_scsi3_put_pr_reg() to decrement our reference.
+ */
+ if (dec_holders)
+ core_scsi3_put_pr_reg(pr_reg);
+ /*
+ * Wait until all reference from any other I_T nexuses for this
+ * *pr_reg have been released. Because list_del() is called above,
+ * the last core_scsi3_put_pr_reg(pr_reg) will release this reference
+ * count back to zero, and we release *pr_reg.
+ */
+ while (atomic_read(&pr_reg->pr_res_holders) != 0) {
+ spin_unlock(&pr_tmpl->registration_lock);
+ printk("SPC-3 PR [%s] waiting for pr_res_holders\n",
+ tfo->get_fabric_name());
+ cpu_relax();
+ spin_lock(&pr_tmpl->registration_lock);
+ }
+
+ printk(KERN_INFO "SPC-3 PR [%s] Service Action: UNREGISTER Initiator"
+ " Node: %s%s\n", tfo->get_fabric_name(),
+ pr_reg->pr_reg_nacl->initiatorname,
+ (prf_isid) ? &i_buf[0] : "");
+ printk(KERN_INFO "SPC-3 PR [%s] for %s TCM Subsystem %s Object Target"
+ " Port(s)\n", tfo->get_fabric_name(),
+ (pr_reg->pr_reg_all_tg_pt) ? "ALL" : "SINGLE",
+ TRANSPORT(dev)->name);
+ printk(KERN_INFO "SPC-3 PR [%s] SA Res Key: 0x%016Lx PRgeneration:"
+ " 0x%08x\n", tfo->get_fabric_name(), pr_reg->pr_res_key,
+ pr_reg->pr_res_generation);
+
+ if (!(preempt_and_abort_list)) {
+ pr_reg->pr_reg_deve = NULL;
+ pr_reg->pr_reg_nacl = NULL;
+ kfree(pr_reg->pr_aptpl_buf);
+ kmem_cache_free(t10_pr_reg_cache, pr_reg);
+ return;
+ }
+ /*
+ * For PREEMPT_AND_ABORT, the list of *pr_reg in preempt_and_abort_list
+ * are released once the ABORT_TASK_SET has completed..
+ */
+ list_add_tail(&pr_reg->pr_reg_abort_list, preempt_and_abort_list);
+}
+
+void core_scsi3_free_pr_reg_from_nacl(
+ struct se_device *dev,
+ struct se_node_acl *nacl)
+{
+ struct t10_reservation_template *pr_tmpl = &SU_DEV(dev)->t10_reservation;
+ struct t10_pr_registration *pr_reg, *pr_reg_tmp, *pr_res_holder;
+ /*
+ * If the passed se_node_acl matches the reservation holder,
+ * release the reservation.
+ */
+ spin_lock(&dev->dev_reservation_lock);
+ pr_res_holder = dev->dev_pr_res_holder;
+ if ((pr_res_holder != NULL) &&
+ (pr_res_holder->pr_reg_nacl == nacl))
+ __core_scsi3_complete_pro_release(dev, nacl, pr_res_holder, 0);
+ spin_unlock(&dev->dev_reservation_lock);
+ /*
+ * Release any registration associated with the struct se_node_acl.
+ */
+ spin_lock(&pr_tmpl->registration_lock);
+ list_for_each_entry_safe(pr_reg, pr_reg_tmp,
+ &pr_tmpl->registration_list, pr_reg_list) {
+
+ if (pr_reg->pr_reg_nacl != nacl)
+ continue;
+
+ __core_scsi3_free_registration(dev, pr_reg, NULL, 0);
+ }
+ spin_unlock(&pr_tmpl->registration_lock);
+}
+
+void core_scsi3_free_all_registrations(
+ struct se_device *dev)
+{
+ struct t10_reservation_template *pr_tmpl = &SU_DEV(dev)->t10_reservation;
+ struct t10_pr_registration *pr_reg, *pr_reg_tmp, *pr_res_holder;
+
+ spin_lock(&dev->dev_reservation_lock);
+ pr_res_holder = dev->dev_pr_res_holder;
+ if (pr_res_holder != NULL) {
+ struct se_node_acl *pr_res_nacl = pr_res_holder->pr_reg_nacl;
+ __core_scsi3_complete_pro_release(dev, pr_res_nacl,
+ pr_res_holder, 0);
+ }
+ spin_unlock(&dev->dev_reservation_lock);
+
+ spin_lock(&pr_tmpl->registration_lock);
+ list_for_each_entry_safe(pr_reg, pr_reg_tmp,
+ &pr_tmpl->registration_list, pr_reg_list) {
+
+ __core_scsi3_free_registration(dev, pr_reg, NULL, 0);
+ }
+ spin_unlock(&pr_tmpl->registration_lock);
+
+ spin_lock(&pr_tmpl->aptpl_reg_lock);
+ list_for_each_entry_safe(pr_reg, pr_reg_tmp, &pr_tmpl->aptpl_reg_list,
+ pr_reg_aptpl_list) {
+ list_del(&pr_reg->pr_reg_aptpl_list);
+ kfree(pr_reg->pr_aptpl_buf);
+ kmem_cache_free(t10_pr_reg_cache, pr_reg);
+ }
+ spin_unlock(&pr_tmpl->aptpl_reg_lock);
+}
+
+static int core_scsi3_tpg_depend_item(struct se_portal_group *tpg)
+{
+ return configfs_depend_item(TPG_TFO(tpg)->tf_subsys,
+ &tpg->tpg_group.cg_item);
+}
+
+static void core_scsi3_tpg_undepend_item(struct se_portal_group *tpg)
+{
+ configfs_undepend_item(TPG_TFO(tpg)->tf_subsys,
+ &tpg->tpg_group.cg_item);
+
+ atomic_dec(&tpg->tpg_pr_ref_count);
+ smp_mb__after_atomic_dec();
+}
+
+static int core_scsi3_nodeacl_depend_item(struct se_node_acl *nacl)
+{
+ struct se_portal_group *tpg = nacl->se_tpg;
+
+ if (nacl->dynamic_node_acl)
+ return 0;
+
+ return configfs_depend_item(TPG_TFO(tpg)->tf_subsys,
+ &nacl->acl_group.cg_item);
+}
+
+static void core_scsi3_nodeacl_undepend_item(struct se_node_acl *nacl)
+{
+ struct se_portal_group *tpg = nacl->se_tpg;
+
+ if (nacl->dynamic_node_acl) {
+ atomic_dec(&nacl->acl_pr_ref_count);
+ smp_mb__after_atomic_dec();
+ return;
+ }
+
+ configfs_undepend_item(TPG_TFO(tpg)->tf_subsys,
+ &nacl->acl_group.cg_item);
+
+ atomic_dec(&nacl->acl_pr_ref_count);
+ smp_mb__after_atomic_dec();
+}
+
+static int core_scsi3_lunacl_depend_item(struct se_dev_entry *se_deve)
+{
+ struct se_lun_acl *lun_acl = se_deve->se_lun_acl;
+ struct se_node_acl *nacl;
+ struct se_portal_group *tpg;
+ /*
+ * For nacl->dynamic_node_acl=1
+ */
+ if (!(lun_acl))
+ return 0;
+
+ nacl = lun_acl->se_lun_nacl;
+ tpg = nacl->se_tpg;
+
+ return configfs_depend_item(TPG_TFO(tpg)->tf_subsys,
+ &lun_acl->se_lun_group.cg_item);
+}
+
+static void core_scsi3_lunacl_undepend_item(struct se_dev_entry *se_deve)
+{
+ struct se_lun_acl *lun_acl = se_deve->se_lun_acl;
+ struct se_node_acl *nacl;
+ struct se_portal_group *tpg;
+ /*
+ * For nacl->dynamic_node_acl=1
+ */
+ if (!(lun_acl)) {
+ atomic_dec(&se_deve->pr_ref_count);
+ smp_mb__after_atomic_dec();
+ return;
+ }
+ nacl = lun_acl->se_lun_nacl;
+ tpg = nacl->se_tpg;
+
+ configfs_undepend_item(TPG_TFO(tpg)->tf_subsys,
+ &lun_acl->se_lun_group.cg_item);
+
+ atomic_dec(&se_deve->pr_ref_count);
+ smp_mb__after_atomic_dec();
+}
+
+static int core_scsi3_decode_spec_i_port(
+ struct se_cmd *cmd,
+ struct se_portal_group *tpg,
+ unsigned char *l_isid,
+ u64 sa_res_key,
+ int all_tg_pt,
+ int aptpl)
+{
+ struct se_device *dev = SE_DEV(cmd);
+ struct se_port *tmp_port;
+ struct se_portal_group *dest_tpg = NULL, *tmp_tpg;
+ struct se_session *se_sess = SE_SESS(cmd);
+ struct se_node_acl *dest_node_acl = NULL;
+ struct se_dev_entry *dest_se_deve = NULL, *local_se_deve;
+ struct t10_pr_registration *dest_pr_reg, *local_pr_reg, *pr_reg_e;
+ struct t10_pr_registration *pr_reg_tmp, *pr_reg_tmp_safe;
+ struct list_head tid_dest_list;
+ struct pr_transport_id_holder *tidh_new, *tidh, *tidh_tmp;
+ struct target_core_fabric_ops *tmp_tf_ops;
+ unsigned char *buf = (unsigned char *)T_TASK(cmd)->t_task_buf;
+ unsigned char *ptr, *i_str = NULL, proto_ident, tmp_proto_ident;
+ char *iport_ptr = NULL, dest_iport[64], i_buf[PR_REG_ISID_ID_LEN];
+ u32 tpdl, tid_len = 0;
+ int ret, dest_local_nexus, prf_isid;
+ u32 dest_rtpi = 0;
+
+ memset(dest_iport, 0, 64);
+ INIT_LIST_HEAD(&tid_dest_list);
+
+ local_se_deve = &se_sess->se_node_acl->device_list[cmd->orig_fe_lun];
+ /*
+ * Allocate a struct pr_transport_id_holder and setup the
+ * local_node_acl and local_se_deve pointers and add to
+ * struct list_head tid_dest_list for add registration
+ * processing in the loop of tid_dest_list below.
+ */
+ tidh_new = kzalloc(sizeof(struct pr_transport_id_holder), GFP_KERNEL);
+ if (!(tidh_new)) {
+ printk(KERN_ERR "Unable to allocate tidh_new\n");
+ return PYX_TRANSPORT_LU_COMM_FAILURE;
+ }
+ INIT_LIST_HEAD(&tidh_new->dest_list);
+ tidh_new->dest_tpg = tpg;
+ tidh_new->dest_node_acl = se_sess->se_node_acl;
+ tidh_new->dest_se_deve = local_se_deve;
+
+ local_pr_reg = __core_scsi3_alloc_registration(SE_DEV(cmd),
+ se_sess->se_node_acl, local_se_deve, l_isid,
+ sa_res_key, all_tg_pt, aptpl);
+ if (!(local_pr_reg)) {
+ kfree(tidh_new);
+ return PYX_TRANSPORT_LU_COMM_FAILURE;
+ }
+ tidh_new->dest_pr_reg = local_pr_reg;
+ /*
+ * The local I_T nexus does not hold any configfs dependances,
+ * so we set tid_h->dest_local_nexus=1 to prevent the
+ * configfs_undepend_item() calls in the tid_dest_list loops below.
+ */
+ tidh_new->dest_local_nexus = 1;
+ list_add_tail(&tidh_new->dest_list, &tid_dest_list);
+ /*
+ * For a PERSISTENT RESERVE OUT specify initiator ports payload,
+ * first extract TransportID Parameter Data Length, and make sure
+ * the value matches up to the SCSI expected data transfer length.
+ */
+ tpdl = (buf[24] & 0xff) << 24;
+ tpdl |= (buf[25] & 0xff) << 16;
+ tpdl |= (buf[26] & 0xff) << 8;
+ tpdl |= buf[27] & 0xff;
+
+ if ((tpdl + 28) != cmd->data_length) {
+ printk(KERN_ERR "SPC-3 PR: Illegal tpdl: %u + 28 byte header"
+ " does not equal CDB data_length: %u\n", tpdl,
+ cmd->data_length);
+ ret = PYX_TRANSPORT_INVALID_PARAMETER_LIST;
+ goto out;
+ }
+ /*
+ * Start processing the received transport IDs using the
+ * receiving I_T Nexus portal's fabric dependent methods to
+ * obtain the SCSI Initiator Port/Device Identifiers.
+ */
+ ptr = &buf[28];
+
+ while (tpdl > 0) {
+ proto_ident = (ptr[0] & 0x0f);
+ dest_tpg = NULL;
+
+ spin_lock(&dev->se_port_lock);
+ list_for_each_entry(tmp_port, &dev->dev_sep_list, sep_list) {
+ tmp_tpg = tmp_port->sep_tpg;
+ if (!(tmp_tpg))
+ continue;
+ tmp_tf_ops = TPG_TFO(tmp_tpg);
+ if (!(tmp_tf_ops))
+ continue;
+ if (!(tmp_tf_ops->get_fabric_proto_ident) ||
+ !(tmp_tf_ops->tpg_parse_pr_out_transport_id))
+ continue;
+ /*
+ * Look for the matching proto_ident provided by
+ * the received TransportID
+ */
+ tmp_proto_ident = tmp_tf_ops->get_fabric_proto_ident(tmp_tpg);
+ if (tmp_proto_ident != proto_ident)
+ continue;
+ dest_rtpi = tmp_port->sep_rtpi;
+
+ i_str = tmp_tf_ops->tpg_parse_pr_out_transport_id(
+ tmp_tpg, (const char *)ptr, &tid_len,
+ &iport_ptr);
+ if (!(i_str))
+ continue;
+
+ atomic_inc(&tmp_tpg->tpg_pr_ref_count);
+ smp_mb__after_atomic_inc();
+ spin_unlock(&dev->se_port_lock);
+
+ ret = core_scsi3_tpg_depend_item(tmp_tpg);
+ if (ret != 0) {
+ printk(KERN_ERR " core_scsi3_tpg_depend_item()"
+ " for tmp_tpg\n");
+ atomic_dec(&tmp_tpg->tpg_pr_ref_count);
+ smp_mb__after_atomic_dec();
+ ret = PYX_TRANSPORT_LU_COMM_FAILURE;
+ goto out;
+ }
+ /*
+ * Locate the desination initiator ACL to be registered
+ * from the decoded fabric module specific TransportID
+ * at *i_str.
+ */
+ spin_lock_bh(&tmp_tpg->acl_node_lock);
+ dest_node_acl = __core_tpg_get_initiator_node_acl(
+ tmp_tpg, i_str);
+ if (dest_node_acl) {
+ atomic_inc(&dest_node_acl->acl_pr_ref_count);
+ smp_mb__after_atomic_inc();
+ }
+ spin_unlock_bh(&tmp_tpg->acl_node_lock);
+
+ if (!(dest_node_acl)) {
+ core_scsi3_tpg_undepend_item(tmp_tpg);
+ spin_lock(&dev->se_port_lock);
+ continue;
+ }
+
+ ret = core_scsi3_nodeacl_depend_item(dest_node_acl);
+ if (ret != 0) {
+ printk(KERN_ERR "configfs_depend_item() failed"
+ " for dest_node_acl->acl_group\n");
+ atomic_dec(&dest_node_acl->acl_pr_ref_count);
+ smp_mb__after_atomic_dec();
+ core_scsi3_tpg_undepend_item(tmp_tpg);
+ ret = PYX_TRANSPORT_LU_COMM_FAILURE;
+ goto out;
+ }
+
+ dest_tpg = tmp_tpg;
+ printk(KERN_INFO "SPC-3 PR SPEC_I_PT: Located %s Node:"
+ " %s Port RTPI: %hu\n",
+ TPG_TFO(dest_tpg)->get_fabric_name(),
+ dest_node_acl->initiatorname, dest_rtpi);
+
+ spin_lock(&dev->se_port_lock);
+ break;
+ }
+ spin_unlock(&dev->se_port_lock);
+
+ if (!(dest_tpg)) {
+ printk(KERN_ERR "SPC-3 PR SPEC_I_PT: Unable to locate"
+ " dest_tpg\n");
+ ret = PYX_TRANSPORT_INVALID_PARAMETER_LIST;
+ goto out;
+ }
+#if 0
+ printk("SPC-3 PR SPEC_I_PT: Got %s data_length: %u tpdl: %u"
+ " tid_len: %d for %s + %s\n",
+ TPG_TFO(dest_tpg)->get_fabric_name(), cmd->data_length,
+ tpdl, tid_len, i_str, iport_ptr);
+#endif
+ if (tid_len > tpdl) {
+ printk(KERN_ERR "SPC-3 PR SPEC_I_PT: Illegal tid_len:"
+ " %u for Transport ID: %s\n", tid_len, ptr);
+ core_scsi3_nodeacl_undepend_item(dest_node_acl);
+ core_scsi3_tpg_undepend_item(dest_tpg);
+ ret = PYX_TRANSPORT_INVALID_PARAMETER_LIST;
+ goto out;
+ }
+ /*
+ * Locate the desintation struct se_dev_entry pointer for matching
+ * RELATIVE TARGET PORT IDENTIFIER on the receiving I_T Nexus
+ * Target Port.
+ */
+ dest_se_deve = core_get_se_deve_from_rtpi(dest_node_acl,
+ dest_rtpi);
+ if (!(dest_se_deve)) {
+ printk(KERN_ERR "Unable to locate %s dest_se_deve"
+ " from destination RTPI: %hu\n",
+ TPG_TFO(dest_tpg)->get_fabric_name(),
+ dest_rtpi);
+
+ core_scsi3_nodeacl_undepend_item(dest_node_acl);
+ core_scsi3_tpg_undepend_item(dest_tpg);
+ ret = PYX_TRANSPORT_INVALID_PARAMETER_LIST;
+ goto out;
+ }
+
+ ret = core_scsi3_lunacl_depend_item(dest_se_deve);
+ if (ret < 0) {
+ printk(KERN_ERR "core_scsi3_lunacl_depend_item()"
+ " failed\n");
+ atomic_dec(&dest_se_deve->pr_ref_count);
+ smp_mb__after_atomic_dec();
+ core_scsi3_nodeacl_undepend_item(dest_node_acl);
+ core_scsi3_tpg_undepend_item(dest_tpg);
+ ret = PYX_TRANSPORT_LU_COMM_FAILURE;
+ goto out;
+ }
+#if 0
+ printk(KERN_INFO "SPC-3 PR SPEC_I_PT: Located %s Node: %s"
+ " dest_se_deve mapped_lun: %u\n",
+ TPG_TFO(dest_tpg)->get_fabric_name(),
+ dest_node_acl->initiatorname, dest_se_deve->mapped_lun);
+#endif
+ /*
+ * Skip any TransportIDs that already have a registration for
+ * this target port.
+ */
+ pr_reg_e = __core_scsi3_locate_pr_reg(dev, dest_node_acl,
+ iport_ptr);
+ if (pr_reg_e) {
+ core_scsi3_put_pr_reg(pr_reg_e);
+ core_scsi3_lunacl_undepend_item(dest_se_deve);
+ core_scsi3_nodeacl_undepend_item(dest_node_acl);
+ core_scsi3_tpg_undepend_item(dest_tpg);
+ ptr += tid_len;
+ tpdl -= tid_len;
+ tid_len = 0;
+ continue;
+ }
+ /*
+ * Allocate a struct pr_transport_id_holder and setup
+ * the dest_node_acl and dest_se_deve pointers for the
+ * loop below.
+ */
+ tidh_new = kzalloc(sizeof(struct pr_transport_id_holder),
+ GFP_KERNEL);
+ if (!(tidh_new)) {
+ printk(KERN_ERR "Unable to allocate tidh_new\n");
+ core_scsi3_lunacl_undepend_item(dest_se_deve);
+ core_scsi3_nodeacl_undepend_item(dest_node_acl);
+ core_scsi3_tpg_undepend_item(dest_tpg);
+ ret = PYX_TRANSPORT_LU_COMM_FAILURE;
+ goto out;
+ }
+ INIT_LIST_HEAD(&tidh_new->dest_list);
+ tidh_new->dest_tpg = dest_tpg;
+ tidh_new->dest_node_acl = dest_node_acl;
+ tidh_new->dest_se_deve = dest_se_deve;
+
+ /*
+ * Allocate, but do NOT add the registration for the
+ * TransportID referenced SCSI Initiator port. This
+ * done because of the following from spc4r17 in section
+ * 6.14.3 wrt SPEC_I_PT:
+ *
+ * "If a registration fails for any initiator port (e.g., if th
+ * logical unit does not have enough resources available to
+ * hold the registration information), no registrations shall be
+ * made, and the command shall be terminated with
+ * CHECK CONDITION status."
+ *
+ * That means we call __core_scsi3_alloc_registration() here,
+ * and then call __core_scsi3_add_registration() in the
+ * 2nd loop which will never fail.
+ */
+ dest_pr_reg = __core_scsi3_alloc_registration(SE_DEV(cmd),
+ dest_node_acl, dest_se_deve, iport_ptr,
+ sa_res_key, all_tg_pt, aptpl);
+ if (!(dest_pr_reg)) {
+ core_scsi3_lunacl_undepend_item(dest_se_deve);
+ core_scsi3_nodeacl_undepend_item(dest_node_acl);
+ core_scsi3_tpg_undepend_item(dest_tpg);
+ kfree(tidh_new);
+ ret = PYX_TRANSPORT_INVALID_PARAMETER_LIST;
+ goto out;
+ }
+ tidh_new->dest_pr_reg = dest_pr_reg;
+ list_add_tail(&tidh_new->dest_list, &tid_dest_list);
+
+ ptr += tid_len;
+ tpdl -= tid_len;
+ tid_len = 0;
+
+ }
+ /*
+ * Go ahead and create a registrations from tid_dest_list for the
+ * SPEC_I_PT provided TransportID for the *tidh referenced dest_node_acl
+ * and dest_se_deve.
+ *
+ * The SA Reservation Key from the PROUT is set for the
+ * registration, and ALL_TG_PT is also passed. ALL_TG_PT=1
+ * means that the TransportID Initiator port will be
+ * registered on all of the target ports in the SCSI target device
+ * ALL_TG_PT=0 means the registration will only be for the
+ * SCSI target port the PROUT REGISTER with SPEC_I_PT=1
+ * was received.
+ */
+ list_for_each_entry_safe(tidh, tidh_tmp, &tid_dest_list, dest_list) {
+ dest_tpg = tidh->dest_tpg;
+ dest_node_acl = tidh->dest_node_acl;
+ dest_se_deve = tidh->dest_se_deve;
+ dest_pr_reg = tidh->dest_pr_reg;
+ dest_local_nexus = tidh->dest_local_nexus;
+
+ list_del(&tidh->dest_list);
+ kfree(tidh);
+
+ memset(i_buf, 0, PR_REG_ISID_ID_LEN);
+ prf_isid = core_pr_dump_initiator_port(dest_pr_reg, &i_buf[0],
+ PR_REG_ISID_ID_LEN);
+
+ __core_scsi3_add_registration(SE_DEV(cmd), dest_node_acl,
+ dest_pr_reg, 0, 0);
+
+ printk(KERN_INFO "SPC-3 PR [%s] SPEC_I_PT: Successfully"
+ " registered Transport ID for Node: %s%s Mapped LUN:"
+ " %u\n", TPG_TFO(dest_tpg)->get_fabric_name(),
+ dest_node_acl->initiatorname, (prf_isid) ?
+ &i_buf[0] : "", dest_se_deve->mapped_lun);
+
+ if (dest_local_nexus)
+ continue;
+
+ core_scsi3_lunacl_undepend_item(dest_se_deve);
+ core_scsi3_nodeacl_undepend_item(dest_node_acl);
+ core_scsi3_tpg_undepend_item(dest_tpg);
+ }
+
+ return 0;
+out:
+ /*
+ * For the failure case, release everything from tid_dest_list
+ * including *dest_pr_reg and the configfs dependances..
+ */
+ list_for_each_entry_safe(tidh, tidh_tmp, &tid_dest_list, dest_list) {
+ dest_tpg = tidh->dest_tpg;
+ dest_node_acl = tidh->dest_node_acl;
+ dest_se_deve = tidh->dest_se_deve;
+ dest_pr_reg = tidh->dest_pr_reg;
+ dest_local_nexus = tidh->dest_local_nexus;
+
+ list_del(&tidh->dest_list);
+ kfree(tidh);
+ /*
+ * Release any extra ALL_TG_PT=1 registrations for
+ * the SPEC_I_PT=1 case.
+ */
+ list_for_each_entry_safe(pr_reg_tmp, pr_reg_tmp_safe,
+ &dest_pr_reg->pr_reg_atp_list,
+ pr_reg_atp_mem_list) {
+ list_del(&pr_reg_tmp->pr_reg_atp_mem_list);
+ core_scsi3_lunacl_undepend_item(pr_reg_tmp->pr_reg_deve);
+ kmem_cache_free(t10_pr_reg_cache, pr_reg_tmp);
+ }
+
+ kfree(dest_pr_reg->pr_aptpl_buf);
+ kmem_cache_free(t10_pr_reg_cache, dest_pr_reg);
+
+ if (dest_local_nexus)
+ continue;
+
+ core_scsi3_lunacl_undepend_item(dest_se_deve);
+ core_scsi3_nodeacl_undepend_item(dest_node_acl);
+ core_scsi3_tpg_undepend_item(dest_tpg);
+ }
+ return ret;
+}
+
+/*
+ * Called with struct se_device->dev_reservation_lock held
+ */
+static int __core_scsi3_update_aptpl_buf(
+ struct se_device *dev,
+ unsigned char *buf,
+ u32 pr_aptpl_buf_len,
+ int clear_aptpl_metadata)
+{
+ struct se_lun *lun;
+ struct se_portal_group *tpg;
+ struct se_subsystem_dev *su_dev = SU_DEV(dev);
+ struct t10_pr_registration *pr_reg;
+ unsigned char tmp[512], isid_buf[32];
+ ssize_t len = 0;
+ int reg_count = 0;
+
+ memset(buf, 0, pr_aptpl_buf_len);
+ /*
+ * Called to clear metadata once APTPL has been deactivated.
+ */
+ if (clear_aptpl_metadata) {
+ snprintf(buf, pr_aptpl_buf_len,
+ "No Registrations or Reservations\n");
+ return 0;
+ }
+ /*
+ * Walk the registration list..
+ */
+ spin_lock(&T10_RES(su_dev)->registration_lock);
+ list_for_each_entry(pr_reg, &T10_RES(su_dev)->registration_list,
+ pr_reg_list) {
+
+ tmp[0] = '\0';
+ isid_buf[0] = '\0';
+ tpg = pr_reg->pr_reg_nacl->se_tpg;
+ lun = pr_reg->pr_reg_tg_pt_lun;
+ /*
+ * Write out any ISID value to APTPL metadata that was included
+ * in the original registration.
+ */
+ if (pr_reg->isid_present_at_reg)
+ snprintf(isid_buf, 32, "initiator_sid=%s\n",
+ pr_reg->pr_reg_isid);
+ /*
+ * Include special metadata if the pr_reg matches the
+ * reservation holder.
+ */
+ if (dev->dev_pr_res_holder == pr_reg) {
+ snprintf(tmp, 512, "PR_REG_START: %d"
+ "\ninitiator_fabric=%s\n"
+ "initiator_node=%s\n%s"
+ "sa_res_key=%llu\n"
+ "res_holder=1\nres_type=%02x\n"
+ "res_scope=%02x\nres_all_tg_pt=%d\n"
+ "mapped_lun=%u\n", reg_count,
+ TPG_TFO(tpg)->get_fabric_name(),
+ pr_reg->pr_reg_nacl->initiatorname, isid_buf,
+ pr_reg->pr_res_key, pr_reg->pr_res_type,
+ pr_reg->pr_res_scope, pr_reg->pr_reg_all_tg_pt,
+ pr_reg->pr_res_mapped_lun);
+ } else {
+ snprintf(tmp, 512, "PR_REG_START: %d\n"
+ "initiator_fabric=%s\ninitiator_node=%s\n%s"
+ "sa_res_key=%llu\nres_holder=0\n"
+ "res_all_tg_pt=%d\nmapped_lun=%u\n",
+ reg_count, TPG_TFO(tpg)->get_fabric_name(),
+ pr_reg->pr_reg_nacl->initiatorname, isid_buf,
+ pr_reg->pr_res_key, pr_reg->pr_reg_all_tg_pt,
+ pr_reg->pr_res_mapped_lun);
+ }
+
+ if ((len + strlen(tmp) > pr_aptpl_buf_len)) {
+ printk(KERN_ERR "Unable to update renaming"
+ " APTPL metadata\n");
+ spin_unlock(&T10_RES(su_dev)->registration_lock);
+ return -1;
+ }
+ len += sprintf(buf+len, "%s", tmp);
+
+ /*
+ * Include information about the associated SCSI target port.
+ */
+ snprintf(tmp, 512, "target_fabric=%s\ntarget_node=%s\n"
+ "tpgt=%hu\nport_rtpi=%hu\ntarget_lun=%u\nPR_REG_END:"
+ " %d\n", TPG_TFO(tpg)->get_fabric_name(),
+ TPG_TFO(tpg)->tpg_get_wwn(tpg),
+ TPG_TFO(tpg)->tpg_get_tag(tpg),
+ lun->lun_sep->sep_rtpi, lun->unpacked_lun, reg_count);
+
+ if ((len + strlen(tmp) > pr_aptpl_buf_len)) {
+ printk(KERN_ERR "Unable to update renaming"
+ " APTPL metadata\n");
+ spin_unlock(&T10_RES(su_dev)->registration_lock);
+ return -1;
+ }
+ len += sprintf(buf+len, "%s", tmp);
+ reg_count++;
+ }
+ spin_unlock(&T10_RES(su_dev)->registration_lock);
+
+ if (!(reg_count))
+ len += sprintf(buf+len, "No Registrations or Reservations");
+
+ return 0;
+}
+
+static int core_scsi3_update_aptpl_buf(
+ struct se_device *dev,
+ unsigned char *buf,
+ u32 pr_aptpl_buf_len,
+ int clear_aptpl_metadata)
+{
+ int ret;
+
+ spin_lock(&dev->dev_reservation_lock);
+ ret = __core_scsi3_update_aptpl_buf(dev, buf, pr_aptpl_buf_len,
+ clear_aptpl_metadata);
+ spin_unlock(&dev->dev_reservation_lock);
+
+ return ret;
+}
+
+/*
+ * Called with struct se_device->aptpl_file_mutex held
+ */
+static int __core_scsi3_write_aptpl_to_file(
+ struct se_device *dev,
+ unsigned char *buf,
+ u32 pr_aptpl_buf_len)
+{
+ struct t10_wwn *wwn = &SU_DEV(dev)->t10_wwn;
+ struct file *file;
+ struct iovec iov[1];
+ mm_segment_t old_fs;
+ int flags = O_RDWR | O_CREAT | O_TRUNC;
+ char path[512];
+ int ret;
+
+ memset(iov, 0, sizeof(struct iovec));
+ memset(path, 0, 512);
+
+ if (strlen(&wwn->unit_serial[0]) > 512) {
+ printk(KERN_ERR "WWN value for struct se_device does not fit"
+ " into path buffer\n");
+ return -1;
+ }
+
+ snprintf(path, 512, "/var/target/pr/aptpl_%s", &wwn->unit_serial[0]);
+ file = filp_open(path, flags, 0600);
+ if (IS_ERR(file) || !file || !file->f_dentry) {
+ printk(KERN_ERR "filp_open(%s) for APTPL metadata"
+ " failed\n", path);
+ return -1;
+ }
+
+ iov[0].iov_base = &buf[0];
+ if (!(pr_aptpl_buf_len))
+ iov[0].iov_len = (strlen(&buf[0]) + 1); /* Add extra for NULL */
+ else
+ iov[0].iov_len = pr_aptpl_buf_len;
+
+ old_fs = get_fs();
+ set_fs(get_ds());
+ ret = vfs_writev(file, &iov[0], 1, &file->f_pos);
+ set_fs(old_fs);
+
+ if (ret < 0) {
+ printk("Error writing APTPL metadata file: %s\n", path);
+ filp_close(file, NULL);
+ return -1;
+ }
+ filp_close(file, NULL);
+
+ return 0;
+}
+
+static int core_scsi3_update_and_write_aptpl(
+ struct se_device *dev,
+ unsigned char *in_buf,
+ u32 in_pr_aptpl_buf_len)
+{
+ unsigned char null_buf[64], *buf;
+ u32 pr_aptpl_buf_len;
+ int ret, clear_aptpl_metadata = 0;
+ /*
+ * Can be called with a NULL pointer from PROUT service action CLEAR
+ */
+ if (!(in_buf)) {
+ memset(null_buf, 0, 64);
+ buf = &null_buf[0];
+ /*
+ * This will clear the APTPL metadata to:
+ * "No Registrations or Reservations" status
+ */
+ pr_aptpl_buf_len = 64;
+ clear_aptpl_metadata = 1;
+ } else {
+ buf = in_buf;
+ pr_aptpl_buf_len = in_pr_aptpl_buf_len;
+ }
+
+ ret = core_scsi3_update_aptpl_buf(dev, buf, pr_aptpl_buf_len,
+ clear_aptpl_metadata);
+ if (ret != 0)
+ return -1;
+ /*
+ * __core_scsi3_write_aptpl_to_file() will call strlen()
+ * on the passed buf to determine pr_aptpl_buf_len.
+ */
+ ret = __core_scsi3_write_aptpl_to_file(dev, buf, 0);
+ if (ret != 0)
+ return -1;
+
+ return ret;
+}
+
+static int core_scsi3_emulate_pro_register(
+ struct se_cmd *cmd,
+ u64 res_key,
+ u64 sa_res_key,
+ int aptpl,
+ int all_tg_pt,
+ int spec_i_pt,
+ int ignore_key)
+{
+ struct se_session *se_sess = SE_SESS(cmd);
+ struct se_device *dev = SE_DEV(cmd);
+ struct se_dev_entry *se_deve;
+ struct se_lun *se_lun = SE_LUN(cmd);
+ struct se_portal_group *se_tpg;
+ struct t10_pr_registration *pr_reg, *pr_reg_p, *pr_reg_tmp, *pr_reg_e;
+ struct t10_reservation_template *pr_tmpl = &SU_DEV(dev)->t10_reservation;
+ /* Used for APTPL metadata w/ UNREGISTER */
+ unsigned char *pr_aptpl_buf = NULL;
+ unsigned char isid_buf[PR_REG_ISID_LEN], *isid_ptr = NULL;
+ int pr_holder = 0, ret = 0, type;
+
+ if (!(se_sess) || !(se_lun)) {
+ printk(KERN_ERR "SPC-3 PR: se_sess || struct se_lun is NULL!\n");
+ return PYX_TRANSPORT_LU_COMM_FAILURE;
+ }
+ se_tpg = se_sess->se_tpg;
+ se_deve = &se_sess->se_node_acl->device_list[cmd->orig_fe_lun];
+
+ if (TPG_TFO(se_tpg)->sess_get_initiator_sid != NULL) {
+ memset(&isid_buf[0], 0, PR_REG_ISID_LEN);
+ TPG_TFO(se_tpg)->sess_get_initiator_sid(se_sess, &isid_buf[0],
+ PR_REG_ISID_LEN);
+ isid_ptr = &isid_buf[0];
+ }
+ /*
+ * Follow logic from spc4r17 Section 5.7.7, Register Behaviors Table 47
+ */
+ pr_reg_e = core_scsi3_locate_pr_reg(dev, se_sess->se_node_acl, se_sess);
+ if (!(pr_reg_e)) {
+ if (res_key) {
+ printk(KERN_WARNING "SPC-3 PR: Reservation Key non-zero"
+ " for SA REGISTER, returning CONFLICT\n");
+ return PYX_TRANSPORT_RESERVATION_CONFLICT;
+ }
+ /*
+ * Do nothing but return GOOD status.
+ */
+ if (!(sa_res_key))
+ return PYX_TRANSPORT_SENT_TO_TRANSPORT;
+
+ if (!(spec_i_pt)) {
+ /*
+ * Perform the Service Action REGISTER on the Initiator
+ * Port Endpoint that the PRO was received from on the
+ * Logical Unit of the SCSI device server.
+ */
+ ret = core_scsi3_alloc_registration(SE_DEV(cmd),
+ se_sess->se_node_acl, se_deve, isid_ptr,
+ sa_res_key, all_tg_pt, aptpl,
+ ignore_key, 0);
+ if (ret != 0) {
+ printk(KERN_ERR "Unable to allocate"
+ " struct t10_pr_registration\n");
+ return PYX_TRANSPORT_INVALID_PARAMETER_LIST;
+ }
+ } else {
+ /*
+ * Register both the Initiator port that received
+ * PROUT SA REGISTER + SPEC_I_PT=1 and extract SCSI
+ * TransportID from Parameter list and loop through
+ * fabric dependent parameter list while calling
+ * logic from of core_scsi3_alloc_registration() for
+ * each TransportID provided SCSI Initiator Port/Device
+ */
+ ret = core_scsi3_decode_spec_i_port(cmd, se_tpg,
+ isid_ptr, sa_res_key, all_tg_pt, aptpl);
+ if (ret != 0)
+ return ret;
+ }
+ /*
+ * Nothing left to do for the APTPL=0 case.
+ */
+ if (!(aptpl)) {
+ pr_tmpl->pr_aptpl_active = 0;
+ core_scsi3_update_and_write_aptpl(SE_DEV(cmd), NULL, 0);
+ printk("SPC-3 PR: Set APTPL Bit Deactivated for"
+ " REGISTER\n");
+ return 0;
+ }
+ /*
+ * Locate the newly allocated local I_T Nexus *pr_reg, and
+ * update the APTPL metadata information using its
+ * preallocated *pr_reg->pr_aptpl_buf.
+ */
+ pr_reg = core_scsi3_locate_pr_reg(SE_DEV(cmd),
+ se_sess->se_node_acl, se_sess);
+
+ ret = core_scsi3_update_and_write_aptpl(SE_DEV(cmd),
+ &pr_reg->pr_aptpl_buf[0],
+ pr_tmpl->pr_aptpl_buf_len);
+ if (!(ret)) {
+ pr_tmpl->pr_aptpl_active = 1;
+ printk("SPC-3 PR: Set APTPL Bit Activated for REGISTER\n");
+ }
+
+ core_scsi3_put_pr_reg(pr_reg);
+ return ret;
+ } else {
+ /*
+ * Locate the existing *pr_reg via struct se_node_acl pointers
+ */
+ pr_reg = pr_reg_e;
+ type = pr_reg->pr_res_type;
+
+ if (!(ignore_key)) {
+ if (res_key != pr_reg->pr_res_key) {
+ printk(KERN_ERR "SPC-3 PR REGISTER: Received"
+ " res_key: 0x%016Lx does not match"
+ " existing SA REGISTER res_key:"
+ " 0x%016Lx\n", res_key,
+ pr_reg->pr_res_key);
+ core_scsi3_put_pr_reg(pr_reg);
+ return PYX_TRANSPORT_RESERVATION_CONFLICT;
+ }
+ }
+ if (spec_i_pt) {
+ printk(KERN_ERR "SPC-3 PR UNREGISTER: SPEC_I_PT"
+ " set while sa_res_key=0\n");
+ core_scsi3_put_pr_reg(pr_reg);
+ return PYX_TRANSPORT_INVALID_PARAMETER_LIST;
+ }
+ /*
+ * An existing ALL_TG_PT=1 registration being released
+ * must also set ALL_TG_PT=1 in the incoming PROUT.
+ */
+ if (pr_reg->pr_reg_all_tg_pt && !(all_tg_pt)) {
+ printk(KERN_ERR "SPC-3 PR UNREGISTER: ALL_TG_PT=1"
+ " registration exists, but ALL_TG_PT=1 bit not"
+ " present in received PROUT\n");
+ core_scsi3_put_pr_reg(pr_reg);
+ return PYX_TRANSPORT_INVALID_CDB_FIELD;
+ }
+ /*
+ * Allocate APTPL metadata buffer used for UNREGISTER ops
+ */
+ if (aptpl) {
+ pr_aptpl_buf = kzalloc(pr_tmpl->pr_aptpl_buf_len,
+ GFP_KERNEL);
+ if (!(pr_aptpl_buf)) {
+ printk(KERN_ERR "Unable to allocate"
+ " pr_aptpl_buf\n");
+ core_scsi3_put_pr_reg(pr_reg);
+ return PYX_TRANSPORT_LU_COMM_FAILURE;
+ }
+ }
+ /*
+ * sa_res_key=0 Unregister Reservation Key for registered I_T
+ * Nexus sa_res_key=1 Change Reservation Key for registered I_T
+ * Nexus.
+ */
+ if (!(sa_res_key)) {
+ pr_holder = core_scsi3_check_implict_release(
+ SE_DEV(cmd), pr_reg);
+ if (pr_holder < 0) {
+ kfree(pr_aptpl_buf);
+ core_scsi3_put_pr_reg(pr_reg);
+ return PYX_TRANSPORT_RESERVATION_CONFLICT;
+ }
+
+ spin_lock(&pr_tmpl->registration_lock);
+ /*
+ * Release all ALL_TG_PT=1 for the matching SCSI Initiator Port
+ * and matching pr_res_key.
+ */
+ if (pr_reg->pr_reg_all_tg_pt) {
+ list_for_each_entry_safe(pr_reg_p, pr_reg_tmp,
+ &pr_tmpl->registration_list,
+ pr_reg_list) {
+
+ if (!(pr_reg_p->pr_reg_all_tg_pt))
+ continue;
+
+ if (pr_reg_p->pr_res_key != res_key)
+ continue;
+
+ if (pr_reg == pr_reg_p)
+ continue;
+
+ if (strcmp(pr_reg->pr_reg_nacl->initiatorname,
+ pr_reg_p->pr_reg_nacl->initiatorname))
+ continue;
+
+ __core_scsi3_free_registration(dev,
+ pr_reg_p, NULL, 0);
+ }
+ }
+ /*
+ * Release the calling I_T Nexus registration now..
+ */
+ __core_scsi3_free_registration(SE_DEV(cmd), pr_reg,
+ NULL, 1);
+ /*
+ * From spc4r17, section 5.7.11.3 Unregistering
+ *
+ * If the persistent reservation is a registrants only
+ * type, the device server shall establish a unit
+ * attention condition for the initiator port associated
+ * with every registered I_T nexus except for the I_T
+ * nexus on which the PERSISTENT RESERVE OUT command was
+ * received, with the additional sense code set to
+ * RESERVATIONS RELEASED.
+ */
+ if (pr_holder &&
+ ((type == PR_TYPE_WRITE_EXCLUSIVE_REGONLY) ||
+ (type == PR_TYPE_EXCLUSIVE_ACCESS_REGONLY))) {
+ list_for_each_entry(pr_reg_p,
+ &pr_tmpl->registration_list,
+ pr_reg_list) {
+
+ core_scsi3_ua_allocate(
+ pr_reg_p->pr_reg_nacl,
+ pr_reg_p->pr_res_mapped_lun,
+ 0x2A,
+ ASCQ_2AH_RESERVATIONS_RELEASED);
+ }
+ }
+ spin_unlock(&pr_tmpl->registration_lock);
+
+ if (!(aptpl)) {
+ pr_tmpl->pr_aptpl_active = 0;
+ core_scsi3_update_and_write_aptpl(dev, NULL, 0);
+ printk("SPC-3 PR: Set APTPL Bit Deactivated"
+ " for UNREGISTER\n");
+ return 0;
+ }
+
+ ret = core_scsi3_update_and_write_aptpl(dev,
+ &pr_aptpl_buf[0],
+ pr_tmpl->pr_aptpl_buf_len);
+ if (!(ret)) {
+ pr_tmpl->pr_aptpl_active = 1;
+ printk("SPC-3 PR: Set APTPL Bit Activated"
+ " for UNREGISTER\n");
+ }
+
+ kfree(pr_aptpl_buf);
+ return ret;
+ } else {
+ /*
+ * Increment PRgeneration counter for struct se_device"
+ * upon a successful REGISTER, see spc4r17 section 6.3.2
+ * READ_KEYS service action.
+ */
+ pr_reg->pr_res_generation = core_scsi3_pr_generation(
+ SE_DEV(cmd));
+ pr_reg->pr_res_key = sa_res_key;
+ printk("SPC-3 PR [%s] REGISTER%s: Changed Reservation"
+ " Key for %s to: 0x%016Lx PRgeneration:"
+ " 0x%08x\n", CMD_TFO(cmd)->get_fabric_name(),
+ (ignore_key) ? "_AND_IGNORE_EXISTING_KEY" : "",
+ pr_reg->pr_reg_nacl->initiatorname,
+ pr_reg->pr_res_key, pr_reg->pr_res_generation);
+
+ if (!(aptpl)) {
+ pr_tmpl->pr_aptpl_active = 0;
+ core_scsi3_update_and_write_aptpl(dev, NULL, 0);
+ core_scsi3_put_pr_reg(pr_reg);
+ printk("SPC-3 PR: Set APTPL Bit Deactivated"
+ " for REGISTER\n");
+ return 0;
+ }
+
+ ret = core_scsi3_update_and_write_aptpl(dev,
+ &pr_aptpl_buf[0],
+ pr_tmpl->pr_aptpl_buf_len);
+ if (!(ret)) {
+ pr_tmpl->pr_aptpl_active = 1;
+ printk("SPC-3 PR: Set APTPL Bit Activated"
+ " for REGISTER\n");
+ }
+
+ kfree(pr_aptpl_buf);
+ core_scsi3_put_pr_reg(pr_reg);
+ }
+ }
+ return 0;
+}
+
+unsigned char *core_scsi3_pr_dump_type(int type)
+{
+ switch (type) {
+ case PR_TYPE_WRITE_EXCLUSIVE:
+ return "Write Exclusive Access";
+ case PR_TYPE_EXCLUSIVE_ACCESS:
+ return "Exclusive Access";
+ case PR_TYPE_WRITE_EXCLUSIVE_REGONLY:
+ return "Write Exclusive Access, Registrants Only";
+ case PR_TYPE_EXCLUSIVE_ACCESS_REGONLY:
+ return "Exclusive Access, Registrants Only";
+ case PR_TYPE_WRITE_EXCLUSIVE_ALLREG:
+ return "Write Exclusive Access, All Registrants";
+ case PR_TYPE_EXCLUSIVE_ACCESS_ALLREG:
+ return "Exclusive Access, All Registrants";
+ default:
+ break;
+ }
+
+ return "Unknown SPC-3 PR Type";
+}
+
+static int core_scsi3_pro_reserve(
+ struct se_cmd *cmd,
+ struct se_device *dev,
+ int type,
+ int scope,
+ u64 res_key)
+{
+ struct se_session *se_sess = SE_SESS(cmd);
+ struct se_dev_entry *se_deve;
+ struct se_lun *se_lun = SE_LUN(cmd);
+ struct se_portal_group *se_tpg;
+ struct t10_pr_registration *pr_reg, *pr_res_holder;
+ struct t10_reservation_template *pr_tmpl = &SU_DEV(dev)->t10_reservation;
+ char i_buf[PR_REG_ISID_ID_LEN];
+ int ret, prf_isid;
+
+ memset(i_buf, 0, PR_REG_ISID_ID_LEN);
+
+ if (!(se_sess) || !(se_lun)) {
+ printk(KERN_ERR "SPC-3 PR: se_sess || struct se_lun is NULL!\n");
+ return PYX_TRANSPORT_LU_COMM_FAILURE;
+ }
+ se_tpg = se_sess->se_tpg;
+ se_deve = &se_sess->se_node_acl->device_list[cmd->orig_fe_lun];
+ /*
+ * Locate the existing *pr_reg via struct se_node_acl pointers
+ */
+ pr_reg = core_scsi3_locate_pr_reg(SE_DEV(cmd), se_sess->se_node_acl,
+ se_sess);
+ if (!(pr_reg)) {
+ printk(KERN_ERR "SPC-3 PR: Unable to locate"
+ " PR_REGISTERED *pr_reg for RESERVE\n");
+ return PYX_TRANSPORT_LU_COMM_FAILURE;
+ }
+ /*
+ * From spc4r17 Section 5.7.9: Reserving:
+ *
+ * An application client creates a persistent reservation by issuing
+ * a PERSISTENT RESERVE OUT command with RESERVE service action through
+ * a registered I_T nexus with the following parameters:
+ * a) RESERVATION KEY set to the value of the reservation key that is
+ * registered with the logical unit for the I_T nexus; and
+ */
+ if (res_key != pr_reg->pr_res_key) {
+ printk(KERN_ERR "SPC-3 PR RESERVE: Received res_key: 0x%016Lx"
+ " does not match existing SA REGISTER res_key:"
+ " 0x%016Lx\n", res_key, pr_reg->pr_res_key);
+ core_scsi3_put_pr_reg(pr_reg);
+ return PYX_TRANSPORT_RESERVATION_CONFLICT;
+ }
+ /*
+ * From spc4r17 Section 5.7.9: Reserving:
+ *
+ * From above:
+ * b) TYPE field and SCOPE field set to the persistent reservation
+ * being created.
+ *
+ * Only one persistent reservation is allowed at a time per logical unit
+ * and that persistent reservation has a scope of LU_SCOPE.
+ */
+ if (scope != PR_SCOPE_LU_SCOPE) {
+ printk(KERN_ERR "SPC-3 PR: Illegal SCOPE: 0x%02x\n", scope);
+ core_scsi3_put_pr_reg(pr_reg);
+ return PYX_TRANSPORT_INVALID_PARAMETER_LIST;
+ }
+ /*
+ * See if we have an existing PR reservation holder pointer at
+ * struct se_device->dev_pr_res_holder in the form struct t10_pr_registration
+ * *pr_res_holder.
+ */
+ spin_lock(&dev->dev_reservation_lock);
+ pr_res_holder = dev->dev_pr_res_holder;
+ if ((pr_res_holder)) {
+ /*
+ * From spc4r17 Section 5.7.9: Reserving:
+ *
+ * If the device server receives a PERSISTENT RESERVE OUT
+ * command from an I_T nexus other than a persistent reservation
+ * holder (see 5.7.10) that attempts to create a persistent
+ * reservation when a persistent reservation already exists for
+ * the logical unit, then the command shall be completed with
+ * RESERVATION CONFLICT status.
+ */
+ if (pr_res_holder != pr_reg) {
+ struct se_node_acl *pr_res_nacl = pr_res_holder->pr_reg_nacl;
+ printk(KERN_ERR "SPC-3 PR: Attempted RESERVE from"
+ " [%s]: %s while reservation already held by"
+ " [%s]: %s, returning RESERVATION_CONFLICT\n",
+ CMD_TFO(cmd)->get_fabric_name(),
+ se_sess->se_node_acl->initiatorname,
+ TPG_TFO(pr_res_nacl->se_tpg)->get_fabric_name(),
+ pr_res_holder->pr_reg_nacl->initiatorname);
+
+ spin_unlock(&dev->dev_reservation_lock);
+ core_scsi3_put_pr_reg(pr_reg);
+ return PYX_TRANSPORT_RESERVATION_CONFLICT;
+ }
+ /*
+ * From spc4r17 Section 5.7.9: Reserving:
+ *
+ * If a persistent reservation holder attempts to modify the
+ * type or scope of an existing persistent reservation, the
+ * command shall be completed with RESERVATION CONFLICT status.
+ */
+ if ((pr_res_holder->pr_res_type != type) ||
+ (pr_res_holder->pr_res_scope != scope)) {
+ struct se_node_acl *pr_res_nacl = pr_res_holder->pr_reg_nacl;
+ printk(KERN_ERR "SPC-3 PR: Attempted RESERVE from"
+ " [%s]: %s trying to change TYPE and/or SCOPE,"
+ " while reservation already held by [%s]: %s,"
+ " returning RESERVATION_CONFLICT\n",
+ CMD_TFO(cmd)->get_fabric_name(),
+ se_sess->se_node_acl->initiatorname,
+ TPG_TFO(pr_res_nacl->se_tpg)->get_fabric_name(),
+ pr_res_holder->pr_reg_nacl->initiatorname);
+
+ spin_unlock(&dev->dev_reservation_lock);
+ core_scsi3_put_pr_reg(pr_reg);
+ return PYX_TRANSPORT_RESERVATION_CONFLICT;
+ }
+ /*
+ * From spc4r17 Section 5.7.9: Reserving:
+ *
+ * If the device server receives a PERSISTENT RESERVE OUT
+ * command with RESERVE service action where the TYPE field and
+ * the SCOPE field contain the same values as the existing type
+ * and scope from a persistent reservation holder, it shall not
+ * make any change to the existing persistent reservation and
+ * shall completethe command with GOOD status.
+ */
+ spin_unlock(&dev->dev_reservation_lock);
+ core_scsi3_put_pr_reg(pr_reg);
+ return PYX_TRANSPORT_SENT_TO_TRANSPORT;
+ }
+ /*
+ * Otherwise, our *pr_reg becomes the PR reservation holder for said
+ * TYPE/SCOPE. Also set the received scope and type in *pr_reg.
+ */
+ pr_reg->pr_res_scope = scope;
+ pr_reg->pr_res_type = type;
+ pr_reg->pr_res_holder = 1;
+ dev->dev_pr_res_holder = pr_reg;
+ prf_isid = core_pr_dump_initiator_port(pr_reg, &i_buf[0],
+ PR_REG_ISID_ID_LEN);
+
+ printk(KERN_INFO "SPC-3 PR [%s] Service Action: RESERVE created new"
+ " reservation holder TYPE: %s ALL_TG_PT: %d\n",
+ CMD_TFO(cmd)->get_fabric_name(), core_scsi3_pr_dump_type(type),
+ (pr_reg->pr_reg_all_tg_pt) ? 1 : 0);
+ printk(KERN_INFO "SPC-3 PR [%s] RESERVE Node: %s%s\n",
+ CMD_TFO(cmd)->get_fabric_name(),
+ se_sess->se_node_acl->initiatorname,
+ (prf_isid) ? &i_buf[0] : "");
+ spin_unlock(&dev->dev_reservation_lock);
+
+ if (pr_tmpl->pr_aptpl_active) {
+ ret = core_scsi3_update_and_write_aptpl(SE_DEV(cmd),
+ &pr_reg->pr_aptpl_buf[0],
+ pr_tmpl->pr_aptpl_buf_len);
+ if (!(ret))
+ printk(KERN_INFO "SPC-3 PR: Updated APTPL metadata"
+ " for RESERVE\n");
+ }
+
+ core_scsi3_put_pr_reg(pr_reg);
+ return 0;
+}
+
+static int core_scsi3_emulate_pro_reserve(
+ struct se_cmd *cmd,
+ int type,
+ int scope,
+ u64 res_key)
+{
+ struct se_device *dev = cmd->se_dev;
+ int ret = 0;
+
+ switch (type) {
+ case PR_TYPE_WRITE_EXCLUSIVE:
+ case PR_TYPE_EXCLUSIVE_ACCESS:
+ case PR_TYPE_WRITE_EXCLUSIVE_REGONLY:
+ case PR_TYPE_EXCLUSIVE_ACCESS_REGONLY:
+ case PR_TYPE_WRITE_EXCLUSIVE_ALLREG:
+ case PR_TYPE_EXCLUSIVE_ACCESS_ALLREG:
+ ret = core_scsi3_pro_reserve(cmd, dev, type, scope, res_key);
+ break;
+ default:
+ printk(KERN_ERR "SPC-3 PR: Unknown Service Action RESERVE Type:"
+ " 0x%02x\n", type);
+ return PYX_TRANSPORT_INVALID_CDB_FIELD;
+ }
+
+ return ret;
+}
+
+/*
+ * Called with struct se_device->dev_reservation_lock held.
+ */
+static void __core_scsi3_complete_pro_release(
+ struct se_device *dev,
+ struct se_node_acl *se_nacl,
+ struct t10_pr_registration *pr_reg,
+ int explict)
+{
+ struct target_core_fabric_ops *tfo = se_nacl->se_tpg->se_tpg_tfo;
+ char i_buf[PR_REG_ISID_ID_LEN];
+ int prf_isid;
+
+ memset(i_buf, 0, PR_REG_ISID_ID_LEN);
+ prf_isid = core_pr_dump_initiator_port(pr_reg, &i_buf[0],
+ PR_REG_ISID_ID_LEN);
+ /*
+ * Go ahead and release the current PR reservation holder.
+ */
+ dev->dev_pr_res_holder = NULL;
+
+ printk(KERN_INFO "SPC-3 PR [%s] Service Action: %s RELEASE cleared"
+ " reservation holder TYPE: %s ALL_TG_PT: %d\n",
+ tfo->get_fabric_name(), (explict) ? "explict" : "implict",
+ core_scsi3_pr_dump_type(pr_reg->pr_res_type),
+ (pr_reg->pr_reg_all_tg_pt) ? 1 : 0);
+ printk(KERN_INFO "SPC-3 PR [%s] RELEASE Node: %s%s\n",
+ tfo->get_fabric_name(), se_nacl->initiatorname,
+ (prf_isid) ? &i_buf[0] : "");
+ /*
+ * Clear TYPE and SCOPE for the next PROUT Service Action: RESERVE
+ */
+ pr_reg->pr_res_holder = pr_reg->pr_res_type = pr_reg->pr_res_scope = 0;
+}
+
+static int core_scsi3_emulate_pro_release(
+ struct se_cmd *cmd,
+ int type,
+ int scope,
+ u64 res_key)
+{
+ struct se_device *dev = cmd->se_dev;
+ struct se_session *se_sess = SE_SESS(cmd);
+ struct se_lun *se_lun = SE_LUN(cmd);
+ struct t10_pr_registration *pr_reg, *pr_reg_p, *pr_res_holder;
+ struct t10_reservation_template *pr_tmpl = &SU_DEV(dev)->t10_reservation;
+ int ret, all_reg = 0;
+
+ if (!(se_sess) || !(se_lun)) {
+ printk(KERN_ERR "SPC-3 PR: se_sess || struct se_lun is NULL!\n");
+ return PYX_TRANSPORT_LU_COMM_FAILURE;
+ }
+ /*
+ * Locate the existing *pr_reg via struct se_node_acl pointers
+ */
+ pr_reg = core_scsi3_locate_pr_reg(dev, se_sess->se_node_acl, se_sess);
+ if (!(pr_reg)) {
+ printk(KERN_ERR "SPC-3 PR: Unable to locate"
+ " PR_REGISTERED *pr_reg for RELEASE\n");
+ return PYX_TRANSPORT_LU_COMM_FAILURE;
+ }
+ /*
+ * From spc4r17 Section 5.7.11.2 Releasing:
+ *
+ * If there is no persistent reservation or in response to a persistent
+ * reservation release request from a registered I_T nexus that is not a
+ * persistent reservation holder (see 5.7.10), the device server shall
+ * do the following:
+ *
+ * a) Not release the persistent reservation, if any;
+ * b) Not remove any registrations; and
+ * c) Complete the command with GOOD status.
+ */
+ spin_lock(&dev->dev_reservation_lock);
+ pr_res_holder = dev->dev_pr_res_holder;
+ if (!(pr_res_holder)) {
+ /*
+ * No persistent reservation, return GOOD status.
+ */
+ spin_unlock(&dev->dev_reservation_lock);
+ core_scsi3_put_pr_reg(pr_reg);
+ return PYX_TRANSPORT_SENT_TO_TRANSPORT;
+ }
+ if ((pr_res_holder->pr_res_type == PR_TYPE_WRITE_EXCLUSIVE_ALLREG) ||
+ (pr_res_holder->pr_res_type == PR_TYPE_EXCLUSIVE_ACCESS_ALLREG))
+ all_reg = 1;
+
+ if ((all_reg == 0) && (pr_res_holder != pr_reg)) {
+ /*
+ * Non 'All Registrants' PR Type cases..
+ * Release request from a registered I_T nexus that is not a
+ * persistent reservation holder. return GOOD status.
+ */
+ spin_unlock(&dev->dev_reservation_lock);
+ core_scsi3_put_pr_reg(pr_reg);
+ return PYX_TRANSPORT_SENT_TO_TRANSPORT;
+ }
+ /*
+ * From spc4r17 Section 5.7.11.2 Releasing:
+ *
+ * Only the persistent reservation holder (see 5.7.10) is allowed to
+ * release a persistent reservation.
+ *
+ * An application client releases the persistent reservation by issuing
+ * a PERSISTENT RESERVE OUT command with RELEASE service action through
+ * an I_T nexus that is a persistent reservation holder with the
+ * following parameters:
+ *
+ * a) RESERVATION KEY field set to the value of the reservation key
+ * that is registered with the logical unit for the I_T nexus;
+ */
+ if (res_key != pr_reg->pr_res_key) {
+ printk(KERN_ERR "SPC-3 PR RELEASE: Received res_key: 0x%016Lx"
+ " does not match existing SA REGISTER res_key:"
+ " 0x%016Lx\n", res_key, pr_reg->pr_res_key);
+ spin_unlock(&dev->dev_reservation_lock);
+ core_scsi3_put_pr_reg(pr_reg);
+ return PYX_TRANSPORT_RESERVATION_CONFLICT;
+ }
+ /*
+ * From spc4r17 Section 5.7.11.2 Releasing and above:
+ *
+ * b) TYPE field and SCOPE field set to match the persistent
+ * reservation being released.
+ */
+ if ((pr_res_holder->pr_res_type != type) ||
+ (pr_res_holder->pr_res_scope != scope)) {
+ struct se_node_acl *pr_res_nacl = pr_res_holder->pr_reg_nacl;
+ printk(KERN_ERR "SPC-3 PR RELEASE: Attempted to release"
+ " reservation from [%s]: %s with different TYPE "
+ "and/or SCOPE while reservation already held by"
+ " [%s]: %s, returning RESERVATION_CONFLICT\n",
+ CMD_TFO(cmd)->get_fabric_name(),
+ se_sess->se_node_acl->initiatorname,
+ TPG_TFO(pr_res_nacl->se_tpg)->get_fabric_name(),
+ pr_res_holder->pr_reg_nacl->initiatorname);
+
+ spin_unlock(&dev->dev_reservation_lock);
+ core_scsi3_put_pr_reg(pr_reg);
+ return PYX_TRANSPORT_RESERVATION_CONFLICT;
+ }
+ /*
+ * In response to a persistent reservation release request from the
+ * persistent reservation holder the device server shall perform a
+ * release by doing the following as an uninterrupted series of actions:
+ * a) Release the persistent reservation;
+ * b) Not remove any registration(s);
+ * c) If the released persistent reservation is a registrants only type
+ * or all registrants type persistent reservation,
+ * the device server shall establish a unit attention condition for
+ * the initiator port associated with every regis-
+ * tered I_T nexus other than I_T nexus on which the PERSISTENT
+ * RESERVE OUT command with RELEASE service action was received,
+ * with the additional sense code set to RESERVATIONS RELEASED; and
+ * d) If the persistent reservation is of any other type, the device
+ * server shall not establish a unit attention condition.
+ */
+ __core_scsi3_complete_pro_release(dev, se_sess->se_node_acl,
+ pr_reg, 1);
+
+ spin_unlock(&dev->dev_reservation_lock);
+
+ if ((type != PR_TYPE_WRITE_EXCLUSIVE_REGONLY) &&
+ (type != PR_TYPE_EXCLUSIVE_ACCESS_REGONLY) &&
+ (type != PR_TYPE_WRITE_EXCLUSIVE_ALLREG) &&
+ (type != PR_TYPE_EXCLUSIVE_ACCESS_ALLREG)) {
+ /*
+ * If no UNIT ATTENTION conditions will be established for
+ * PR_TYPE_WRITE_EXCLUSIVE or PR_TYPE_EXCLUSIVE_ACCESS
+ * go ahead and check for APTPL=1 update+write below
+ */
+ goto write_aptpl;
+ }
+
+ spin_lock(&pr_tmpl->registration_lock);
+ list_for_each_entry(pr_reg_p, &pr_tmpl->registration_list,
+ pr_reg_list) {
+ /*
+ * Do not establish a UNIT ATTENTION condition
+ * for the calling I_T Nexus
+ */
+ if (pr_reg_p == pr_reg)
+ continue;
+
+ core_scsi3_ua_allocate(pr_reg_p->pr_reg_nacl,
+ pr_reg_p->pr_res_mapped_lun,
+ 0x2A, ASCQ_2AH_RESERVATIONS_RELEASED);
+ }
+ spin_unlock(&pr_tmpl->registration_lock);
+
+write_aptpl:
+ if (pr_tmpl->pr_aptpl_active) {
+ ret = core_scsi3_update_and_write_aptpl(SE_DEV(cmd),
+ &pr_reg->pr_aptpl_buf[0],
+ pr_tmpl->pr_aptpl_buf_len);
+ if (!(ret))
+ printk("SPC-3 PR: Updated APTPL metadata for RELEASE\n");
+ }
+
+ core_scsi3_put_pr_reg(pr_reg);
+ return 0;
+}
+
+static int core_scsi3_emulate_pro_clear(
+ struct se_cmd *cmd,
+ u64 res_key)
+{
+ struct se_device *dev = cmd->se_dev;
+ struct se_node_acl *pr_reg_nacl;
+ struct se_session *se_sess = SE_SESS(cmd);
+ struct t10_reservation_template *pr_tmpl = &SU_DEV(dev)->t10_reservation;
+ struct t10_pr_registration *pr_reg, *pr_reg_tmp, *pr_reg_n, *pr_res_holder;
+ u32 pr_res_mapped_lun = 0;
+ int calling_it_nexus = 0;
+ /*
+ * Locate the existing *pr_reg via struct se_node_acl pointers
+ */
+ pr_reg_n = core_scsi3_locate_pr_reg(SE_DEV(cmd),
+ se_sess->se_node_acl, se_sess);
+ if (!(pr_reg_n)) {
+ printk(KERN_ERR "SPC-3 PR: Unable to locate"
+ " PR_REGISTERED *pr_reg for CLEAR\n");
+ return PYX_TRANSPORT_LU_COMM_FAILURE;
+ }
+ /*
+ * From spc4r17 section 5.7.11.6, Clearing:
+ *
+ * Any application client may release the persistent reservation and
+ * remove all registrations from a device server by issuing a
+ * PERSISTENT RESERVE OUT command with CLEAR service action through a
+ * registered I_T nexus with the following parameter:
+ *
+ * a) RESERVATION KEY field set to the value of the reservation key
+ * that is registered with the logical unit for the I_T nexus.
+ */
+ if (res_key != pr_reg_n->pr_res_key) {
+ printk(KERN_ERR "SPC-3 PR REGISTER: Received"
+ " res_key: 0x%016Lx does not match"
+ " existing SA REGISTER res_key:"
+ " 0x%016Lx\n", res_key, pr_reg_n->pr_res_key);
+ core_scsi3_put_pr_reg(pr_reg_n);
+ return PYX_TRANSPORT_RESERVATION_CONFLICT;
+ }
+ /*
+ * a) Release the persistent reservation, if any;
+ */
+ spin_lock(&dev->dev_reservation_lock);
+ pr_res_holder = dev->dev_pr_res_holder;
+ if (pr_res_holder) {
+ struct se_node_acl *pr_res_nacl = pr_res_holder->pr_reg_nacl;
+ __core_scsi3_complete_pro_release(dev, pr_res_nacl,
+ pr_res_holder, 0);
+ }
+ spin_unlock(&dev->dev_reservation_lock);
+ /*
+ * b) Remove all registration(s) (see spc4r17 5.7.7);
+ */
+ spin_lock(&pr_tmpl->registration_lock);
+ list_for_each_entry_safe(pr_reg, pr_reg_tmp,
+ &pr_tmpl->registration_list, pr_reg_list) {
+
+ calling_it_nexus = (pr_reg_n == pr_reg) ? 1 : 0;
+ pr_reg_nacl = pr_reg->pr_reg_nacl;
+ pr_res_mapped_lun = pr_reg->pr_res_mapped_lun;
+ __core_scsi3_free_registration(dev, pr_reg, NULL,
+ calling_it_nexus);
+ /*
+ * e) Establish a unit attention condition for the initiator
+ * port associated with every registered I_T nexus other
+ * than the I_T nexus on which the PERSISTENT RESERVE OUT
+ * command with CLEAR service action was received, with the
+ * additional sense code set to RESERVATIONS PREEMPTED.
+ */
+ if (!(calling_it_nexus))
+ core_scsi3_ua_allocate(pr_reg_nacl, pr_res_mapped_lun,
+ 0x2A, ASCQ_2AH_RESERVATIONS_PREEMPTED);
+ }
+ spin_unlock(&pr_tmpl->registration_lock);
+
+ printk(KERN_INFO "SPC-3 PR [%s] Service Action: CLEAR complete\n",
+ CMD_TFO(cmd)->get_fabric_name());
+
+ if (pr_tmpl->pr_aptpl_active) {
+ core_scsi3_update_and_write_aptpl(SE_DEV(cmd), NULL, 0);
+ printk(KERN_INFO "SPC-3 PR: Updated APTPL metadata"
+ " for CLEAR\n");
+ }
+
+ core_scsi3_pr_generation(dev);
+ return 0;
+}
+
+/*
+ * Called with struct se_device->dev_reservation_lock held.
+ */
+static void __core_scsi3_complete_pro_preempt(
+ struct se_device *dev,
+ struct t10_pr_registration *pr_reg,
+ struct list_head *preempt_and_abort_list,
+ int type,
+ int scope,
+ int abort)
+{
+ struct se_node_acl *nacl = pr_reg->pr_reg_nacl;
+ struct target_core_fabric_ops *tfo = nacl->se_tpg->se_tpg_tfo;
+ char i_buf[PR_REG_ISID_ID_LEN];
+ int prf_isid;
+
+ memset(i_buf, 0, PR_REG_ISID_ID_LEN);
+ prf_isid = core_pr_dump_initiator_port(pr_reg, &i_buf[0],
+ PR_REG_ISID_ID_LEN);
+ /*
+ * Do an implict RELEASE of the existing reservation.
+ */
+ if (dev->dev_pr_res_holder)
+ __core_scsi3_complete_pro_release(dev, nacl,
+ dev->dev_pr_res_holder, 0);
+
+ dev->dev_pr_res_holder = pr_reg;
+ pr_reg->pr_res_holder = 1;
+ pr_reg->pr_res_type = type;
+ pr_reg->pr_res_scope = scope;
+
+ printk(KERN_INFO "SPC-3 PR [%s] Service Action: PREEMPT%s created new"
+ " reservation holder TYPE: %s ALL_TG_PT: %d\n",
+ tfo->get_fabric_name(), (abort) ? "_AND_ABORT" : "",
+ core_scsi3_pr_dump_type(type),
+ (pr_reg->pr_reg_all_tg_pt) ? 1 : 0);
+ printk(KERN_INFO "SPC-3 PR [%s] PREEMPT%s from Node: %s%s\n",
+ tfo->get_fabric_name(), (abort) ? "_AND_ABORT" : "",
+ nacl->initiatorname, (prf_isid) ? &i_buf[0] : "");
+ /*
+ * For PREEMPT_AND_ABORT, add the preempting reservation's
+ * struct t10_pr_registration to the list that will be compared
+ * against received CDBs..
+ */
+ if (preempt_and_abort_list)
+ list_add_tail(&pr_reg->pr_reg_abort_list,
+ preempt_and_abort_list);
+}
+
+static void core_scsi3_release_preempt_and_abort(
+ struct list_head *preempt_and_abort_list,
+ struct t10_pr_registration *pr_reg_holder)
+{
+ struct t10_pr_registration *pr_reg, *pr_reg_tmp;
+
+ list_for_each_entry_safe(pr_reg, pr_reg_tmp, preempt_and_abort_list,
+ pr_reg_abort_list) {
+
+ list_del(&pr_reg->pr_reg_abort_list);
+ if (pr_reg_holder == pr_reg)
+ continue;
+ if (pr_reg->pr_res_holder) {
+ printk(KERN_WARNING "pr_reg->pr_res_holder still set\n");
+ continue;
+ }
+
+ pr_reg->pr_reg_deve = NULL;
+ pr_reg->pr_reg_nacl = NULL;
+ kfree(pr_reg->pr_aptpl_buf);
+ kmem_cache_free(t10_pr_reg_cache, pr_reg);
+ }
+}
+
+int core_scsi3_check_cdb_abort_and_preempt(
+ struct list_head *preempt_and_abort_list,
+ struct se_cmd *cmd)
+{
+ struct t10_pr_registration *pr_reg, *pr_reg_tmp;
+
+ list_for_each_entry_safe(pr_reg, pr_reg_tmp, preempt_and_abort_list,
+ pr_reg_abort_list) {
+ if (pr_reg->pr_res_key == cmd->pr_res_key)
+ return 0;
+ }
+
+ return 1;
+}
+
+static int core_scsi3_pro_preempt(
+ struct se_cmd *cmd,
+ int type,
+ int scope,
+ u64 res_key,
+ u64 sa_res_key,
+ int abort)
+{
+ struct se_device *dev = SE_DEV(cmd);
+ struct se_dev_entry *se_deve;
+ struct se_node_acl *pr_reg_nacl;
+ struct se_session *se_sess = SE_SESS(cmd);
+ struct list_head preempt_and_abort_list;
+ struct t10_pr_registration *pr_reg, *pr_reg_tmp, *pr_reg_n, *pr_res_holder;
+ struct t10_reservation_template *pr_tmpl = &SU_DEV(dev)->t10_reservation;
+ u32 pr_res_mapped_lun = 0;
+ int all_reg = 0, calling_it_nexus = 0, released_regs = 0;
+ int prh_type = 0, prh_scope = 0, ret;
+
+ if (!(se_sess))
+ return PYX_TRANSPORT_LU_COMM_FAILURE;
+
+ se_deve = &se_sess->se_node_acl->device_list[cmd->orig_fe_lun];
+ pr_reg_n = core_scsi3_locate_pr_reg(SE_DEV(cmd), se_sess->se_node_acl,
+ se_sess);
+ if (!(pr_reg_n)) {
+ printk(KERN_ERR "SPC-3 PR: Unable to locate"
+ " PR_REGISTERED *pr_reg for PREEMPT%s\n",
+ (abort) ? "_AND_ABORT" : "");
+ return PYX_TRANSPORT_RESERVATION_CONFLICT;
+ }
+ if (pr_reg_n->pr_res_key != res_key) {
+ core_scsi3_put_pr_reg(pr_reg_n);
+ return PYX_TRANSPORT_RESERVATION_CONFLICT;
+ }
+ if (scope != PR_SCOPE_LU_SCOPE) {
+ printk(KERN_ERR "SPC-3 PR: Illegal SCOPE: 0x%02x\n", scope);
+ core_scsi3_put_pr_reg(pr_reg_n);
+ return PYX_TRANSPORT_INVALID_PARAMETER_LIST;
+ }
+ INIT_LIST_HEAD(&preempt_and_abort_list);
+
+ spin_lock(&dev->dev_reservation_lock);
+ pr_res_holder = dev->dev_pr_res_holder;
+ if (pr_res_holder &&
+ ((pr_res_holder->pr_res_type == PR_TYPE_WRITE_EXCLUSIVE_ALLREG) ||
+ (pr_res_holder->pr_res_type == PR_TYPE_EXCLUSIVE_ACCESS_ALLREG)))
+ all_reg = 1;
+
+ if (!(all_reg) && !(sa_res_key)) {
+ spin_unlock(&dev->dev_reservation_lock);
+ core_scsi3_put_pr_reg(pr_reg_n);
+ return PYX_TRANSPORT_INVALID_PARAMETER_LIST;
+ }
+ /*
+ * From spc4r17, section 5.7.11.4.4 Removing Registrations:
+ *
+ * If the SERVICE ACTION RESERVATION KEY field does not identify a
+ * persistent reservation holder or there is no persistent reservation
+ * holder (i.e., there is no persistent reservation), then the device
+ * server shall perform a preempt by doing the following in an
+ * uninterrupted series of actions. (See below..)
+ */
+ if (!(pr_res_holder) || (pr_res_holder->pr_res_key != sa_res_key)) {
+ /*
+ * No existing or SA Reservation Key matching reservations..
+ *
+ * PROUT SA PREEMPT with All Registrant type reservations are
+ * allowed to be processed without a matching SA Reservation Key
+ */
+ spin_lock(&pr_tmpl->registration_lock);
+ list_for_each_entry_safe(pr_reg, pr_reg_tmp,
+ &pr_tmpl->registration_list, pr_reg_list) {
+ /*
+ * Removing of registrations in non all registrants
+ * type reservations without a matching SA reservation
+ * key.
+ *
+ * a) Remove the registrations for all I_T nexuses
+ * specified by the SERVICE ACTION RESERVATION KEY
+ * field;
+ * b) Ignore the contents of the SCOPE and TYPE fields;
+ * c) Process tasks as defined in 5.7.1; and
+ * d) Establish a unit attention condition for the
+ * initiator port associated with every I_T nexus
+ * that lost its registration other than the I_T
+ * nexus on which the PERSISTENT RESERVE OUT command
+ * was received, with the additional sense code set
+ * to REGISTRATIONS PREEMPTED.
+ */
+ if (!(all_reg)) {
+ if (pr_reg->pr_res_key != sa_res_key)
+ continue;
+
+ calling_it_nexus = (pr_reg_n == pr_reg) ? 1 : 0;
+ pr_reg_nacl = pr_reg->pr_reg_nacl;
+ pr_res_mapped_lun = pr_reg->pr_res_mapped_lun;
+ __core_scsi3_free_registration(dev, pr_reg,
+ (abort) ? &preempt_and_abort_list :
+ NULL, calling_it_nexus);
+ released_regs++;
+ } else {
+ /*
+ * Case for any existing all registrants type
+ * reservation, follow logic in spc4r17 section
+ * 5.7.11.4 Preempting, Table 52 and Figure 7.
+ *
+ * For a ZERO SA Reservation key, release
+ * all other registrations and do an implict
+ * release of active persistent reservation.
+ *
+ * For a non-ZERO SA Reservation key, only
+ * release the matching reservation key from
+ * registrations.
+ */
+ if ((sa_res_key) &&
+ (pr_reg->pr_res_key != sa_res_key))
+ continue;
+
+ calling_it_nexus = (pr_reg_n == pr_reg) ? 1 : 0;
+ if (calling_it_nexus)
+ continue;
+
+ pr_reg_nacl = pr_reg->pr_reg_nacl;
+ pr_res_mapped_lun = pr_reg->pr_res_mapped_lun;
+ __core_scsi3_free_registration(dev, pr_reg,
+ (abort) ? &preempt_and_abort_list :
+ NULL, 0);
+ released_regs++;
+ }
+ if (!(calling_it_nexus))
+ core_scsi3_ua_allocate(pr_reg_nacl,
+ pr_res_mapped_lun, 0x2A,
+ ASCQ_2AH_RESERVATIONS_PREEMPTED);
+ }
+ spin_unlock(&pr_tmpl->registration_lock);
+ /*
+ * If a PERSISTENT RESERVE OUT with a PREEMPT service action or
+ * a PREEMPT AND ABORT service action sets the SERVICE ACTION
+ * RESERVATION KEY field to a value that does not match any
+ * registered reservation key, then the device server shall
+ * complete the command with RESERVATION CONFLICT status.
+ */
+ if (!(released_regs)) {
+ spin_unlock(&dev->dev_reservation_lock);
+ core_scsi3_put_pr_reg(pr_reg_n);
+ return PYX_TRANSPORT_RESERVATION_CONFLICT;
+ }
+ /*
+ * For an existing all registrants type reservation
+ * with a zero SA rservation key, preempt the existing
+ * reservation with the new PR type and scope.
+ */
+ if (pr_res_holder && all_reg && !(sa_res_key)) {
+ __core_scsi3_complete_pro_preempt(dev, pr_reg_n,
+ (abort) ? &preempt_and_abort_list : NULL,
+ type, scope, abort);
+
+ if (abort)
+ core_scsi3_release_preempt_and_abort(
+ &preempt_and_abort_list, pr_reg_n);
+ }
+ spin_unlock(&dev->dev_reservation_lock);
+
+ if (pr_tmpl->pr_aptpl_active) {
+ ret = core_scsi3_update_and_write_aptpl(SE_DEV(cmd),
+ &pr_reg_n->pr_aptpl_buf[0],
+ pr_tmpl->pr_aptpl_buf_len);
+ if (!(ret))
+ printk(KERN_INFO "SPC-3 PR: Updated APTPL"
+ " metadata for PREEMPT%s\n", (abort) ?
+ "_AND_ABORT" : "");
+ }
+
+ core_scsi3_put_pr_reg(pr_reg_n);
+ core_scsi3_pr_generation(SE_DEV(cmd));
+ return 0;
+ }
+ /*
+ * The PREEMPTing SA reservation key matches that of the
+ * existing persistent reservation, first, we check if
+ * we are preempting our own reservation.
+ * From spc4r17, section 5.7.11.4.3 Preempting
+ * persistent reservations and registration handling
+ *
+ * If an all registrants persistent reservation is not
+ * present, it is not an error for the persistent
+ * reservation holder to preempt itself (i.e., a
+ * PERSISTENT RESERVE OUT with a PREEMPT service action
+ * or a PREEMPT AND ABORT service action with the
+ * SERVICE ACTION RESERVATION KEY value equal to the
+ * persistent reservation holder's reservation key that
+ * is received from the persistent reservation holder).
+ * In that case, the device server shall establish the
+ * new persistent reservation and maintain the
+ * registration.
+ */
+ prh_type = pr_res_holder->pr_res_type;
+ prh_scope = pr_res_holder->pr_res_scope;
+ /*
+ * If the SERVICE ACTION RESERVATION KEY field identifies a
+ * persistent reservation holder (see 5.7.10), the device
+ * server shall perform a preempt by doing the following as
+ * an uninterrupted series of actions:
+ *
+ * a) Release the persistent reservation for the holder
+ * identified by the SERVICE ACTION RESERVATION KEY field;
+ */
+ if (pr_reg_n != pr_res_holder)
+ __core_scsi3_complete_pro_release(dev,
+ pr_res_holder->pr_reg_nacl,
+ dev->dev_pr_res_holder, 0);
+ /*
+ * b) Remove the registrations for all I_T nexuses identified
+ * by the SERVICE ACTION RESERVATION KEY field, except the
+ * I_T nexus that is being used for the PERSISTENT RESERVE
+ * OUT command. If an all registrants persistent reservation
+ * is present and the SERVICE ACTION RESERVATION KEY field
+ * is set to zero, then all registrations shall be removed
+ * except for that of the I_T nexus that is being used for
+ * the PERSISTENT RESERVE OUT command;
+ */
+ spin_lock(&pr_tmpl->registration_lock);
+ list_for_each_entry_safe(pr_reg, pr_reg_tmp,
+ &pr_tmpl->registration_list, pr_reg_list) {
+
+ calling_it_nexus = (pr_reg_n == pr_reg) ? 1 : 0;
+ if (calling_it_nexus)
+ continue;
+
+ if (pr_reg->pr_res_key != sa_res_key)
+ continue;
+
+ pr_reg_nacl = pr_reg->pr_reg_nacl;
+ pr_res_mapped_lun = pr_reg->pr_res_mapped_lun;
+ __core_scsi3_free_registration(dev, pr_reg,
+ (abort) ? &preempt_and_abort_list : NULL,
+ calling_it_nexus);
+ /*
+ * e) Establish a unit attention condition for the initiator
+ * port associated with every I_T nexus that lost its
+ * persistent reservation and/or registration, with the
+ * additional sense code set to REGISTRATIONS PREEMPTED;
+ */
+ core_scsi3_ua_allocate(pr_reg_nacl, pr_res_mapped_lun, 0x2A,
+ ASCQ_2AH_RESERVATIONS_PREEMPTED);
+ }
+ spin_unlock(&pr_tmpl->registration_lock);
+ /*
+ * c) Establish a persistent reservation for the preempting
+ * I_T nexus using the contents of the SCOPE and TYPE fields;
+ */
+ __core_scsi3_complete_pro_preempt(dev, pr_reg_n,
+ (abort) ? &preempt_and_abort_list : NULL,
+ type, scope, abort);
+ /*
+ * d) Process tasks as defined in 5.7.1;
+ * e) See above..
+ * f) If the type or scope has changed, then for every I_T nexus
+ * whose reservation key was not removed, except for the I_T
+ * nexus on which the PERSISTENT RESERVE OUT command was
+ * received, the device server shall establish a unit
+ * attention condition for the initiator port associated with
+ * that I_T nexus, with the additional sense code set to
+ * RESERVATIONS RELEASED. If the type or scope have not
+ * changed, then no unit attention condition(s) shall be
+ * established for this reason.
+ */
+ if ((prh_type != type) || (prh_scope != scope)) {
+ spin_lock(&pr_tmpl->registration_lock);
+ list_for_each_entry_safe(pr_reg, pr_reg_tmp,
+ &pr_tmpl->registration_list, pr_reg_list) {
+
+ calling_it_nexus = (pr_reg_n == pr_reg) ? 1 : 0;
+ if (calling_it_nexus)
+ continue;
+
+ core_scsi3_ua_allocate(pr_reg->pr_reg_nacl,
+ pr_reg->pr_res_mapped_lun, 0x2A,
+ ASCQ_2AH_RESERVATIONS_RELEASED);
+ }
+ spin_unlock(&pr_tmpl->registration_lock);
+ }
+ spin_unlock(&dev->dev_reservation_lock);
+ /*
+ * Call LUN_RESET logic upon list of struct t10_pr_registration,
+ * All received CDBs for the matching existing reservation and
+ * registrations undergo ABORT_TASK logic.
+ *
+ * From there, core_scsi3_release_preempt_and_abort() will
+ * release every registration in the list (which have already
+ * been removed from the primary pr_reg list), except the
+ * new persistent reservation holder, the calling Initiator Port.
+ */
+ if (abort) {
+ core_tmr_lun_reset(dev, NULL, &preempt_and_abort_list, cmd);
+ core_scsi3_release_preempt_and_abort(&preempt_and_abort_list,
+ pr_reg_n);
+ }
+
+ if (pr_tmpl->pr_aptpl_active) {
+ ret = core_scsi3_update_and_write_aptpl(SE_DEV(cmd),
+ &pr_reg_n->pr_aptpl_buf[0],
+ pr_tmpl->pr_aptpl_buf_len);
+ if (!(ret))
+ printk("SPC-3 PR: Updated APTPL metadata for PREEMPT"
+ "%s\n", (abort) ? "_AND_ABORT" : "");
+ }
+
+ core_scsi3_put_pr_reg(pr_reg_n);
+ core_scsi3_pr_generation(SE_DEV(cmd));
+ return 0;
+}
+
+static int core_scsi3_emulate_pro_preempt(
+ struct se_cmd *cmd,
+ int type,
+ int scope,
+ u64 res_key,
+ u64 sa_res_key,
+ int abort)
+{
+ int ret = 0;
+
+ switch (type) {
+ case PR_TYPE_WRITE_EXCLUSIVE:
+ case PR_TYPE_EXCLUSIVE_ACCESS:
+ case PR_TYPE_WRITE_EXCLUSIVE_REGONLY:
+ case PR_TYPE_EXCLUSIVE_ACCESS_REGONLY:
+ case PR_TYPE_WRITE_EXCLUSIVE_ALLREG:
+ case PR_TYPE_EXCLUSIVE_ACCESS_ALLREG:
+ ret = core_scsi3_pro_preempt(cmd, type, scope,
+ res_key, sa_res_key, abort);
+ break;
+ default:
+ printk(KERN_ERR "SPC-3 PR: Unknown Service Action PREEMPT%s"
+ " Type: 0x%02x\n", (abort) ? "_AND_ABORT" : "", type);
+ return PYX_TRANSPORT_INVALID_CDB_FIELD;
+ }
+
+ return ret;
+}
+
+
+static int core_scsi3_emulate_pro_register_and_move(
+ struct se_cmd *cmd,
+ u64 res_key,
+ u64 sa_res_key,
+ int aptpl,
+ int unreg)
+{
+ struct se_session *se_sess = SE_SESS(cmd);
+ struct se_device *dev = SE_DEV(cmd);
+ struct se_dev_entry *se_deve, *dest_se_deve = NULL;
+ struct se_lun *se_lun = SE_LUN(cmd);
+ struct se_node_acl *pr_res_nacl, *pr_reg_nacl, *dest_node_acl = NULL;
+ struct se_port *se_port;
+ struct se_portal_group *se_tpg, *dest_se_tpg = NULL;
+ struct target_core_fabric_ops *dest_tf_ops = NULL, *tf_ops;
+ struct t10_pr_registration *pr_reg, *pr_res_holder, *dest_pr_reg;
+ struct t10_reservation_template *pr_tmpl = &SU_DEV(dev)->t10_reservation;
+ unsigned char *buf = (unsigned char *)T_TASK(cmd)->t_task_buf;
+ unsigned char *initiator_str;
+ char *iport_ptr = NULL, dest_iport[64], i_buf[PR_REG_ISID_ID_LEN];
+ u32 tid_len, tmp_tid_len;
+ int new_reg = 0, type, scope, ret, matching_iname, prf_isid;
+ unsigned short rtpi;
+ unsigned char proto_ident;
+
+ if (!(se_sess) || !(se_lun)) {
+ printk(KERN_ERR "SPC-3 PR: se_sess || struct se_lun is NULL!\n");
+ return PYX_TRANSPORT_LU_COMM_FAILURE;
+ }
+ memset(dest_iport, 0, 64);
+ memset(i_buf, 0, PR_REG_ISID_ID_LEN);
+ se_tpg = se_sess->se_tpg;
+ tf_ops = TPG_TFO(se_tpg);
+ se_deve = &se_sess->se_node_acl->device_list[cmd->orig_fe_lun];
+ /*
+ * Follow logic from spc4r17 Section 5.7.8, Table 50 --
+ * Register behaviors for a REGISTER AND MOVE service action
+ *
+ * Locate the existing *pr_reg via struct se_node_acl pointers
+ */
+ pr_reg = core_scsi3_locate_pr_reg(SE_DEV(cmd), se_sess->se_node_acl,
+ se_sess);
+ if (!(pr_reg)) {
+ printk(KERN_ERR "SPC-3 PR: Unable to locate PR_REGISTERED"
+ " *pr_reg for REGISTER_AND_MOVE\n");
+ return PYX_TRANSPORT_LU_COMM_FAILURE;
+ }
+ /*
+ * The provided reservation key much match the existing reservation key
+ * provided during this initiator's I_T nexus registration.
+ */
+ if (res_key != pr_reg->pr_res_key) {
+ printk(KERN_WARNING "SPC-3 PR REGISTER_AND_MOVE: Received"
+ " res_key: 0x%016Lx does not match existing SA REGISTER"
+ " res_key: 0x%016Lx\n", res_key, pr_reg->pr_res_key);
+ core_scsi3_put_pr_reg(pr_reg);
+ return PYX_TRANSPORT_RESERVATION_CONFLICT;
+ }
+ /*
+ * The service active reservation key needs to be non zero
+ */
+ if (!(sa_res_key)) {
+ printk(KERN_WARNING "SPC-3 PR REGISTER_AND_MOVE: Received zero"
+ " sa_res_key\n");
+ core_scsi3_put_pr_reg(pr_reg);
+ return PYX_TRANSPORT_INVALID_PARAMETER_LIST;
+ }
+ /*
+ * Determine the Relative Target Port Identifier where the reservation
+ * will be moved to for the TransportID containing SCSI initiator WWN
+ * information.
+ */
+ rtpi = (buf[18] & 0xff) << 8;
+ rtpi |= buf[19] & 0xff;
+ tid_len = (buf[20] & 0xff) << 24;
+ tid_len |= (buf[21] & 0xff) << 16;
+ tid_len |= (buf[22] & 0xff) << 8;
+ tid_len |= buf[23] & 0xff;
+
+ if ((tid_len + 24) != cmd->data_length) {
+ printk(KERN_ERR "SPC-3 PR: Illegal tid_len: %u + 24 byte header"
+ " does not equal CDB data_length: %u\n", tid_len,
+ cmd->data_length);
+ core_scsi3_put_pr_reg(pr_reg);
+ return PYX_TRANSPORT_INVALID_PARAMETER_LIST;
+ }
+
+ spin_lock(&dev->se_port_lock);
+ list_for_each_entry(se_port, &dev->dev_sep_list, sep_list) {
+ if (se_port->sep_rtpi != rtpi)
+ continue;
+ dest_se_tpg = se_port->sep_tpg;
+ if (!(dest_se_tpg))
+ continue;
+ dest_tf_ops = TPG_TFO(dest_se_tpg);
+ if (!(dest_tf_ops))
+ continue;
+
+ atomic_inc(&dest_se_tpg->tpg_pr_ref_count);
+ smp_mb__after_atomic_inc();
+ spin_unlock(&dev->se_port_lock);
+
+ ret = core_scsi3_tpg_depend_item(dest_se_tpg);
+ if (ret != 0) {
+ printk(KERN_ERR "core_scsi3_tpg_depend_item() failed"
+ " for dest_se_tpg\n");
+ atomic_dec(&dest_se_tpg->tpg_pr_ref_count);
+ smp_mb__after_atomic_dec();
+ core_scsi3_put_pr_reg(pr_reg);
+ return PYX_TRANSPORT_LU_COMM_FAILURE;
+ }
+
+ spin_lock(&dev->se_port_lock);
+ break;
+ }
+ spin_unlock(&dev->se_port_lock);
+
+ if (!(dest_se_tpg) || (!dest_tf_ops)) {
+ printk(KERN_ERR "SPC-3 PR REGISTER_AND_MOVE: Unable to locate"
+ " fabric ops from Relative Target Port Identifier:"
+ " %hu\n", rtpi);
+ core_scsi3_put_pr_reg(pr_reg);
+ return PYX_TRANSPORT_INVALID_PARAMETER_LIST;
+ }
+ proto_ident = (buf[24] & 0x0f);
+#if 0
+ printk("SPC-3 PR REGISTER_AND_MOVE: Extracted Protocol Identifier:"
+ " 0x%02x\n", proto_ident);
+#endif
+ if (proto_ident != dest_tf_ops->get_fabric_proto_ident(dest_se_tpg)) {
+ printk(KERN_ERR "SPC-3 PR REGISTER_AND_MOVE: Received"
+ " proto_ident: 0x%02x does not match ident: 0x%02x"
+ " from fabric: %s\n", proto_ident,
+ dest_tf_ops->get_fabric_proto_ident(dest_se_tpg),
+ dest_tf_ops->get_fabric_name());
+ ret = PYX_TRANSPORT_INVALID_PARAMETER_LIST;
+ goto out;
+ }
+ if (dest_tf_ops->tpg_parse_pr_out_transport_id == NULL) {
+ printk(KERN_ERR "SPC-3 PR REGISTER_AND_MOVE: Fabric does not"
+ " containg a valid tpg_parse_pr_out_transport_id"
+ " function pointer\n");
+ ret = PYX_TRANSPORT_LU_COMM_FAILURE;
+ goto out;
+ }
+ initiator_str = dest_tf_ops->tpg_parse_pr_out_transport_id(dest_se_tpg,
+ (const char *)&buf[24], &tmp_tid_len, &iport_ptr);
+ if (!(initiator_str)) {
+ printk(KERN_ERR "SPC-3 PR REGISTER_AND_MOVE: Unable to locate"
+ " initiator_str from Transport ID\n");
+ ret = PYX_TRANSPORT_INVALID_PARAMETER_LIST;
+ goto out;
+ }
+
+ printk(KERN_INFO "SPC-3 PR [%s] Extracted initiator %s identifier: %s"
+ " %s\n", dest_tf_ops->get_fabric_name(), (iport_ptr != NULL) ?
+ "port" : "device", initiator_str, (iport_ptr != NULL) ?
+ iport_ptr : "");
+ /*
+ * If a PERSISTENT RESERVE OUT command with a REGISTER AND MOVE service
+ * action specifies a TransportID that is the same as the initiator port
+ * of the I_T nexus for the command received, then the command shall
+ * be terminated with CHECK CONDITION status, with the sense key set to
+ * ILLEGAL REQUEST, and the additional sense code set to INVALID FIELD
+ * IN PARAMETER LIST.
+ */
+ pr_reg_nacl = pr_reg->pr_reg_nacl;
+ matching_iname = (!strcmp(initiator_str,
+ pr_reg_nacl->initiatorname)) ? 1 : 0;
+ if (!(matching_iname))
+ goto after_iport_check;
+
+ if (!(iport_ptr) || !(pr_reg->isid_present_at_reg)) {
+ printk(KERN_ERR "SPC-3 PR REGISTER_AND_MOVE: TransportID: %s"
+ " matches: %s on received I_T Nexus\n", initiator_str,
+ pr_reg_nacl->initiatorname);
+ ret = PYX_TRANSPORT_INVALID_PARAMETER_LIST;
+ goto out;
+ }
+ if (!(strcmp(iport_ptr, pr_reg->pr_reg_isid))) {
+ printk(KERN_ERR "SPC-3 PR REGISTER_AND_MOVE: TransportID: %s %s"
+ " matches: %s %s on received I_T Nexus\n",
+ initiator_str, iport_ptr, pr_reg_nacl->initiatorname,
+ pr_reg->pr_reg_isid);
+ ret = PYX_TRANSPORT_INVALID_PARAMETER_LIST;
+ goto out;
+ }
+after_iport_check:
+ /*
+ * Locate the destination struct se_node_acl from the received Transport ID
+ */
+ spin_lock_bh(&dest_se_tpg->acl_node_lock);
+ dest_node_acl = __core_tpg_get_initiator_node_acl(dest_se_tpg,
+ initiator_str);
+ if (dest_node_acl) {
+ atomic_inc(&dest_node_acl->acl_pr_ref_count);
+ smp_mb__after_atomic_inc();
+ }
+ spin_unlock_bh(&dest_se_tpg->acl_node_lock);
+
+ if (!(dest_node_acl)) {
+ printk(KERN_ERR "Unable to locate %s dest_node_acl for"
+ " TransportID%s\n", dest_tf_ops->get_fabric_name(),
+ initiator_str);
+ ret = PYX_TRANSPORT_INVALID_PARAMETER_LIST;
+ goto out;
+ }
+ ret = core_scsi3_nodeacl_depend_item(dest_node_acl);
+ if (ret != 0) {
+ printk(KERN_ERR "core_scsi3_nodeacl_depend_item() for"
+ " dest_node_acl\n");
+ atomic_dec(&dest_node_acl->acl_pr_ref_count);
+ smp_mb__after_atomic_dec();
+ dest_node_acl = NULL;
+ ret = PYX_TRANSPORT_LU_COMM_FAILURE;
+ goto out;
+ }
+#if 0
+ printk(KERN_INFO "SPC-3 PR REGISTER_AND_MOVE: Found %s dest_node_acl:"
+ " %s from TransportID\n", dest_tf_ops->get_fabric_name(),
+ dest_node_acl->initiatorname);
+#endif
+ /*
+ * Locate the struct se_dev_entry pointer for the matching RELATIVE TARGET
+ * PORT IDENTIFIER.
+ */
+ dest_se_deve = core_get_se_deve_from_rtpi(dest_node_acl, rtpi);
+ if (!(dest_se_deve)) {
+ printk(KERN_ERR "Unable to locate %s dest_se_deve from RTPI:"
+ " %hu\n", dest_tf_ops->get_fabric_name(), rtpi);
+ ret = PYX_TRANSPORT_INVALID_PARAMETER_LIST;
+ goto out;
+ }
+
+ ret = core_scsi3_lunacl_depend_item(dest_se_deve);
+ if (ret < 0) {
+ printk(KERN_ERR "core_scsi3_lunacl_depend_item() failed\n");
+ atomic_dec(&dest_se_deve->pr_ref_count);
+ smp_mb__after_atomic_dec();
+ dest_se_deve = NULL;
+ ret = PYX_TRANSPORT_LU_COMM_FAILURE;
+ goto out;
+ }
+#if 0
+ printk(KERN_INFO "SPC-3 PR REGISTER_AND_MOVE: Located %s node %s LUN"
+ " ACL for dest_se_deve->mapped_lun: %u\n",
+ dest_tf_ops->get_fabric_name(), dest_node_acl->initiatorname,
+ dest_se_deve->mapped_lun);
+#endif
+ /*
+ * A persistent reservation needs to already existing in order to
+ * successfully complete the REGISTER_AND_MOVE service action..
+ */
+ spin_lock(&dev->dev_reservation_lock);
+ pr_res_holder = dev->dev_pr_res_holder;
+ if (!(pr_res_holder)) {
+ printk(KERN_WARNING "SPC-3 PR REGISTER_AND_MOVE: No reservation"
+ " currently held\n");
+ spin_unlock(&dev->dev_reservation_lock);
+ ret = PYX_TRANSPORT_INVALID_CDB_FIELD;
+ goto out;
+ }
+ /*
+ * The received on I_T Nexus must be the reservation holder.
+ *
+ * From spc4r17 section 5.7.8 Table 50 --
+ * Register behaviors for a REGISTER AND MOVE service action
+ */
+ if (pr_res_holder != pr_reg) {
+ printk(KERN_WARNING "SPC-3 PR REGISTER_AND_MOVE: Calling I_T"
+ " Nexus is not reservation holder\n");
+ spin_unlock(&dev->dev_reservation_lock);
+ ret = PYX_TRANSPORT_RESERVATION_CONFLICT;
+ goto out;
+ }
+ /*
+ * From spc4r17 section 5.7.8: registering and moving reservation
+ *
+ * If a PERSISTENT RESERVE OUT command with a REGISTER AND MOVE service
+ * action is received and the established persistent reservation is a
+ * Write Exclusive - All Registrants type or Exclusive Access -
+ * All Registrants type reservation, then the command shall be completed
+ * with RESERVATION CONFLICT status.
+ */
+ if ((pr_res_holder->pr_res_type == PR_TYPE_WRITE_EXCLUSIVE_ALLREG) ||
+ (pr_res_holder->pr_res_type == PR_TYPE_EXCLUSIVE_ACCESS_ALLREG)) {
+ printk(KERN_WARNING "SPC-3 PR REGISTER_AND_MOVE: Unable to move"
+ " reservation for type: %s\n",
+ core_scsi3_pr_dump_type(pr_res_holder->pr_res_type));
+ spin_unlock(&dev->dev_reservation_lock);
+ ret = PYX_TRANSPORT_RESERVATION_CONFLICT;
+ goto out;
+ }
+ pr_res_nacl = pr_res_holder->pr_reg_nacl;
+ /*
+ * b) Ignore the contents of the (received) SCOPE and TYPE fields;
+ */
+ type = pr_res_holder->pr_res_type;
+ scope = pr_res_holder->pr_res_type;
+ /*
+ * c) Associate the reservation key specified in the SERVICE ACTION
+ * RESERVATION KEY field with the I_T nexus specified as the
+ * destination of the register and move, where:
+ * A) The I_T nexus is specified by the TransportID and the
+ * RELATIVE TARGET PORT IDENTIFIER field (see 6.14.4); and
+ * B) Regardless of the TransportID format used, the association for
+ * the initiator port is based on either the initiator port name
+ * (see 3.1.71) on SCSI transport protocols where port names are
+ * required or the initiator port identifier (see 3.1.70) on SCSI
+ * transport protocols where port names are not required;
+ * d) Register the reservation key specified in the SERVICE ACTION
+ * RESERVATION KEY field;
+ * e) Retain the reservation key specified in the SERVICE ACTION
+ * RESERVATION KEY field and associated information;
+ *
+ * Also, It is not an error for a REGISTER AND MOVE service action to
+ * register an I_T nexus that is already registered with the same
+ * reservation key or a different reservation key.
+ */
+ dest_pr_reg = __core_scsi3_locate_pr_reg(dev, dest_node_acl,
+ iport_ptr);
+ if (!(dest_pr_reg)) {
+ ret = core_scsi3_alloc_registration(SE_DEV(cmd),
+ dest_node_acl, dest_se_deve, iport_ptr,
+ sa_res_key, 0, aptpl, 2, 1);
+ if (ret != 0) {
+ spin_unlock(&dev->dev_reservation_lock);
+ ret = PYX_TRANSPORT_INVALID_PARAMETER_LIST;
+ goto out;
+ }
+ dest_pr_reg = __core_scsi3_locate_pr_reg(dev, dest_node_acl,
+ iport_ptr);
+ new_reg = 1;
+ }
+ /*
+ * f) Release the persistent reservation for the persistent reservation
+ * holder (i.e., the I_T nexus on which the
+ */
+ __core_scsi3_complete_pro_release(dev, pr_res_nacl,
+ dev->dev_pr_res_holder, 0);
+ /*
+ * g) Move the persistent reservation to the specified I_T nexus using
+ * the same scope and type as the persistent reservation released in
+ * item f); and
+ */
+ dev->dev_pr_res_holder = dest_pr_reg;
+ dest_pr_reg->pr_res_holder = 1;
+ dest_pr_reg->pr_res_type = type;
+ pr_reg->pr_res_scope = scope;
+ prf_isid = core_pr_dump_initiator_port(pr_reg, &i_buf[0],
+ PR_REG_ISID_ID_LEN);
+ /*
+ * Increment PRGeneration for existing registrations..
+ */
+ if (!(new_reg))
+ dest_pr_reg->pr_res_generation = pr_tmpl->pr_generation++;
+ spin_unlock(&dev->dev_reservation_lock);
+
+ printk(KERN_INFO "SPC-3 PR [%s] Service Action: REGISTER_AND_MOVE"
+ " created new reservation holder TYPE: %s on object RTPI:"
+ " %hu PRGeneration: 0x%08x\n", dest_tf_ops->get_fabric_name(),
+ core_scsi3_pr_dump_type(type), rtpi,
+ dest_pr_reg->pr_res_generation);
+ printk(KERN_INFO "SPC-3 PR Successfully moved reservation from"
+ " %s Fabric Node: %s%s -> %s Fabric Node: %s %s\n",
+ tf_ops->get_fabric_name(), pr_reg_nacl->initiatorname,
+ (prf_isid) ? &i_buf[0] : "", dest_tf_ops->get_fabric_name(),
+ dest_node_acl->initiatorname, (iport_ptr != NULL) ?
+ iport_ptr : "");
+ /*
+ * It is now safe to release configfs group dependencies for destination
+ * of Transport ID Initiator Device/Port Identifier
+ */
+ core_scsi3_lunacl_undepend_item(dest_se_deve);
+ core_scsi3_nodeacl_undepend_item(dest_node_acl);
+ core_scsi3_tpg_undepend_item(dest_se_tpg);
+ /*
+ * h) If the UNREG bit is set to one, unregister (see 5.7.11.3) the I_T
+ * nexus on which PERSISTENT RESERVE OUT command was received.
+ */
+ if (unreg) {
+ spin_lock(&pr_tmpl->registration_lock);
+ __core_scsi3_free_registration(dev, pr_reg, NULL, 1);
+ spin_unlock(&pr_tmpl->registration_lock);
+ } else
+ core_scsi3_put_pr_reg(pr_reg);
+
+ /*
+ * Clear the APTPL metadata if APTPL has been disabled, otherwise
+ * write out the updated metadata to struct file for this SCSI device.
+ */
+ if (!(aptpl)) {
+ pr_tmpl->pr_aptpl_active = 0;
+ core_scsi3_update_and_write_aptpl(SE_DEV(cmd), NULL, 0);
+ printk("SPC-3 PR: Set APTPL Bit Deactivated for"
+ " REGISTER_AND_MOVE\n");
+ } else {
+ pr_tmpl->pr_aptpl_active = 1;
+ ret = core_scsi3_update_and_write_aptpl(SE_DEV(cmd),
+ &dest_pr_reg->pr_aptpl_buf[0],
+ pr_tmpl->pr_aptpl_buf_len);
+ if (!(ret))
+ printk("SPC-3 PR: Set APTPL Bit Activated for"
+ " REGISTER_AND_MOVE\n");
+ }
+
+ core_scsi3_put_pr_reg(dest_pr_reg);
+ return 0;
+out:
+ if (dest_se_deve)
+ core_scsi3_lunacl_undepend_item(dest_se_deve);
+ if (dest_node_acl)
+ core_scsi3_nodeacl_undepend_item(dest_node_acl);
+ core_scsi3_tpg_undepend_item(dest_se_tpg);
+ core_scsi3_put_pr_reg(pr_reg);
+ return ret;
+}
+
+static unsigned long long core_scsi3_extract_reservation_key(unsigned char *cdb)
+{
+ unsigned int __v1, __v2;
+
+ __v1 = (cdb[0] << 24) | (cdb[1] << 16) | (cdb[2] << 8) | cdb[3];
+ __v2 = (cdb[4] << 24) | (cdb[5] << 16) | (cdb[6] << 8) | cdb[7];
+
+ return ((unsigned long long)__v2) | (unsigned long long)__v1 << 32;
+}
+
+/*
+ * See spc4r17 section 6.14 Table 170
+ */
+static int core_scsi3_emulate_pr_out(struct se_cmd *cmd, unsigned char *cdb)
+{
+ unsigned char *buf = (unsigned char *)T_TASK(cmd)->t_task_buf;
+ u64 res_key, sa_res_key;
+ int sa, scope, type, aptpl;
+ int spec_i_pt = 0, all_tg_pt = 0, unreg = 0;
+ /*
+ * FIXME: A NULL struct se_session pointer means an this is not coming from
+ * a $FABRIC_MOD's nexus, but from internal passthrough ops.
+ */
+ if (!(SE_SESS(cmd)))
+ return PYX_TRANSPORT_LU_COMM_FAILURE;
+
+ if (cmd->data_length < 24) {
+ printk(KERN_WARNING "SPC-PR: Recieved PR OUT parameter list"
+ " length too small: %u\n", cmd->data_length);
+ return PYX_TRANSPORT_INVALID_PARAMETER_LIST;
+ }
+ /*
+ * From the PERSISTENT_RESERVE_OUT command descriptor block (CDB)
+ */
+ sa = (cdb[1] & 0x1f);
+ scope = (cdb[2] & 0xf0);
+ type = (cdb[2] & 0x0f);
+ /*
+ * From PERSISTENT_RESERVE_OUT parameter list (payload)
+ */
+ res_key = core_scsi3_extract_reservation_key(&buf[0]);
+ sa_res_key = core_scsi3_extract_reservation_key(&buf[8]);
+ /*
+ * REGISTER_AND_MOVE uses a different SA parameter list containing
+ * SCSI TransportIDs.
+ */
+ if (sa != PRO_REGISTER_AND_MOVE) {
+ spec_i_pt = (buf[20] & 0x08);
+ all_tg_pt = (buf[20] & 0x04);
+ aptpl = (buf[20] & 0x01);
+ } else {
+ aptpl = (buf[17] & 0x01);
+ unreg = (buf[17] & 0x02);
+ }
+ /*
+ * SPEC_I_PT=1 is only valid for Service action: REGISTER
+ */
+ if (spec_i_pt && ((cdb[1] & 0x1f) != PRO_REGISTER))
+ return PYX_TRANSPORT_INVALID_PARAMETER_LIST;
+ /*
+ * From spc4r17 section 6.14:
+ *
+ * If the SPEC_I_PT bit is set to zero, the service action is not
+ * REGISTER AND MOVE, and the parameter list length is not 24, then
+ * the command shall be terminated with CHECK CONDITION status, with
+ * the sense key set to ILLEGAL REQUEST, and the additional sense
+ * code set to PARAMETER LIST LENGTH ERROR.
+ */
+ if (!(spec_i_pt) && ((cdb[1] & 0x1f) != PRO_REGISTER_AND_MOVE) &&
+ (cmd->data_length != 24)) {
+ printk(KERN_WARNING "SPC-PR: Recieved PR OUT illegal parameter"
+ " list length: %u\n", cmd->data_length);
+ return PYX_TRANSPORT_INVALID_PARAMETER_LIST;
+ }
+ /*
+ * (core_scsi3_emulate_pro_* function parameters
+ * are defined by spc4r17 Table 174:
+ * PERSISTENT_RESERVE_OUT service actions and valid parameters.
+ */
+ switch (sa) {
+ case PRO_REGISTER:
+ return core_scsi3_emulate_pro_register(cmd,
+ res_key, sa_res_key, aptpl, all_tg_pt, spec_i_pt, 0);
+ case PRO_RESERVE:
+ return core_scsi3_emulate_pro_reserve(cmd,
+ type, scope, res_key);
+ case PRO_RELEASE:
+ return core_scsi3_emulate_pro_release(cmd,
+ type, scope, res_key);
+ case PRO_CLEAR:
+ return core_scsi3_emulate_pro_clear(cmd, res_key);
+ case PRO_PREEMPT:
+ return core_scsi3_emulate_pro_preempt(cmd, type, scope,
+ res_key, sa_res_key, 0);
+ case PRO_PREEMPT_AND_ABORT:
+ return core_scsi3_emulate_pro_preempt(cmd, type, scope,
+ res_key, sa_res_key, 1);
+ case PRO_REGISTER_AND_IGNORE_EXISTING_KEY:
+ return core_scsi3_emulate_pro_register(cmd,
+ 0, sa_res_key, aptpl, all_tg_pt, spec_i_pt, 1);
+ case PRO_REGISTER_AND_MOVE:
+ return core_scsi3_emulate_pro_register_and_move(cmd, res_key,
+ sa_res_key, aptpl, unreg);
+ default:
+ printk(KERN_ERR "Unknown PERSISTENT_RESERVE_OUT service"
+ " action: 0x%02x\n", cdb[1] & 0x1f);
+ return PYX_TRANSPORT_INVALID_CDB_FIELD;
+ }
+
+ return PYX_TRANSPORT_INVALID_CDB_FIELD;
+}
+
+/*
+ * PERSISTENT_RESERVE_IN Service Action READ_KEYS
+ *
+ * See spc4r17 section 5.7.6.2 and section 6.13.2, Table 160
+ */
+static int core_scsi3_pri_read_keys(struct se_cmd *cmd)
+{
+ struct se_device *se_dev = SE_DEV(cmd);
+ struct se_subsystem_dev *su_dev = SU_DEV(se_dev);
+ struct t10_pr_registration *pr_reg;
+ unsigned char *buf = (unsigned char *)T_TASK(cmd)->t_task_buf;
+ u32 add_len = 0, off = 8;
+
+ if (cmd->data_length < 8) {
+ printk(KERN_ERR "PRIN SA READ_KEYS SCSI Data Length: %u"
+ " too small\n", cmd->data_length);
+ return PYX_TRANSPORT_INVALID_CDB_FIELD;
+ }
+
+ buf[0] = ((T10_RES(su_dev)->pr_generation >> 24) & 0xff);
+ buf[1] = ((T10_RES(su_dev)->pr_generation >> 16) & 0xff);
+ buf[2] = ((T10_RES(su_dev)->pr_generation >> 8) & 0xff);
+ buf[3] = (T10_RES(su_dev)->pr_generation & 0xff);
+
+ spin_lock(&T10_RES(su_dev)->registration_lock);
+ list_for_each_entry(pr_reg, &T10_RES(su_dev)->registration_list,
+ pr_reg_list) {
+ /*
+ * Check for overflow of 8byte PRI READ_KEYS payload and
+ * next reservation key list descriptor.
+ */
+ if ((add_len + 8) > (cmd->data_length - 8))
+ break;
+
+ buf[off++] = ((pr_reg->pr_res_key >> 56) & 0xff);
+ buf[off++] = ((pr_reg->pr_res_key >> 48) & 0xff);
+ buf[off++] = ((pr_reg->pr_res_key >> 40) & 0xff);
+ buf[off++] = ((pr_reg->pr_res_key >> 32) & 0xff);
+ buf[off++] = ((pr_reg->pr_res_key >> 24) & 0xff);
+ buf[off++] = ((pr_reg->pr_res_key >> 16) & 0xff);
+ buf[off++] = ((pr_reg->pr_res_key >> 8) & 0xff);
+ buf[off++] = (pr_reg->pr_res_key & 0xff);
+
+ add_len += 8;
+ }
+ spin_unlock(&T10_RES(su_dev)->registration_lock);
+
+ buf[4] = ((add_len >> 24) & 0xff);
+ buf[5] = ((add_len >> 16) & 0xff);
+ buf[6] = ((add_len >> 8) & 0xff);
+ buf[7] = (add_len & 0xff);
+
+ return 0;
+}
+
+/*
+ * PERSISTENT_RESERVE_IN Service Action READ_RESERVATION
+ *
+ * See spc4r17 section 5.7.6.3 and section 6.13.3.2 Table 161 and 162
+ */
+static int core_scsi3_pri_read_reservation(struct se_cmd *cmd)
+{
+ struct se_device *se_dev = SE_DEV(cmd);
+ struct se_subsystem_dev *su_dev = SU_DEV(se_dev);
+ struct t10_pr_registration *pr_reg;
+ unsigned char *buf = (unsigned char *)T_TASK(cmd)->t_task_buf;
+ u64 pr_res_key;
+ u32 add_len = 16; /* Hardcoded to 16 when a reservation is held. */
+
+ if (cmd->data_length < 8) {
+ printk(KERN_ERR "PRIN SA READ_RESERVATIONS SCSI Data Length: %u"
+ " too small\n", cmd->data_length);
+ return PYX_TRANSPORT_INVALID_CDB_FIELD;
+ }
+
+ buf[0] = ((T10_RES(su_dev)->pr_generation >> 24) & 0xff);
+ buf[1] = ((T10_RES(su_dev)->pr_generation >> 16) & 0xff);
+ buf[2] = ((T10_RES(su_dev)->pr_generation >> 8) & 0xff);
+ buf[3] = (T10_RES(su_dev)->pr_generation & 0xff);
+
+ spin_lock(&se_dev->dev_reservation_lock);
+ pr_reg = se_dev->dev_pr_res_holder;
+ if ((pr_reg)) {
+ /*
+ * Set the hardcoded Additional Length
+ */
+ buf[4] = ((add_len >> 24) & 0xff);
+ buf[5] = ((add_len >> 16) & 0xff);
+ buf[6] = ((add_len >> 8) & 0xff);
+ buf[7] = (add_len & 0xff);
+
+ if (cmd->data_length < 22) {
+ spin_unlock(&se_dev->dev_reservation_lock);
+ return 0;
+ }
+ /*
+ * Set the Reservation key.
+ *
+ * From spc4r17, section 5.7.10:
+ * A persistent reservation holder has its reservation key
+ * returned in the parameter data from a PERSISTENT
+ * RESERVE IN command with READ RESERVATION service action as
+ * follows:
+ * a) For a persistent reservation of the type Write Exclusive
+ * - All Registrants or Exclusive Access ­ All Regitrants,
+ * the reservation key shall be set to zero; or
+ * b) For all other persistent reservation types, the
+ * reservation key shall be set to the registered
+ * reservation key for the I_T nexus that holds the
+ * persistent reservation.
+ */
+ if ((pr_reg->pr_res_type == PR_TYPE_WRITE_EXCLUSIVE_ALLREG) ||
+ (pr_reg->pr_res_type == PR_TYPE_EXCLUSIVE_ACCESS_ALLREG))
+ pr_res_key = 0;
+ else
+ pr_res_key = pr_reg->pr_res_key;
+
+ buf[8] = ((pr_res_key >> 56) & 0xff);
+ buf[9] = ((pr_res_key >> 48) & 0xff);
+ buf[10] = ((pr_res_key >> 40) & 0xff);
+ buf[11] = ((pr_res_key >> 32) & 0xff);
+ buf[12] = ((pr_res_key >> 24) & 0xff);
+ buf[13] = ((pr_res_key >> 16) & 0xff);
+ buf[14] = ((pr_res_key >> 8) & 0xff);
+ buf[15] = (pr_res_key & 0xff);
+ /*
+ * Set the SCOPE and TYPE
+ */
+ buf[21] = (pr_reg->pr_res_scope & 0xf0) |
+ (pr_reg->pr_res_type & 0x0f);
+ }
+ spin_unlock(&se_dev->dev_reservation_lock);
+
+ return 0;
+}
+
+/*
+ * PERSISTENT_RESERVE_IN Service Action REPORT_CAPABILITIES
+ *
+ * See spc4r17 section 6.13.4 Table 165
+ */
+static int core_scsi3_pri_report_capabilities(struct se_cmd *cmd)
+{
+ struct se_device *dev = SE_DEV(cmd);
+ struct t10_reservation_template *pr_tmpl = &SU_DEV(dev)->t10_reservation;
+ unsigned char *buf = (unsigned char *)T_TASK(cmd)->t_task_buf;
+ u16 add_len = 8; /* Hardcoded to 8. */
+
+ if (cmd->data_length < 6) {
+ printk(KERN_ERR "PRIN SA REPORT_CAPABILITIES SCSI Data Length:"
+ " %u too small\n", cmd->data_length);
+ return PYX_TRANSPORT_INVALID_CDB_FIELD;
+ }
+
+ buf[0] = ((add_len << 8) & 0xff);
+ buf[1] = (add_len & 0xff);
+ buf[2] |= 0x10; /* CRH: Compatible Reservation Hanlding bit. */
+ buf[2] |= 0x08; /* SIP_C: Specify Initiator Ports Capable bit */
+ buf[2] |= 0x04; /* ATP_C: All Target Ports Capable bit */
+ buf[2] |= 0x01; /* PTPL_C: Persistence across Target Power Loss bit */
+ /*
+ * We are filling in the PERSISTENT RESERVATION TYPE MASK below, so
+ * set the TMV: Task Mask Valid bit.
+ */
+ buf[3] |= 0x80;
+ /*
+ * Change ALLOW COMMANDs to 0x20 or 0x40 later from Table 166
+ */
+ buf[3] |= 0x10; /* ALLOW COMMANDs field 001b */
+ /*
+ * PTPL_A: Persistence across Target Power Loss Active bit
+ */
+ if (pr_tmpl->pr_aptpl_active)
+ buf[3] |= 0x01;
+ /*
+ * Setup the PERSISTENT RESERVATION TYPE MASK from Table 167
+ */
+ buf[4] |= 0x80; /* PR_TYPE_EXCLUSIVE_ACCESS_ALLREG */
+ buf[4] |= 0x40; /* PR_TYPE_EXCLUSIVE_ACCESS_REGONLY */
+ buf[4] |= 0x20; /* PR_TYPE_WRITE_EXCLUSIVE_REGONLY */
+ buf[4] |= 0x08; /* PR_TYPE_EXCLUSIVE_ACCESS */
+ buf[4] |= 0x02; /* PR_TYPE_WRITE_EXCLUSIVE */
+ buf[5] |= 0x01; /* PR_TYPE_EXCLUSIVE_ACCESS_ALLREG */
+
+ return 0;
+}
+
+/*
+ * PERSISTENT_RESERVE_IN Service Action READ_FULL_STATUS
+ *
+ * See spc4r17 section 6.13.5 Table 168 and 169
+ */
+static int core_scsi3_pri_read_full_status(struct se_cmd *cmd)
+{
+ struct se_device *se_dev = SE_DEV(cmd);
+ struct se_node_acl *se_nacl;
+ struct se_subsystem_dev *su_dev = SU_DEV(se_dev);
+ struct se_portal_group *se_tpg;
+ struct t10_pr_registration *pr_reg, *pr_reg_tmp;
+ struct t10_reservation_template *pr_tmpl = &SU_DEV(se_dev)->t10_reservation;
+ unsigned char *buf = (unsigned char *)T_TASK(cmd)->t_task_buf;
+ u32 add_desc_len = 0, add_len = 0, desc_len, exp_desc_len;
+ u32 off = 8; /* off into first Full Status descriptor */
+ int format_code = 0;
+
+ if (cmd->data_length < 8) {
+ printk(KERN_ERR "PRIN SA READ_FULL_STATUS SCSI Data Length: %u"
+ " too small\n", cmd->data_length);
+ return PYX_TRANSPORT_INVALID_CDB_FIELD;
+ }
+
+ buf[0] = ((T10_RES(su_dev)->pr_generation >> 24) & 0xff);
+ buf[1] = ((T10_RES(su_dev)->pr_generation >> 16) & 0xff);
+ buf[2] = ((T10_RES(su_dev)->pr_generation >> 8) & 0xff);
+ buf[3] = (T10_RES(su_dev)->pr_generation & 0xff);
+
+ spin_lock(&pr_tmpl->registration_lock);
+ list_for_each_entry_safe(pr_reg, pr_reg_tmp,
+ &pr_tmpl->registration_list, pr_reg_list) {
+
+ se_nacl = pr_reg->pr_reg_nacl;
+ se_tpg = pr_reg->pr_reg_nacl->se_tpg;
+ add_desc_len = 0;
+
+ atomic_inc(&pr_reg->pr_res_holders);
+ smp_mb__after_atomic_inc();
+ spin_unlock(&pr_tmpl->registration_lock);
+ /*
+ * Determine expected length of $FABRIC_MOD specific
+ * TransportID full status descriptor..
+ */
+ exp_desc_len = TPG_TFO(se_tpg)->tpg_get_pr_transport_id_len(
+ se_tpg, se_nacl, pr_reg, &format_code);
+
+ if ((exp_desc_len + add_len) > cmd->data_length) {
+ printk(KERN_WARNING "SPC-3 PRIN READ_FULL_STATUS ran"
+ " out of buffer: %d\n", cmd->data_length);
+ spin_lock(&pr_tmpl->registration_lock);
+ atomic_dec(&pr_reg->pr_res_holders);
+ smp_mb__after_atomic_dec();
+ break;
+ }
+ /*
+ * Set RESERVATION KEY
+ */
+ buf[off++] = ((pr_reg->pr_res_key >> 56) & 0xff);
+ buf[off++] = ((pr_reg->pr_res_key >> 48) & 0xff);
+ buf[off++] = ((pr_reg->pr_res_key >> 40) & 0xff);
+ buf[off++] = ((pr_reg->pr_res_key >> 32) & 0xff);
+ buf[off++] = ((pr_reg->pr_res_key >> 24) & 0xff);
+ buf[off++] = ((pr_reg->pr_res_key >> 16) & 0xff);
+ buf[off++] = ((pr_reg->pr_res_key >> 8) & 0xff);
+ buf[off++] = (pr_reg->pr_res_key & 0xff);
+ off += 4; /* Skip Over Reserved area */
+
+ /*
+ * Set ALL_TG_PT bit if PROUT SA REGISTER had this set.
+ */
+ if (pr_reg->pr_reg_all_tg_pt)
+ buf[off] = 0x02;
+ /*
+ * The struct se_lun pointer will be present for the
+ * reservation holder for PR_HOLDER bit.
+ *
+ * Also, if this registration is the reservation
+ * holder, fill in SCOPE and TYPE in the next byte.
+ */
+ if (pr_reg->pr_res_holder) {
+ buf[off++] |= 0x01;
+ buf[off++] = (pr_reg->pr_res_scope & 0xf0) |
+ (pr_reg->pr_res_type & 0x0f);
+ } else
+ off += 2;
+
+ off += 4; /* Skip over reserved area */
+ /*
+ * From spc4r17 6.3.15:
+ *
+ * If the ALL_TG_PT bit set to zero, the RELATIVE TARGET PORT
+ * IDENTIFIER field contains the relative port identifier (see
+ * 3.1.120) of the target port that is part of the I_T nexus
+ * described by this full status descriptor. If the ALL_TG_PT
+ * bit is set to one, the contents of the RELATIVE TARGET PORT
+ * IDENTIFIER field are not defined by this standard.
+ */
+ if (!(pr_reg->pr_reg_all_tg_pt)) {
+ struct se_port *port = pr_reg->pr_reg_tg_pt_lun->lun_sep;
+
+ buf[off++] = ((port->sep_rtpi >> 8) & 0xff);
+ buf[off++] = (port->sep_rtpi & 0xff);
+ } else
+ off += 2; /* Skip over RELATIVE TARGET PORT IDENTIFER */
+
+ /*
+ * Now, have the $FABRIC_MOD fill in the protocol identifier
+ */
+ desc_len = TPG_TFO(se_tpg)->tpg_get_pr_transport_id(se_tpg,
+ se_nacl, pr_reg, &format_code, &buf[off+4]);
+
+ spin_lock(&pr_tmpl->registration_lock);
+ atomic_dec(&pr_reg->pr_res_holders);
+ smp_mb__after_atomic_dec();
+ /*
+ * Set the ADDITIONAL DESCRIPTOR LENGTH
+ */
+ buf[off++] = ((desc_len >> 24) & 0xff);
+ buf[off++] = ((desc_len >> 16) & 0xff);
+ buf[off++] = ((desc_len >> 8) & 0xff);
+ buf[off++] = (desc_len & 0xff);
+ /*
+ * Size of full desctipor header minus TransportID
+ * containing $FABRIC_MOD specific) initiator device/port
+ * WWN information.
+ *
+ * See spc4r17 Section 6.13.5 Table 169
+ */
+ add_desc_len = (24 + desc_len);
+
+ off += desc_len;
+ add_len += add_desc_len;
+ }
+ spin_unlock(&pr_tmpl->registration_lock);
+ /*
+ * Set ADDITIONAL_LENGTH
+ */
+ buf[4] = ((add_len >> 24) & 0xff);
+ buf[5] = ((add_len >> 16) & 0xff);
+ buf[6] = ((add_len >> 8) & 0xff);
+ buf[7] = (add_len & 0xff);
+
+ return 0;
+}
+
+static int core_scsi3_emulate_pr_in(struct se_cmd *cmd, unsigned char *cdb)
+{
+ switch (cdb[1] & 0x1f) {
+ case PRI_READ_KEYS:
+ return core_scsi3_pri_read_keys(cmd);
+ case PRI_READ_RESERVATION:
+ return core_scsi3_pri_read_reservation(cmd);
+ case PRI_REPORT_CAPABILITIES:
+ return core_scsi3_pri_report_capabilities(cmd);
+ case PRI_READ_FULL_STATUS:
+ return core_scsi3_pri_read_full_status(cmd);
+ default:
+ printk(KERN_ERR "Unknown PERSISTENT_RESERVE_IN service"
+ " action: 0x%02x\n", cdb[1] & 0x1f);
+ return PYX_TRANSPORT_INVALID_CDB_FIELD;
+ }
+
+}
+
+int core_scsi3_emulate_pr(struct se_cmd *cmd)
+{
+ unsigned char *cdb = &T_TASK(cmd)->t_task_cdb[0];
+ struct se_device *dev = cmd->se_dev;
+ /*
+ * Following spc2r20 5.5.1 Reservations overview:
+ *
+ * If a logical unit has been reserved by any RESERVE command and is
+ * still reserved by any initiator, all PERSISTENT RESERVE IN and all
+ * PERSISTENT RESERVE OUT commands shall conflict regardless of
+ * initiator or service action and shall terminate with a RESERVATION
+ * CONFLICT status.
+ */
+ if (dev->dev_flags & DF_SPC2_RESERVATIONS) {
+ printk(KERN_ERR "Received PERSISTENT_RESERVE CDB while legacy"
+ " SPC-2 reservation is held, returning"
+ " RESERVATION_CONFLICT\n");
+ return PYX_TRANSPORT_RESERVATION_CONFLICT;
+ }
+
+ return (cdb[0] == PERSISTENT_RESERVE_OUT) ?
+ core_scsi3_emulate_pr_out(cmd, cdb) :
+ core_scsi3_emulate_pr_in(cmd, cdb);
+}
+
+static int core_pt_reservation_check(struct se_cmd *cmd, u32 *pr_res_type)
+{
+ return 0;
+}
+
+static int core_pt_seq_non_holder(
+ struct se_cmd *cmd,
+ unsigned char *cdb,
+ u32 pr_reg_type)
+{
+ return 0;
+}
+
+int core_setup_reservations(struct se_device *dev, int force_pt)
+{
+ struct se_subsystem_dev *su_dev = dev->se_sub_dev;
+ struct t10_reservation_template *rest = &su_dev->t10_reservation;
+ /*
+ * If this device is from Target_Core_Mod/pSCSI, use the reservations
+ * of the Underlying SCSI hardware. In Linux/SCSI terms, this can
+ * cause a problem because libata and some SATA RAID HBAs appear
+ * under Linux/SCSI, but to emulate reservations themselves.
+ */
+ if (((TRANSPORT(dev)->transport_type == TRANSPORT_PLUGIN_PHBA_PDEV) &&
+ !(DEV_ATTRIB(dev)->emulate_reservations)) || force_pt) {
+ rest->res_type = SPC_PASSTHROUGH;
+ rest->pr_ops.t10_reservation_check = &core_pt_reservation_check;
+ rest->pr_ops.t10_seq_non_holder = &core_pt_seq_non_holder;
+ printk(KERN_INFO "%s: Using SPC_PASSTHROUGH, no reservation"
+ " emulation\n", TRANSPORT(dev)->name);
+ return 0;
+ }
+ /*
+ * If SPC-3 or above is reported by real or emulated struct se_device,
+ * use emulated Persistent Reservations.
+ */
+ if (TRANSPORT(dev)->get_device_rev(dev) >= SCSI_3) {
+ rest->res_type = SPC3_PERSISTENT_RESERVATIONS;
+ rest->pr_ops.t10_reservation_check = &core_scsi3_pr_reservation_check;
+ rest->pr_ops.t10_seq_non_holder = &core_scsi3_pr_seq_non_holder;
+ printk(KERN_INFO "%s: Using SPC3_PERSISTENT_RESERVATIONS"
+ " emulation\n", TRANSPORT(dev)->name);
+ } else {
+ rest->res_type = SPC2_RESERVATIONS;
+ rest->pr_ops.t10_reservation_check = &core_scsi2_reservation_check;
+ rest->pr_ops.t10_seq_non_holder =
+ &core_scsi2_reservation_seq_non_holder;
+ printk(KERN_INFO "%s: Using SPC2_RESERVATIONS emulation\n",
+ TRANSPORT(dev)->name);
+ }
+
+ return 0;
+}
diff --git a/drivers/target/target_core_pr.h b/drivers/target/target_core_pr.h
new file mode 100644
index 0000000..5603bcf
--- /dev/null
+++ b/drivers/target/target_core_pr.h
@@ -0,0 +1,67 @@
+#ifndef TARGET_CORE_PR_H
+#define TARGET_CORE_PR_H
+/*
+ * PERSISTENT_RESERVE_OUT service action codes
+ *
+ * spc4r17 section 6.14.2 Table 171
+ */
+#define PRO_REGISTER 0x00
+#define PRO_RESERVE 0x01
+#define PRO_RELEASE 0x02
+#define PRO_CLEAR 0x03
+#define PRO_PREEMPT 0x04
+#define PRO_PREEMPT_AND_ABORT 0x05
+#define PRO_REGISTER_AND_IGNORE_EXISTING_KEY 0x06
+#define PRO_REGISTER_AND_MOVE 0x07
+/*
+ * PERSISTENT_RESERVE_IN service action codes
+ *
+ * spc4r17 section 6.13.1 Table 159
+ */
+#define PRI_READ_KEYS 0x00
+#define PRI_READ_RESERVATION 0x01
+#define PRI_REPORT_CAPABILITIES 0x02
+#define PRI_READ_FULL_STATUS 0x03
+/*
+ * PERSISTENT_RESERVE_ SCOPE field
+ *
+ * spc4r17 section 6.13.3.3 Table 163
+ */
+#define PR_SCOPE_LU_SCOPE 0x00
+/*
+ * PERSISTENT_RESERVE_* TYPE field
+ *
+ * spc4r17 section 6.13.3.4 Table 164
+ */
+#define PR_TYPE_WRITE_EXCLUSIVE 0x01
+#define PR_TYPE_EXCLUSIVE_ACCESS 0x03
+#define PR_TYPE_WRITE_EXCLUSIVE_REGONLY 0x05
+#define PR_TYPE_EXCLUSIVE_ACCESS_REGONLY 0x06
+#define PR_TYPE_WRITE_EXCLUSIVE_ALLREG 0x07
+#define PR_TYPE_EXCLUSIVE_ACCESS_ALLREG 0x08
+
+#define PR_APTPL_MAX_IPORT_LEN 256
+#define PR_APTPL_MAX_TPORT_LEN 256
+
+extern struct kmem_cache *t10_pr_reg_cache;
+
+extern int core_pr_dump_initiator_port(struct t10_pr_registration *,
+ char *, u32);
+extern int core_scsi2_emulate_crh(struct se_cmd *);
+extern int core_scsi3_alloc_aptpl_registration(
+ struct t10_reservation_template *, u64,
+ unsigned char *, unsigned char *, u32,
+ unsigned char *, u16, u32, int, int, u8);
+extern int core_scsi3_check_aptpl_registration(struct se_device *,
+ struct se_portal_group *, struct se_lun *,
+ struct se_lun_acl *);
+extern void core_scsi3_free_pr_reg_from_nacl(struct se_device *,
+ struct se_node_acl *);
+extern void core_scsi3_free_all_registrations(struct se_device *);
+extern unsigned char *core_scsi3_pr_dump_type(int);
+extern int core_scsi3_check_cdb_abort_and_preempt(struct list_head *,
+ struct se_cmd *);
+extern int core_scsi3_emulate_pr(struct se_cmd *);
+extern int core_setup_reservations(struct se_device *, int);
+
+#endif /* TARGET_CORE_PR_H */
diff --git a/drivers/target/target_core_pscsi.c b/drivers/target/target_core_pscsi.c
new file mode 100644
index 0000000..742d246
--- /dev/null
+++ b/drivers/target/target_core_pscsi.c
@@ -0,0 +1,1470 @@
+/*******************************************************************************
+ * Filename: target_core_pscsi.c
+ *
+ * This file contains the generic target mode <-> Linux SCSI subsystem plugin.
+ *
+ * Copyright (c) 2003, 2004, 2005 PyX Technologies, Inc.
+ * Copyright (c) 2005, 2006, 2007 SBE, Inc.
+ * Copyright (c) 2007-2010 Rising Tide Systems
+ * Copyright (c) 2008-2010 Linux-iSCSI.org
+ *
+ * Nicholas A. Bellinger <nab@kernel.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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ ******************************************************************************/
+
+#include <linux/version.h>
+#include <linux/string.h>
+#include <linux/parser.h>
+#include <linux/timer.h>
+#include <linux/blkdev.h>
+#include <linux/blk_types.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/smp_lock.h>
+#include <linux/genhd.h>
+#include <linux/cdrom.h>
+#include <linux/file.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_host.h>
+#include <scsi/libsas.h> /* For TASK_ATTR_* */
+
+#include <target/target_core_base.h>
+#include <target/target_core_device.h>
+#include <target/target_core_transport.h>
+
+#include "target_core_pscsi.h"
+
+#define ISPRINT(a) ((a >= ' ') && (a <= '~'))
+
+static struct se_subsystem_api pscsi_template;
+
+static void pscsi_req_done(struct request *, int);
+
+/* pscsi_get_sh():
+ *
+ *
+ */
+static struct Scsi_Host *pscsi_get_sh(u32 host_no)
+{
+ struct Scsi_Host *sh = NULL;
+
+ sh = scsi_host_lookup(host_no);
+ if (IS_ERR(sh)) {
+ printk(KERN_ERR "Unable to locate SCSI HBA with Host ID:"
+ " %u\n", host_no);
+ return NULL;
+ }
+
+ return sh;
+}
+
+/* pscsi_attach_hba():
+ *
+ * pscsi_get_sh() used scsi_host_lookup() to locate struct Scsi_Host.
+ * from the passed SCSI Host ID.
+ */
+static int pscsi_attach_hba(struct se_hba *hba, u32 host_id)
+{
+ int hba_depth;
+ struct pscsi_hba_virt *phv;
+
+ phv = kzalloc(sizeof(struct pscsi_hba_virt), GFP_KERNEL);
+ if (!(phv)) {
+ printk(KERN_ERR "Unable to allocate struct pscsi_hba_virt\n");
+ return -1;
+ }
+ phv->phv_host_id = host_id;
+ phv->phv_mode = PHV_VIRUTAL_HOST_ID;
+ hba_depth = PSCSI_VIRTUAL_HBA_DEPTH;
+ atomic_set(&hba->left_queue_depth, hba_depth);
+ atomic_set(&hba->max_queue_depth, hba_depth);
+
+ hba->hba_ptr = (void *)phv;
+
+ printk(KERN_INFO "CORE_HBA[%d] - TCM SCSI HBA Driver %s on"
+ " Generic Target Core Stack %s\n", hba->hba_id,
+ PSCSI_VERSION, TARGET_CORE_MOD_VERSION);
+ printk(KERN_INFO "CORE_HBA[%d] - Attached SCSI HBA to Generic"
+ " Target Core with TCQ Depth: %d\n", hba->hba_id,
+ atomic_read(&hba->max_queue_depth));
+
+ return 0;
+}
+
+static void pscsi_detach_hba(struct se_hba *hba)
+{
+ struct pscsi_hba_virt *phv = hba->hba_ptr;
+ struct Scsi_Host *scsi_host = phv->phv_lld_host;
+
+ if (scsi_host) {
+ scsi_host_put(scsi_host);
+
+ printk(KERN_INFO "CORE_HBA[%d] - Detached SCSI HBA: %s from"
+ " Generic Target Core\n", hba->hba_id,
+ (scsi_host->hostt->name) ? (scsi_host->hostt->name) :
+ "Unknown");
+ } else
+ printk(KERN_INFO "CORE_HBA[%d] - Detached Virtual SCSI HBA"
+ " from Generic Target Core\n", hba->hba_id);
+
+ kfree(phv);
+ hba->hba_ptr = NULL;
+}
+
+static int pscsi_pmode_enable_hba(struct se_hba *hba, unsigned long mode_flag)
+{
+ struct pscsi_hba_virt *phv = (struct pscsi_hba_virt *)hba->hba_ptr;
+ struct Scsi_Host *sh = phv->phv_lld_host;
+ int hba_depth = PSCSI_VIRTUAL_HBA_DEPTH;
+ /*
+ * Release the struct Scsi_Host
+ */
+ if (!(mode_flag)) {
+ if (!(sh))
+ return 0;
+
+ phv->phv_lld_host = NULL;
+ phv->phv_mode = PHV_VIRUTAL_HOST_ID;
+ atomic_set(&hba->left_queue_depth, hba_depth);
+ atomic_set(&hba->max_queue_depth, hba_depth);
+
+ printk(KERN_INFO "CORE_HBA[%d] - Disabled pSCSI HBA Passthrough"
+ " %s\n", hba->hba_id, (sh->hostt->name) ?
+ (sh->hostt->name) : "Unknown");
+
+ scsi_host_put(sh);
+ return 0;
+ }
+ /*
+ * Otherwise, locate struct Scsi_Host from the original passed
+ * pSCSI Host ID and enable for phba mode
+ */
+ sh = pscsi_get_sh(phv->phv_host_id);
+ if (!(sh)) {
+ printk(KERN_ERR "pSCSI: Unable to locate SCSI Host for"
+ " phv_host_id: %d\n", phv->phv_host_id);
+ return -1;
+ }
+ /*
+ * Usually the SCSI LLD will use the hostt->can_queue value to define
+ * its HBA TCQ depth. Some other drivers (like 2.6 megaraid) don't set
+ * this at all and set sh->can_queue at runtime.
+ */
+ hba_depth = (sh->hostt->can_queue > sh->can_queue) ?
+ sh->hostt->can_queue : sh->can_queue;
+
+ atomic_set(&hba->left_queue_depth, hba_depth);
+ atomic_set(&hba->max_queue_depth, hba_depth);
+
+ phv->phv_lld_host = sh;
+ phv->phv_mode = PHV_LLD_SCSI_HOST_NO;
+
+ printk(KERN_INFO "CORE_HBA[%d] - Enabled pSCSI HBA Passthrough %s\n",
+ hba->hba_id, (sh->hostt->name) ? (sh->hostt->name) : "Unknown");
+
+ return 1;
+}
+
+static void pscsi_tape_read_blocksize(struct se_device *dev,
+ struct scsi_device *sdev)
+{
+ unsigned char cdb[MAX_COMMAND_SIZE], *buf;
+ int ret;
+
+ buf = kzalloc(12, GFP_KERNEL);
+ if (!buf)
+ return;
+
+ memset(cdb, 0, MAX_COMMAND_SIZE);
+ cdb[0] = MODE_SENSE;
+ cdb[4] = 0x0c; /* 12 bytes */
+
+ ret = scsi_execute_req(sdev, cdb, DMA_FROM_DEVICE, buf, 12, NULL,
+ HZ, 1, NULL);
+ if (ret)
+ goto out_free;
+
+ /*
+ * If MODE_SENSE still returns zero, set the default value to 1024.
+ */
+ sdev->sector_size = (buf[9] << 16) | (buf[10] << 8) | (buf[11]);
+ if (!sdev->sector_size)
+ sdev->sector_size = 1024;
+out_free:
+ kfree(buf);
+}
+
+static void
+pscsi_set_inquiry_info(struct scsi_device *sdev, struct t10_wwn *wwn)
+{
+ unsigned char *buf;
+
+ if (sdev->inquiry_len < INQUIRY_LEN)
+ return;
+
+ buf = sdev->inquiry;
+ if (!buf)
+ return;
+ /*
+ * Use sdev->inquiry from drivers/scsi/scsi_scan.c:scsi_alloc_sdev()
+ */
+ memcpy(&wwn->vendor[0], &buf[8], sizeof(wwn->vendor));
+ memcpy(&wwn->model[0], &buf[16], sizeof(wwn->model));
+ memcpy(&wwn->revision[0], &buf[32], sizeof(wwn->revision));
+}
+
+static int
+pscsi_get_inquiry_vpd_serial(struct scsi_device *sdev, struct t10_wwn *wwn)
+{
+ unsigned char cdb[MAX_COMMAND_SIZE], *buf;
+ int ret;
+
+ buf = kzalloc(INQUIRY_VPD_SERIAL_LEN, GFP_KERNEL);
+ if (!buf)
+ return -1;
+
+ memset(cdb, 0, MAX_COMMAND_SIZE);
+ cdb[0] = INQUIRY;
+ cdb[1] = 0x01; /* Query VPD */
+ cdb[2] = 0x80; /* Unit Serial Number */
+ cdb[3] = (INQUIRY_VPD_SERIAL_LEN >> 8) & 0xff;
+ cdb[4] = (INQUIRY_VPD_SERIAL_LEN & 0xff);
+
+ ret = scsi_execute_req(sdev, cdb, DMA_FROM_DEVICE, buf,
+ INQUIRY_VPD_SERIAL_LEN, NULL, HZ, 1, NULL);
+ if (ret)
+ goto out_free;
+
+ snprintf(&wwn->unit_serial[0], INQUIRY_VPD_SERIAL_LEN, "%s", &buf[4]);
+
+ wwn->t10_sub_dev->su_dev_flags |= SDF_FIRMWARE_VPD_UNIT_SERIAL;
+
+ kfree(buf);
+ return 0;
+
+out_free:
+ kfree(buf);
+ return -1;
+}
+
+static void
+pscsi_get_inquiry_vpd_device_ident(struct scsi_device *sdev,
+ struct t10_wwn *wwn)
+{
+ unsigned char cdb[MAX_COMMAND_SIZE], *buf, *page_83;
+ int ident_len, page_len, off = 4, ret;
+ struct t10_vpd *vpd;
+
+ buf = kzalloc(INQUIRY_VPD_SERIAL_LEN, GFP_KERNEL);
+ if (!buf)
+ return;
+
+ memset(cdb, 0, MAX_COMMAND_SIZE);
+ cdb[0] = INQUIRY;
+ cdb[1] = 0x01; /* Query VPD */
+ cdb[2] = 0x83; /* Device Identifier */
+ cdb[3] = (INQUIRY_VPD_DEVICE_IDENTIFIER_LEN >> 8) & 0xff;
+ cdb[4] = (INQUIRY_VPD_DEVICE_IDENTIFIER_LEN & 0xff);
+
+ ret = scsi_execute_req(sdev, cdb, DMA_FROM_DEVICE, buf,
+ INQUIRY_VPD_DEVICE_IDENTIFIER_LEN,
+ NULL, HZ, 1, NULL);
+ if (ret)
+ goto out;
+
+ page_len = (buf[2] << 8) | buf[3];
+ while (page_len > 0) {
+ /* Grab a pointer to the Identification descriptor */
+ page_83 = &buf[off];
+ ident_len = page_83[3];
+ if (!ident_len) {
+ printk(KERN_ERR "page_83[3]: identifier"
+ " length zero!\n");
+ break;
+ }
+ printk(KERN_INFO "T10 VPD Identifer Length: %d\n", ident_len);
+
+ vpd = kzalloc(sizeof(struct t10_vpd), GFP_KERNEL);
+ if (!vpd) {
+ printk(KERN_ERR "Unable to allocate memory for"
+ " struct t10_vpd\n");
+ goto out;
+ }
+ INIT_LIST_HEAD(&vpd->vpd_list);
+
+ transport_set_vpd_proto_id(vpd, page_83);
+ transport_set_vpd_assoc(vpd, page_83);
+
+ if (transport_set_vpd_ident_type(vpd, page_83) < 0) {
+ off += (ident_len + 4);
+ page_len -= (ident_len + 4);
+ kfree(vpd);
+ continue;
+ }
+ if (transport_set_vpd_ident(vpd, page_83) < 0) {
+ off += (ident_len + 4);
+ page_len -= (ident_len + 4);
+ kfree(vpd);
+ continue;
+ }
+
+ list_add_tail(&vpd->vpd_list, &wwn->t10_vpd_list);
+ off += (ident_len + 4);
+ page_len -= (ident_len + 4);
+ }
+
+out:
+ kfree(buf);
+}
+
+/* pscsi_add_device_to_list():
+ *
+ *
+ */
+static struct se_device *pscsi_add_device_to_list(
+ struct se_hba *hba,
+ struct se_subsystem_dev *se_dev,
+ struct pscsi_dev_virt *pdv,
+ struct scsi_device *sd,
+ int dev_flags)
+{
+ struct se_device *dev;
+ struct se_dev_limits dev_limits;
+ struct request_queue *q;
+ struct queue_limits *limits;
+
+ memset(&dev_limits, 0, sizeof(struct se_dev_limits));
+
+ if (!sd->queue_depth) {
+ sd->queue_depth = PSCSI_DEFAULT_QUEUEDEPTH;
+
+ printk(KERN_ERR "Set broken SCSI Device %d:%d:%d"
+ " queue_depth to %d\n", sd->channel, sd->id,
+ sd->lun, sd->queue_depth);
+ }
+ /*
+ * Setup the local scope queue_limits from struct request_queue->limits
+ * to pass into transport_add_device_to_core_hba() as struct se_dev_limits.
+ */
+ q = sd->request_queue;
+ limits = &dev_limits.limits;
+ limits->logical_block_size = sd->sector_size;
+ limits->max_hw_sectors = (sd->host->max_sectors > queue_max_hw_sectors(q)) ?
+ queue_max_hw_sectors(q) : sd->host->max_sectors;
+ limits->max_sectors = (sd->host->max_sectors > queue_max_sectors(q)) ?
+ queue_max_sectors(q) : sd->host->max_sectors;
+ dev_limits.hw_queue_depth = sd->queue_depth;
+ dev_limits.queue_depth = sd->queue_depth;
+ /*
+ * Setup our standard INQUIRY info into se_dev->t10_wwn
+ */
+ pscsi_set_inquiry_info(sd, &se_dev->t10_wwn);
+
+ /*
+ * Set the pointer pdv->pdv_sd to from passed struct scsi_device,
+ * which has already been referenced with Linux SCSI code with
+ * scsi_device_get() in this file's pscsi_create_virtdevice().
+ *
+ * The passthrough operations called by the transport_add_device_*
+ * function below will require this pointer to be set for passthroug
+ * ops.
+ *
+ * For the shutdown case in pscsi_free_device(), this struct
+ * scsi_device reference is released with Linux SCSI code
+ * scsi_device_put() and the pdv->pdv_sd cleared.
+ */
+ pdv->pdv_sd = sd;
+
+ dev = transport_add_device_to_core_hba(hba, &pscsi_template,
+ se_dev, dev_flags, (void *)pdv,
+ &dev_limits, NULL, NULL);
+ if (!(dev)) {
+ pdv->pdv_sd = NULL;
+ return NULL;
+ }
+
+ /*
+ * Locate VPD WWN Information used for various purposes within
+ * the Storage Engine.
+ */
+ if (!pscsi_get_inquiry_vpd_serial(sd, &se_dev->t10_wwn)) {
+ /*
+ * If VPD Unit Serial returned GOOD status, try
+ * VPD Device Identification page (0x83).
+ */
+ pscsi_get_inquiry_vpd_device_ident(sd, &se_dev->t10_wwn);
+ }
+
+ /*
+ * For TYPE_TAPE, attempt to determine blocksize with MODE_SENSE.
+ */
+ if (sd->type == TYPE_TAPE)
+ pscsi_tape_read_blocksize(dev, sd);
+ return dev;
+}
+
+static void *pscsi_allocate_virtdevice(struct se_hba *hba, const char *name)
+{
+ struct pscsi_dev_virt *pdv;
+
+ pdv = kzalloc(sizeof(struct pscsi_dev_virt), GFP_KERNEL);
+ if (!(pdv)) {
+ printk(KERN_ERR "Unable to allocate memory for struct pscsi_dev_virt\n");
+ return NULL;
+ }
+ pdv->pdv_se_hba = hba;
+
+ printk(KERN_INFO "PSCSI: Allocated pdv: %p for %s\n", pdv, name);
+ return (void *)pdv;
+}
+
+/*
+ * Called with struct Scsi_Host->host_lock called.
+ */
+static struct se_device *pscsi_create_type_disk(
+ struct scsi_device *sd,
+ struct pscsi_dev_virt *pdv,
+ struct se_subsystem_dev *se_dev,
+ struct se_hba *hba)
+{
+ struct se_device *dev;
+ struct pscsi_hba_virt *phv = (struct pscsi_hba_virt *)pdv->pdv_se_hba->hba_ptr;
+ struct Scsi_Host *sh = sd->host;
+ struct block_device *bd;
+ u32 dev_flags = 0;
+
+ if (scsi_device_get(sd)) {
+ printk(KERN_ERR "scsi_device_get() failed for %d:%d:%d:%d\n",
+ sh->host_no, sd->channel, sd->id, sd->lun);
+ spin_unlock_irq(sh->host_lock);
+ return NULL;
+ }
+ spin_unlock_irq(sh->host_lock);
+ /*
+ * Claim exclusive struct block_device access to struct scsi_device
+ * for TYPE_DISK using supplied udev_path
+ */
+ bd = blkdev_get_by_path(se_dev->se_dev_udev_path,
+ FMODE_WRITE|FMODE_READ|FMODE_EXCL, pdv);
+ if (!(bd)) {
+ printk("pSCSI: blkdev_get_by_path() failed\n");
+ scsi_device_put(sd);
+ return NULL;
+ }
+ pdv->pdv_bd = bd;
+
+ dev = pscsi_add_device_to_list(hba, se_dev, pdv, sd, dev_flags);
+ if (!(dev)) {
+ blkdev_put(pdv->pdv_bd, FMODE_WRITE|FMODE_READ|FMODE_EXCL);
+ scsi_device_put(sd);
+ return NULL;
+ }
+ printk(KERN_INFO "CORE_PSCSI[%d] - Added TYPE_DISK for %d:%d:%d:%d\n",
+ phv->phv_host_id, sh->host_no, sd->channel, sd->id, sd->lun);
+
+ return dev;
+}
+
+/*
+ * Called with struct Scsi_Host->host_lock called.
+ */
+static struct se_device *pscsi_create_type_rom(
+ struct scsi_device *sd,
+ struct pscsi_dev_virt *pdv,
+ struct se_subsystem_dev *se_dev,
+ struct se_hba *hba)
+{
+ struct se_device *dev;
+ struct pscsi_hba_virt *phv = (struct pscsi_hba_virt *)pdv->pdv_se_hba->hba_ptr;
+ struct Scsi_Host *sh = sd->host;
+ u32 dev_flags = 0;
+
+ if (scsi_device_get(sd)) {
+ printk(KERN_ERR "scsi_device_get() failed for %d:%d:%d:%d\n",
+ sh->host_no, sd->channel, sd->id, sd->lun);
+ spin_unlock_irq(sh->host_lock);
+ return NULL;
+ }
+ spin_unlock_irq(sh->host_lock);
+
+ dev = pscsi_add_device_to_list(hba, se_dev, pdv, sd, dev_flags);
+ if (!(dev)) {
+ scsi_device_put(sd);
+ return NULL;
+ }
+ printk(KERN_INFO "CORE_PSCSI[%d] - Added Type: %s for %d:%d:%d:%d\n",
+ phv->phv_host_id, scsi_device_type(sd->type), sh->host_no,
+ sd->channel, sd->id, sd->lun);
+
+ return dev;
+}
+
+/*
+ *Called with struct Scsi_Host->host_lock called.
+ */
+static struct se_device *pscsi_create_type_other(
+ struct scsi_device *sd,
+ struct pscsi_dev_virt *pdv,
+ struct se_subsystem_dev *se_dev,
+ struct se_hba *hba)
+{
+ struct se_device *dev;
+ struct pscsi_hba_virt *phv = (struct pscsi_hba_virt *)pdv->pdv_se_hba->hba_ptr;
+ struct Scsi_Host *sh = sd->host;
+ u32 dev_flags = 0;
+
+ spin_unlock_irq(sh->host_lock);
+ dev = pscsi_add_device_to_list(hba, se_dev, pdv, sd, dev_flags);
+ if (!(dev))
+ return NULL;
+
+ printk(KERN_INFO "CORE_PSCSI[%d] - Added Type: %s for %d:%d:%d:%d\n",
+ phv->phv_host_id, scsi_device_type(sd->type), sh->host_no,
+ sd->channel, sd->id, sd->lun);
+
+ return dev;
+}
+
+static struct se_device *pscsi_create_virtdevice(
+ struct se_hba *hba,
+ struct se_subsystem_dev *se_dev,
+ void *p)
+{
+ struct pscsi_dev_virt *pdv = (struct pscsi_dev_virt *)p;
+ struct se_device *dev;
+ struct scsi_device *sd;
+ struct pscsi_hba_virt *phv = (struct pscsi_hba_virt *)hba->hba_ptr;
+ struct Scsi_Host *sh = phv->phv_lld_host;
+ int legacy_mode_enable = 0;
+
+ if (!(pdv)) {
+ printk(KERN_ERR "Unable to locate struct pscsi_dev_virt"
+ " parameter\n");
+ return NULL;
+ }
+ /*
+ * If not running in PHV_LLD_SCSI_HOST_NO mode, locate the
+ * struct Scsi_Host we will need to bring the TCM/pSCSI object online
+ */
+ if (!(sh)) {
+ if (phv->phv_mode == PHV_LLD_SCSI_HOST_NO) {
+ printk(KERN_ERR "pSCSI: Unable to locate struct"
+ " Scsi_Host for PHV_LLD_SCSI_HOST_NO\n");
+ return NULL;
+ }
+ /*
+ * For the newer PHV_VIRUTAL_HOST_ID struct scsi_device
+ * reference, we enforce that udev_path has been set
+ */
+ if (!(se_dev->su_dev_flags & SDF_USING_UDEV_PATH)) {
+ printk(KERN_ERR "pSCSI: udev_path attribute has not"
+ " been set before ENABLE=1\n");
+ return NULL;
+ }
+ /*
+ * If no scsi_host_id= was passed for PHV_VIRUTAL_HOST_ID,
+ * use the original TCM hba ID to reference Linux/SCSI Host No
+ * and enable for PHV_LLD_SCSI_HOST_NO mode.
+ */
+ if (!(pdv->pdv_flags & PDF_HAS_VIRT_HOST_ID)) {
+ spin_lock(&hba->device_lock);
+ if (!(list_empty(&hba->hba_dev_list))) {
+ printk(KERN_ERR "pSCSI: Unable to set hba_mode"
+ " with active devices\n");
+ spin_unlock(&hba->device_lock);
+ return NULL;
+ }
+ spin_unlock(&hba->device_lock);
+
+ if (pscsi_pmode_enable_hba(hba, 1) != 1)
+ return NULL;
+
+ legacy_mode_enable = 1;
+ hba->hba_flags |= HBA_FLAGS_PSCSI_MODE;
+ sh = phv->phv_lld_host;
+ } else {
+ sh = pscsi_get_sh(pdv->pdv_host_id);
+ if (!(sh)) {
+ printk(KERN_ERR "pSCSI: Unable to locate"
+ " pdv_host_id: %d\n", pdv->pdv_host_id);
+ return NULL;
+ }
+ }
+ } else {
+ if (phv->phv_mode == PHV_VIRUTAL_HOST_ID) {
+ printk(KERN_ERR "pSCSI: PHV_VIRUTAL_HOST_ID set while"
+ " struct Scsi_Host exists\n");
+ return NULL;
+ }
+ }
+
+ spin_lock_irq(sh->host_lock);
+ list_for_each_entry(sd, &sh->__devices, siblings) {
+ if ((pdv->pdv_channel_id != sd->channel) ||
+ (pdv->pdv_target_id != sd->id) ||
+ (pdv->pdv_lun_id != sd->lun))
+ continue;
+ /*
+ * Functions will release the held struct scsi_host->host_lock
+ * before calling calling pscsi_add_device_to_list() to register
+ * struct scsi_device with target_core_mod.
+ */
+ switch (sd->type) {
+ case TYPE_DISK:
+ dev = pscsi_create_type_disk(sd, pdv, se_dev, hba);
+ break;
+ case TYPE_ROM:
+ dev = pscsi_create_type_rom(sd, pdv, se_dev, hba);
+ break;
+ default:
+ dev = pscsi_create_type_other(sd, pdv, se_dev, hba);
+ break;
+ }
+
+ if (!(dev)) {
+ if (phv->phv_mode == PHV_VIRUTAL_HOST_ID)
+ scsi_host_put(sh);
+ else if (legacy_mode_enable) {
+ pscsi_pmode_enable_hba(hba, 0);
+ hba->hba_flags &= ~HBA_FLAGS_PSCSI_MODE;
+ }
+ pdv->pdv_sd = NULL;
+ return NULL;
+ }
+ return dev;
+ }
+ spin_unlock_irq(sh->host_lock);
+
+ printk(KERN_ERR "pSCSI: Unable to locate %d:%d:%d:%d\n", sh->host_no,
+ pdv->pdv_channel_id, pdv->pdv_target_id, pdv->pdv_lun_id);
+
+ if (phv->phv_mode == PHV_VIRUTAL_HOST_ID)
+ scsi_host_put(sh);
+ else if (legacy_mode_enable) {
+ pscsi_pmode_enable_hba(hba, 0);
+ hba->hba_flags &= ~HBA_FLAGS_PSCSI_MODE;
+ }
+
+ return NULL;
+}
+
+/* pscsi_free_device(): (Part of se_subsystem_api_t template)
+ *
+ *
+ */
+static void pscsi_free_device(void *p)
+{
+ struct pscsi_dev_virt *pdv = p;
+ struct pscsi_hba_virt *phv = pdv->pdv_se_hba->hba_ptr;
+ struct scsi_device *sd = pdv->pdv_sd;
+
+ if (sd) {
+ /*
+ * Release exclusive pSCSI internal struct block_device claim for
+ * struct scsi_device with TYPE_DISK from pscsi_create_type_disk()
+ */
+ if ((sd->type == TYPE_DISK) && pdv->pdv_bd) {
+ blkdev_put(pdv->pdv_bd,
+ FMODE_WRITE|FMODE_READ|FMODE_EXCL);
+ pdv->pdv_bd = NULL;
+ }
+ /*
+ * For HBA mode PHV_LLD_SCSI_HOST_NO, release the reference
+ * to struct Scsi_Host now.
+ */
+ if ((phv->phv_mode == PHV_LLD_SCSI_HOST_NO) &&
+ (phv->phv_lld_host != NULL))
+ scsi_host_put(phv->phv_lld_host);
+
+ if ((sd->type == TYPE_DISK) || (sd->type == TYPE_ROM))
+ scsi_device_put(sd);
+
+ pdv->pdv_sd = NULL;
+ }
+
+ kfree(pdv);
+}
+
+static inline struct pscsi_plugin_task *PSCSI_TASK(struct se_task *task)
+{
+ return container_of(task, struct pscsi_plugin_task, pscsi_task);
+}
+
+
+/* pscsi_transport_complete():
+ *
+ *
+ */
+static int pscsi_transport_complete(struct se_task *task)
+{
+ struct pscsi_dev_virt *pdv = task->se_dev->dev_ptr;
+ struct scsi_device *sd = pdv->pdv_sd;
+ int result;
+ struct pscsi_plugin_task *pt = PSCSI_TASK(task);
+ unsigned char *cdb = &pt->pscsi_cdb[0];
+
+ result = pt->pscsi_result;
+ /*
+ * Hack to make sure that Write-Protect modepage is set if R/O mode is
+ * forced.
+ */
+ if (((cdb[0] == MODE_SENSE) || (cdb[0] == MODE_SENSE_10)) &&
+ (status_byte(result) << 1) == SAM_STAT_GOOD) {
+ if (!TASK_CMD(task)->se_deve)
+ goto after_mode_sense;
+
+ if (TASK_CMD(task)->se_deve->lun_flags &
+ TRANSPORT_LUNFLAGS_READ_ONLY) {
+ unsigned char *buf = (unsigned char *)
+ T_TASK(task->task_se_cmd)->t_task_buf;
+
+ if (cdb[0] == MODE_SENSE_10) {
+ if (!(buf[3] & 0x80))
+ buf[3] |= 0x80;
+ } else {
+ if (!(buf[2] & 0x80))
+ buf[2] |= 0x80;
+ }
+ }
+ }
+after_mode_sense:
+
+ if (sd->type != TYPE_TAPE)
+ goto after_mode_select;
+
+ /*
+ * Hack to correctly obtain the initiator requested blocksize for
+ * TYPE_TAPE. Since this value is dependent upon each tape media,
+ * struct scsi_device->sector_size will not contain the correct value
+ * by default, so we go ahead and set it so
+ * TRANSPORT(dev)->get_blockdev() returns the correct value to the
+ * storage engine.
+ */
+ if (((cdb[0] == MODE_SELECT) || (cdb[0] == MODE_SELECT_10)) &&
+ (status_byte(result) << 1) == SAM_STAT_GOOD) {
+ unsigned char *buf;
+ struct scatterlist *sg = task->task_sg;
+ u16 bdl;
+ u32 blocksize;
+
+ buf = sg_virt(&sg[0]);
+ if (!(buf)) {
+ printk(KERN_ERR "Unable to get buf for scatterlist\n");
+ goto after_mode_select;
+ }
+
+ if (cdb[0] == MODE_SELECT)
+ bdl = (buf[3]);
+ else
+ bdl = (buf[6] << 8) | (buf[7]);
+
+ if (!bdl)
+ goto after_mode_select;
+
+ if (cdb[0] == MODE_SELECT)
+ blocksize = (buf[9] << 16) | (buf[10] << 8) |
+ (buf[11]);
+ else
+ blocksize = (buf[13] << 16) | (buf[14] << 8) |
+ (buf[15]);
+
+ sd->sector_size = blocksize;
+ }
+after_mode_select:
+
+ if (status_byte(result) & CHECK_CONDITION)
+ return 1;
+
+ return 0;
+}
+
+static struct se_task *
+pscsi_alloc_task(struct se_cmd *cmd)
+{
+ struct pscsi_plugin_task *pt;
+ unsigned char *cdb = T_TASK(cmd)->t_task_cdb;
+
+ pt = kzalloc(sizeof(struct pscsi_plugin_task), GFP_KERNEL);
+ if (!pt) {
+ printk(KERN_ERR "Unable to allocate struct pscsi_plugin_task\n");
+ return NULL;
+ }
+
+ /*
+ * If TCM Core is signaling a > TCM_MAX_COMMAND_SIZE allocation,
+ * allocate the extended CDB buffer for per struct se_task context
+ * pt->pscsi_cdb now.
+ */
+ if (T_TASK(cmd)->t_task_cdb != T_TASK(cmd)->__t_task_cdb) {
+
+ pt->pscsi_cdb = kzalloc(scsi_command_size(cdb), GFP_KERNEL);
+ if (!(pt->pscsi_cdb)) {
+ printk(KERN_ERR "pSCSI: Unable to allocate extended"
+ " pt->pscsi_cdb\n");
+ return NULL;
+ }
+ } else
+ pt->pscsi_cdb = &pt->__pscsi_cdb[0];
+
+ return &pt->pscsi_task;
+}
+
+static inline void pscsi_blk_init_request(
+ struct se_task *task,
+ struct pscsi_plugin_task *pt,
+ struct request *req,
+ int bidi_read)
+{
+ /*
+ * Defined as "scsi command" in include/linux/blkdev.h.
+ */
+ req->cmd_type = REQ_TYPE_BLOCK_PC;
+ /*
+ * For the extra BIDI-COMMAND READ struct request we do not
+ * need to setup the remaining structure members
+ */
+ if (bidi_read)
+ return;
+ /*
+ * Setup the done function pointer for struct request,
+ * also set the end_io_data pointer.to struct se_task.
+ */
+ req->end_io = pscsi_req_done;
+ req->end_io_data = (void *)task;
+ /*
+ * Load the referenced struct se_task's SCSI CDB into
+ * include/linux/blkdev.h:struct request->cmd
+ */
+ req->cmd_len = scsi_command_size(pt->pscsi_cdb);
+ req->cmd = &pt->pscsi_cdb[0];
+ /*
+ * Setup pointer for outgoing sense data.
+ */
+ req->sense = (void *)&pt->pscsi_sense[0];
+ req->sense_len = 0;
+}
+
+/*
+ * Used for pSCSI data payloads for all *NON* SCF_SCSI_DATA_SG_IO_CDB
+*/
+static int pscsi_blk_get_request(struct se_task *task)
+{
+ struct pscsi_plugin_task *pt = PSCSI_TASK(task);
+ struct pscsi_dev_virt *pdv = task->se_dev->dev_ptr;
+
+ pt->pscsi_req = blk_get_request(pdv->pdv_sd->request_queue,
+ (task->task_data_direction == DMA_TO_DEVICE),
+ GFP_KERNEL);
+ if (!(pt->pscsi_req) || IS_ERR(pt->pscsi_req)) {
+ printk(KERN_ERR "PSCSI: blk_get_request() failed: %ld\n",
+ IS_ERR(pt->pscsi_req));
+ return PYX_TRANSPORT_LU_COMM_FAILURE;
+ }
+ /*
+ * Setup the newly allocated struct request for REQ_TYPE_BLOCK_PC,
+ * and setup rq callback, CDB and sense.
+ */
+ pscsi_blk_init_request(task, pt, pt->pscsi_req, 0);
+ return 0;
+}
+
+/* pscsi_do_task(): (Part of se_subsystem_api_t template)
+ *
+ *
+ */
+static int pscsi_do_task(struct se_task *task)
+{
+ struct pscsi_plugin_task *pt = PSCSI_TASK(task);
+ struct pscsi_dev_virt *pdv = task->se_dev->dev_ptr;
+ /*
+ * Set the struct request->timeout value based on peripheral
+ * device type from SCSI.
+ */
+ if (pdv->pdv_sd->type == TYPE_DISK)
+ pt->pscsi_req->timeout = PS_TIMEOUT_DISK;
+ else
+ pt->pscsi_req->timeout = PS_TIMEOUT_OTHER;
+
+ pt->pscsi_req->retries = PS_RETRY;
+ /*
+ * Queue the struct request into the struct scsi_device->request_queue.
+ * Also check for HEAD_OF_QUEUE SAM TASK attr from received se_cmd
+ * descriptor
+ */
+ blk_execute_rq_nowait(pdv->pdv_sd->request_queue, NULL, pt->pscsi_req,
+ (task->task_se_cmd->sam_task_attr == TASK_ATTR_HOQ),
+ pscsi_req_done);
+
+ return PYX_TRANSPORT_SENT_TO_TRANSPORT;
+}
+
+static void pscsi_free_task(struct se_task *task)
+{
+ struct pscsi_plugin_task *pt = PSCSI_TASK(task);
+ struct se_cmd *cmd = task->task_se_cmd;
+
+ /*
+ * Release the extended CDB allocation from pscsi_alloc_task()
+ * if one exists.
+ */
+ if (T_TASK(cmd)->t_task_cdb != T_TASK(cmd)->__t_task_cdb)
+ kfree(pt->pscsi_cdb);
+ /*
+ * We do not release the bio(s) here associated with this task, as
+ * this is handled by bio_put() and pscsi_bi_endio().
+ */
+ kfree(pt);
+}
+
+enum {
+ Opt_scsi_host_id, Opt_scsi_channel_id, Opt_scsi_target_id,
+ Opt_scsi_lun_id, Opt_err
+};
+
+static match_table_t tokens = {
+ {Opt_scsi_host_id, "scsi_host_id=%d"},
+ {Opt_scsi_channel_id, "scsi_channel_id=%d"},
+ {Opt_scsi_target_id, "scsi_target_id=%d"},
+ {Opt_scsi_lun_id, "scsi_lun_id=%d"},
+ {Opt_err, NULL}
+};
+
+static ssize_t pscsi_set_configfs_dev_params(struct se_hba *hba,
+ struct se_subsystem_dev *se_dev,
+ const char *page,
+ ssize_t count)
+{
+ struct pscsi_dev_virt *pdv = se_dev->se_dev_su_ptr;
+ struct pscsi_hba_virt *phv = hba->hba_ptr;
+ char *orig, *ptr, *opts;
+ substring_t args[MAX_OPT_ARGS];
+ int ret = 0, arg, token;
+
+ opts = kstrdup(page, GFP_KERNEL);
+ if (!opts)
+ return -ENOMEM;
+
+ orig = opts;
+
+ while ((ptr = strsep(&opts, ",")) != NULL) {
+ if (!*ptr)
+ continue;
+
+ token = match_token(ptr, tokens, args);
+ switch (token) {
+ case Opt_scsi_host_id:
+ if (phv->phv_mode == PHV_LLD_SCSI_HOST_NO) {
+ printk(KERN_ERR "PSCSI[%d]: Unable to accept"
+ " scsi_host_id while phv_mode =="
+ " PHV_LLD_SCSI_HOST_NO\n",
+ phv->phv_host_id);
+ ret = -EINVAL;
+ goto out;
+ }
+ match_int(args, &arg);
+ pdv->pdv_host_id = arg;
+ printk(KERN_INFO "PSCSI[%d]: Referencing SCSI Host ID:"
+ " %d\n", phv->phv_host_id, pdv->pdv_host_id);
+ pdv->pdv_flags |= PDF_HAS_VIRT_HOST_ID;
+ break;
+ case Opt_scsi_channel_id:
+ match_int(args, &arg);
+ pdv->pdv_channel_id = arg;
+ printk(KERN_INFO "PSCSI[%d]: Referencing SCSI Channel"
+ " ID: %d\n", phv->phv_host_id,
+ pdv->pdv_channel_id);
+ pdv->pdv_flags |= PDF_HAS_CHANNEL_ID;
+ break;
+ case Opt_scsi_target_id:
+ match_int(args, &arg);
+ pdv->pdv_target_id = arg;
+ printk(KERN_INFO "PSCSI[%d]: Referencing SCSI Target"
+ " ID: %d\n", phv->phv_host_id,
+ pdv->pdv_target_id);
+ pdv->pdv_flags |= PDF_HAS_TARGET_ID;
+ break;
+ case Opt_scsi_lun_id:
+ match_int(args, &arg);
+ pdv->pdv_lun_id = arg;
+ printk(KERN_INFO "PSCSI[%d]: Referencing SCSI LUN ID:"
+ " %d\n", phv->phv_host_id, pdv->pdv_lun_id);
+ pdv->pdv_flags |= PDF_HAS_LUN_ID;
+ break;
+ default:
+ break;
+ }
+ }
+
+out:
+ kfree(orig);
+ return (!ret) ? count : ret;
+}
+
+static ssize_t pscsi_check_configfs_dev_params(
+ struct se_hba *hba,
+ struct se_subsystem_dev *se_dev)
+{
+ struct pscsi_dev_virt *pdv = se_dev->se_dev_su_ptr;
+
+ if (!(pdv->pdv_flags & PDF_HAS_CHANNEL_ID) ||
+ !(pdv->pdv_flags & PDF_HAS_TARGET_ID) ||
+ !(pdv->pdv_flags & PDF_HAS_LUN_ID)) {
+ printk(KERN_ERR "Missing scsi_channel_id=, scsi_target_id= and"
+ " scsi_lun_id= parameters\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static ssize_t pscsi_show_configfs_dev_params(struct se_hba *hba,
+ struct se_subsystem_dev *se_dev,
+ char *b)
+{
+ struct pscsi_hba_virt *phv = hba->hba_ptr;
+ struct pscsi_dev_virt *pdv = se_dev->se_dev_su_ptr;
+ struct scsi_device *sd = pdv->pdv_sd;
+ unsigned char host_id[16];
+ ssize_t bl;
+ int i;
+
+ if (phv->phv_mode == PHV_VIRUTAL_HOST_ID)
+ snprintf(host_id, 16, "%d", pdv->pdv_host_id);
+ else
+ snprintf(host_id, 16, "PHBA Mode");
+
+ bl = sprintf(b, "SCSI Device Bus Location:"
+ " Channel ID: %d Target ID: %d LUN: %d Host ID: %s\n",
+ pdv->pdv_channel_id, pdv->pdv_target_id, pdv->pdv_lun_id,
+ host_id);
+
+ if (sd) {
+ bl += sprintf(b + bl, " ");
+ bl += sprintf(b + bl, "Vendor: ");
+ for (i = 0; i < 8; i++) {
+ if (ISPRINT(sd->vendor[i])) /* printable character? */
+ bl += sprintf(b + bl, "%c", sd->vendor[i]);
+ else
+ bl += sprintf(b + bl, " ");
+ }
+ bl += sprintf(b + bl, " Model: ");
+ for (i = 0; i < 16; i++) {
+ if (ISPRINT(sd->model[i])) /* printable character ? */
+ bl += sprintf(b + bl, "%c", sd->model[i]);
+ else
+ bl += sprintf(b + bl, " ");
+ }
+ bl += sprintf(b + bl, " Rev: ");
+ for (i = 0; i < 4; i++) {
+ if (ISPRINT(sd->rev[i])) /* printable character ? */
+ bl += sprintf(b + bl, "%c", sd->rev[i]);
+ else
+ bl += sprintf(b + bl, " ");
+ }
+ bl += sprintf(b + bl, "\n");
+ }
+ return bl;
+}
+
+static void pscsi_bi_endio(struct bio *bio, int error)
+{
+ bio_put(bio);
+}
+
+static inline struct bio *pscsi_get_bio(struct pscsi_dev_virt *pdv, int sg_num)
+{
+ struct bio *bio;
+ /*
+ * Use bio_malloc() following the comment in for bio -> struct request
+ * in block/blk-core.c:blk_make_request()
+ */
+ bio = bio_kmalloc(GFP_KERNEL, sg_num);
+ if (!(bio)) {
+ printk(KERN_ERR "PSCSI: bio_kmalloc() failed\n");
+ return NULL;
+ }
+ bio->bi_end_io = pscsi_bi_endio;
+
+ return bio;
+}
+
+#if 0
+#define DEBUG_PSCSI(x...) printk(x)
+#else
+#define DEBUG_PSCSI(x...)
+#endif
+
+static int __pscsi_map_task_SG(
+ struct se_task *task,
+ struct scatterlist *task_sg,
+ u32 task_sg_num,
+ int bidi_read)
+{
+ struct pscsi_plugin_task *pt = PSCSI_TASK(task);
+ struct pscsi_dev_virt *pdv = task->se_dev->dev_ptr;
+ struct bio *bio = NULL, *hbio = NULL, *tbio = NULL;
+ struct page *page;
+ struct scatterlist *sg;
+ u32 data_len = task->task_size, i, len, bytes, off;
+ int nr_pages = (task->task_size + task_sg[0].offset +
+ PAGE_SIZE - 1) >> PAGE_SHIFT;
+ int nr_vecs = 0, rc, ret = PYX_TRANSPORT_OUT_OF_MEMORY_RESOURCES;
+ int rw = (task->task_data_direction == DMA_TO_DEVICE);
+
+ if (!task->task_size)
+ return 0;
+ /*
+ * For SCF_SCSI_DATA_SG_IO_CDB, Use fs/bio.c:bio_add_page() to setup
+ * the bio_vec maplist from TC< struct se_mem -> task->task_sg ->
+ * struct scatterlist memory. The struct se_task->task_sg[] currently needs
+ * to be attached to struct bios for submission to Linux/SCSI using
+ * struct request to struct scsi_device->request_queue.
+ *
+ * Note that this will be changing post v2.6.28 as Target_Core_Mod/pSCSI
+ * is ported to upstream SCSI passthrough functionality that accepts
+ * struct scatterlist->page_link or struct page as a paraemeter.
+ */
+ DEBUG_PSCSI("PSCSI: nr_pages: %d\n", nr_pages);
+
+ for_each_sg(task_sg, sg, task_sg_num, i) {
+ page = sg_page(sg);
+ off = sg->offset;
+ len = sg->length;
+
+ DEBUG_PSCSI("PSCSI: i: %d page: %p len: %d off: %d\n", i,
+ page, len, off);
+
+ while (len > 0 && data_len > 0) {
+ bytes = min_t(unsigned int, len, PAGE_SIZE - off);
+ bytes = min(bytes, data_len);
+
+ if (!(bio)) {
+ nr_vecs = min_t(int, BIO_MAX_PAGES, nr_pages);
+ nr_pages -= nr_vecs;
+ /*
+ * Calls bio_kmalloc() and sets bio->bi_end_io()
+ */
+ bio = pscsi_get_bio(pdv, nr_vecs);
+ if (!(bio))
+ goto fail;
+
+ if (rw)
+ bio->bi_rw |= REQ_WRITE;
+
+ DEBUG_PSCSI("PSCSI: Allocated bio: %p,"
+ " dir: %s nr_vecs: %d\n", bio,
+ (rw) ? "rw" : "r", nr_vecs);
+ /*
+ * Set *hbio pointer to handle the case:
+ * nr_pages > BIO_MAX_PAGES, where additional
+ * bios need to be added to complete a given
+ * struct se_task
+ */
+ if (!hbio)
+ hbio = tbio = bio;
+ else
+ tbio = tbio->bi_next = bio;
+ }
+
+ DEBUG_PSCSI("PSCSI: Calling bio_add_pc_page() i: %d"
+ " bio: %p page: %p len: %d off: %d\n", i, bio,
+ page, len, off);
+
+ rc = bio_add_pc_page(pdv->pdv_sd->request_queue,
+ bio, page, bytes, off);
+ if (rc != bytes)
+ goto fail;
+
+ DEBUG_PSCSI("PSCSI: bio->bi_vcnt: %d nr_vecs: %d\n",
+ bio->bi_vcnt, nr_vecs);
+
+ if (bio->bi_vcnt > nr_vecs) {
+ DEBUG_PSCSI("PSCSI: Reached bio->bi_vcnt max:"
+ " %d i: %d bio: %p, allocating another"
+ " bio\n", bio->bi_vcnt, i, bio);
+ /*
+ * Clear the pointer so that another bio will
+ * be allocated with pscsi_get_bio() above, the
+ * current bio has already been set *tbio and
+ * bio->bi_next.
+ */
+ bio = NULL;
+ }
+
+ page++;
+ len -= bytes;
+ data_len -= bytes;
+ off = 0;
+ }
+ }
+ /*
+ * Setup the primary pt->pscsi_req used for non BIDI and BIDI-COMMAND
+ * primary SCSI WRITE poayload mapped for struct se_task->task_sg[]
+ */
+ if (!(bidi_read)) {
+ /*
+ * Starting with v2.6.31, call blk_make_request() passing in *hbio to
+ * allocate the pSCSI task a struct request.
+ */
+ pt->pscsi_req = blk_make_request(pdv->pdv_sd->request_queue,
+ hbio, GFP_KERNEL);
+ if (!(pt->pscsi_req)) {
+ printk(KERN_ERR "pSCSI: blk_make_request() failed\n");
+ goto fail;
+ }
+ /*
+ * Setup the newly allocated struct request for REQ_TYPE_BLOCK_PC,
+ * and setup rq callback, CDB and sense.
+ */
+ pscsi_blk_init_request(task, pt, pt->pscsi_req, 0);
+
+ return task->task_sg_num;
+ }
+ /*
+ * Setup the secondary pt->pscsi_req->next_rq used for the extra BIDI-COMMAND
+ * SCSI READ paylaod mapped for struct se_task->task_sg_bidi[]
+ */
+ pt->pscsi_req->next_rq = blk_make_request(pdv->pdv_sd->request_queue,
+ hbio, GFP_KERNEL);
+ if (!(pt->pscsi_req->next_rq)) {
+ printk(KERN_ERR "pSCSI: blk_make_request() failed for BIDI\n");
+ goto fail;
+ }
+ pscsi_blk_init_request(task, pt, pt->pscsi_req->next_rq, 1);
+
+ return task->task_sg_num;
+fail:
+ while (hbio) {
+ bio = hbio;
+ hbio = hbio->bi_next;
+ bio->bi_next = NULL;
+ bio_endio(bio, 0);
+ }
+ return ret;
+}
+
+static int pscsi_map_task_SG(struct se_task *task)
+{
+ int ret;
+
+ /*
+ * Setup the main struct request for the task->task_sg[] payload
+ */
+
+ ret = __pscsi_map_task_SG(task, task->task_sg, task->task_sg_num, 0);
+ if (ret >= 0 && task->task_sg_bidi) {
+ /*
+ * If present, set up the extra BIDI-COMMAND SCSI READ
+ * struct request and payload.
+ */
+ ret = __pscsi_map_task_SG(task, task->task_sg_bidi,
+ task->task_sg_num, 1);
+ }
+
+ if (ret < 0)
+ return PYX_TRANSPORT_LU_COMM_FAILURE;
+ return 0;
+}
+
+/* pscsi_map_task_non_SG():
+ *
+ *
+ */
+static int pscsi_map_task_non_SG(struct se_task *task)
+{
+ struct se_cmd *cmd = TASK_CMD(task);
+ struct pscsi_plugin_task *pt = PSCSI_TASK(task);
+ struct pscsi_dev_virt *pdv = task->se_dev->dev_ptr;
+ int ret = 0;
+
+ if (pscsi_blk_get_request(task) < 0)
+ return PYX_TRANSPORT_LU_COMM_FAILURE;
+
+ if (!task->task_size)
+ return 0;
+
+ ret = blk_rq_map_kern(pdv->pdv_sd->request_queue,
+ pt->pscsi_req, T_TASK(cmd)->t_task_buf,
+ task->task_size, GFP_KERNEL);
+ if (ret < 0) {
+ printk(KERN_ERR "PSCSI: blk_rq_map_kern() failed: %d\n", ret);
+ return PYX_TRANSPORT_LU_COMM_FAILURE;
+ }
+ return 0;
+}
+
+static int pscsi_CDB_none(struct se_task *task)
+{
+ return pscsi_blk_get_request(task);
+}
+
+/* pscsi_get_cdb():
+ *
+ *
+ */
+static unsigned char *pscsi_get_cdb(struct se_task *task)
+{
+ struct pscsi_plugin_task *pt = PSCSI_TASK(task);
+
+ return pt->pscsi_cdb;
+}
+
+/* pscsi_get_sense_buffer():
+ *
+ *
+ */
+static unsigned char *pscsi_get_sense_buffer(struct se_task *task)
+{
+ struct pscsi_plugin_task *pt = PSCSI_TASK(task);
+
+ return (unsigned char *)&pt->pscsi_sense[0];
+}
+
+/* pscsi_get_device_rev():
+ *
+ *
+ */
+static u32 pscsi_get_device_rev(struct se_device *dev)
+{
+ struct pscsi_dev_virt *pdv = dev->dev_ptr;
+ struct scsi_device *sd = pdv->pdv_sd;
+
+ return (sd->scsi_level - 1) ? sd->scsi_level - 1 : 1;
+}
+
+/* pscsi_get_device_type():
+ *
+ *
+ */
+static u32 pscsi_get_device_type(struct se_device *dev)
+{
+ struct pscsi_dev_virt *pdv = dev->dev_ptr;
+ struct scsi_device *sd = pdv->pdv_sd;
+
+ return sd->type;
+}
+
+static sector_t pscsi_get_blocks(struct se_device *dev)
+{
+ struct pscsi_dev_virt *pdv = dev->dev_ptr;
+
+ if (pdv->pdv_bd && pdv->pdv_bd->bd_part)
+ return pdv->pdv_bd->bd_part->nr_sects;
+
+ dump_stack();
+ return 0;
+}
+
+/* pscsi_handle_SAM_STATUS_failures():
+ *
+ *
+ */
+static inline void pscsi_process_SAM_status(
+ struct se_task *task,
+ struct pscsi_plugin_task *pt)
+{
+ task->task_scsi_status = status_byte(pt->pscsi_result);
+ if ((task->task_scsi_status)) {
+ task->task_scsi_status <<= 1;
+ printk(KERN_INFO "PSCSI Status Byte exception at task: %p CDB:"
+ " 0x%02x Result: 0x%08x\n", task, pt->pscsi_cdb[0],
+ pt->pscsi_result);
+ }
+
+ switch (host_byte(pt->pscsi_result)) {
+ case DID_OK:
+ transport_complete_task(task, (!task->task_scsi_status));
+ break;
+ default:
+ printk(KERN_INFO "PSCSI Host Byte exception at task: %p CDB:"
+ " 0x%02x Result: 0x%08x\n", task, pt->pscsi_cdb[0],
+ pt->pscsi_result);
+ task->task_scsi_status = SAM_STAT_CHECK_CONDITION;
+ task->task_error_status = PYX_TRANSPORT_UNKNOWN_SAM_OPCODE;
+ TASK_CMD(task)->transport_error_status =
+ PYX_TRANSPORT_UNKNOWN_SAM_OPCODE;
+ transport_complete_task(task, 0);
+ break;
+ }
+
+ return;
+}
+
+static void pscsi_req_done(struct request *req, int uptodate)
+{
+ struct se_task *task = req->end_io_data;
+ struct pscsi_plugin_task *pt = PSCSI_TASK(task);
+
+ pt->pscsi_result = req->errors;
+ pt->pscsi_resid = req->resid_len;
+
+ pscsi_process_SAM_status(task, pt);
+ /*
+ * Release BIDI-READ if present
+ */
+ if (req->next_rq != NULL)
+ __blk_put_request(req->q, req->next_rq);
+
+ __blk_put_request(req->q, req);
+ pt->pscsi_req = NULL;
+}
+
+static struct se_subsystem_api pscsi_template = {
+ .name = "pscsi",
+ .owner = THIS_MODULE,
+ .transport_type = TRANSPORT_PLUGIN_PHBA_PDEV,
+ .cdb_none = pscsi_CDB_none,
+ .map_task_non_SG = pscsi_map_task_non_SG,
+ .map_task_SG = pscsi_map_task_SG,
+ .attach_hba = pscsi_attach_hba,
+ .detach_hba = pscsi_detach_hba,
+ .pmode_enable_hba = pscsi_pmode_enable_hba,
+ .allocate_virtdevice = pscsi_allocate_virtdevice,
+ .create_virtdevice = pscsi_create_virtdevice,
+ .free_device = pscsi_free_device,
+ .transport_complete = pscsi_transport_complete,
+ .alloc_task = pscsi_alloc_task,
+ .do_task = pscsi_do_task,
+ .free_task = pscsi_free_task,
+ .check_configfs_dev_params = pscsi_check_configfs_dev_params,
+ .set_configfs_dev_params = pscsi_set_configfs_dev_params,
+ .show_configfs_dev_params = pscsi_show_configfs_dev_params,
+ .get_cdb = pscsi_get_cdb,
+ .get_sense_buffer = pscsi_get_sense_buffer,
+ .get_device_rev = pscsi_get_device_rev,
+ .get_device_type = pscsi_get_device_type,
+ .get_blocks = pscsi_get_blocks,
+};
+
+static int __init pscsi_module_init(void)
+{
+ return transport_subsystem_register(&pscsi_template);
+}
+
+static void pscsi_module_exit(void)
+{
+ transport_subsystem_release(&pscsi_template);
+}
+
+MODULE_DESCRIPTION("TCM PSCSI subsystem plugin");
+MODULE_AUTHOR("nab@Linux-iSCSI.org");
+MODULE_LICENSE("GPL");
+
+module_init(pscsi_module_init);
+module_exit(pscsi_module_exit);
diff --git a/drivers/target/target_core_pscsi.h b/drivers/target/target_core_pscsi.h
new file mode 100644
index 0000000..a4cd5d3
--- /dev/null
+++ b/drivers/target/target_core_pscsi.h
@@ -0,0 +1,65 @@
+#ifndef TARGET_CORE_PSCSI_H
+#define TARGET_CORE_PSCSI_H
+
+#define PSCSI_VERSION "v4.0"
+#define PSCSI_VIRTUAL_HBA_DEPTH 2048
+
+/* used in pscsi_find_alloc_len() */
+#ifndef INQUIRY_DATA_SIZE
+#define INQUIRY_DATA_SIZE 0x24
+#endif
+
+/* used in pscsi_add_device_to_list() */
+#define PSCSI_DEFAULT_QUEUEDEPTH 1
+
+#define PS_RETRY 5
+#define PS_TIMEOUT_DISK (15*HZ)
+#define PS_TIMEOUT_OTHER (500*HZ)
+
+#include <linux/device.h>
+#include <scsi/scsi_driver.h>
+#include <scsi/scsi_device.h>
+#include <linux/kref.h>
+#include <linux/kobject.h>
+
+struct pscsi_plugin_task {
+ struct se_task pscsi_task;
+ unsigned char *pscsi_cdb;
+ unsigned char __pscsi_cdb[TCM_MAX_COMMAND_SIZE];
+ unsigned char pscsi_sense[SCSI_SENSE_BUFFERSIZE];
+ int pscsi_direction;
+ int pscsi_result;
+ u32 pscsi_resid;
+ struct request *pscsi_req;
+} ____cacheline_aligned;
+
+#define PDF_HAS_CHANNEL_ID 0x01
+#define PDF_HAS_TARGET_ID 0x02
+#define PDF_HAS_LUN_ID 0x04
+#define PDF_HAS_VPD_UNIT_SERIAL 0x08
+#define PDF_HAS_VPD_DEV_IDENT 0x10
+#define PDF_HAS_VIRT_HOST_ID 0x20
+
+struct pscsi_dev_virt {
+ int pdv_flags;
+ int pdv_host_id;
+ int pdv_channel_id;
+ int pdv_target_id;
+ int pdv_lun_id;
+ struct block_device *pdv_bd;
+ struct scsi_device *pdv_sd;
+ struct se_hba *pdv_se_hba;
+} ____cacheline_aligned;
+
+typedef enum phv_modes {
+ PHV_VIRUTAL_HOST_ID,
+ PHV_LLD_SCSI_HOST_NO
+} phv_modes_t;
+
+struct pscsi_hba_virt {
+ int phv_host_id;
+ phv_modes_t phv_mode;
+ struct Scsi_Host *phv_lld_host;
+} ____cacheline_aligned;
+
+#endif /*** TARGET_CORE_PSCSI_H ***/
diff --git a/drivers/target/target_core_rd.c b/drivers/target/target_core_rd.c
new file mode 100644
index 0000000..979aebf
--- /dev/null
+++ b/drivers/target/target_core_rd.c
@@ -0,0 +1,1091 @@
+/*******************************************************************************
+ * Filename: target_core_rd.c
+ *
+ * This file contains the Storage Engine <-> Ramdisk transport
+ * specific functions.
+ *
+ * Copyright (c) 2003, 2004, 2005 PyX Technologies, Inc.
+ * Copyright (c) 2005, 2006, 2007 SBE, Inc.
+ * Copyright (c) 2007-2010 Rising Tide Systems
+ * Copyright (c) 2008-2010 Linux-iSCSI.org
+ *
+ * Nicholas A. Bellinger <nab@kernel.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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ ******************************************************************************/
+
+#include <linux/version.h>
+#include <linux/string.h>
+#include <linux/parser.h>
+#include <linux/timer.h>
+#include <linux/blkdev.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/smp_lock.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_host.h>
+
+#include <target/target_core_base.h>
+#include <target/target_core_device.h>
+#include <target/target_core_transport.h>
+#include <target/target_core_fabric_ops.h>
+
+#include "target_core_rd.h"
+
+static struct se_subsystem_api rd_dr_template;
+static struct se_subsystem_api rd_mcp_template;
+
+/* #define DEBUG_RAMDISK_MCP */
+/* #define DEBUG_RAMDISK_DR */
+
+/* rd_attach_hba(): (Part of se_subsystem_api_t template)
+ *
+ *
+ */
+static int rd_attach_hba(struct se_hba *hba, u32 host_id)
+{
+ struct rd_host *rd_host;
+
+ rd_host = kzalloc(sizeof(struct rd_host), GFP_KERNEL);
+ if (!(rd_host)) {
+ printk(KERN_ERR "Unable to allocate memory for struct rd_host\n");
+ return -ENOMEM;
+ }
+
+ rd_host->rd_host_id = host_id;
+
+ atomic_set(&hba->left_queue_depth, RD_HBA_QUEUE_DEPTH);
+ atomic_set(&hba->max_queue_depth, RD_HBA_QUEUE_DEPTH);
+ hba->hba_ptr = (void *) rd_host;
+
+ printk(KERN_INFO "CORE_HBA[%d] - TCM Ramdisk HBA Driver %s on"
+ " Generic Target Core Stack %s\n", hba->hba_id,
+ RD_HBA_VERSION, TARGET_CORE_MOD_VERSION);
+ printk(KERN_INFO "CORE_HBA[%d] - Attached Ramdisk HBA: %u to Generic"
+ " Target Core TCQ Depth: %d MaxSectors: %u\n", hba->hba_id,
+ rd_host->rd_host_id, atomic_read(&hba->max_queue_depth),
+ RD_MAX_SECTORS);
+
+ return 0;
+}
+
+static void rd_detach_hba(struct se_hba *hba)
+{
+ struct rd_host *rd_host = hba->hba_ptr;
+
+ printk(KERN_INFO "CORE_HBA[%d] - Detached Ramdisk HBA: %u from"
+ " Generic Target Core\n", hba->hba_id, rd_host->rd_host_id);
+
+ kfree(rd_host);
+ hba->hba_ptr = NULL;
+}
+
+/* rd_release_device_space():
+ *
+ *
+ */
+static void rd_release_device_space(struct rd_dev *rd_dev)
+{
+ u32 i, j, page_count = 0, sg_per_table;
+ struct rd_dev_sg_table *sg_table;
+ struct page *pg;
+ struct scatterlist *sg;
+
+ if (!rd_dev->sg_table_array || !rd_dev->sg_table_count)
+ return;
+
+ sg_table = rd_dev->sg_table_array;
+
+ for (i = 0; i < rd_dev->sg_table_count; i++) {
+ sg = sg_table[i].sg_table;
+ sg_per_table = sg_table[i].rd_sg_count;
+
+ for (j = 0; j < sg_per_table; j++) {
+ pg = sg_page(&sg[j]);
+ if ((pg)) {
+ __free_page(pg);
+ page_count++;
+ }
+ }
+
+ kfree(sg);
+ }
+
+ printk(KERN_INFO "CORE_RD[%u] - Released device space for Ramdisk"
+ " Device ID: %u, pages %u in %u tables total bytes %lu\n",
+ rd_dev->rd_host->rd_host_id, rd_dev->rd_dev_id, page_count,
+ rd_dev->sg_table_count, (unsigned long)page_count * PAGE_SIZE);
+
+ kfree(sg_table);
+ rd_dev->sg_table_array = NULL;
+ rd_dev->sg_table_count = 0;
+}
+
+
+/* rd_build_device_space():
+ *
+ *
+ */
+static int rd_build_device_space(struct rd_dev *rd_dev)
+{
+ u32 i = 0, j, page_offset = 0, sg_per_table, sg_tables, total_sg_needed;
+ u32 max_sg_per_table = (RD_MAX_ALLOCATION_SIZE /
+ sizeof(struct scatterlist));
+ struct rd_dev_sg_table *sg_table;
+ struct page *pg;
+ struct scatterlist *sg;
+
+ if (rd_dev->rd_page_count <= 0) {
+ printk(KERN_ERR "Illegal page count: %u for Ramdisk device\n",
+ rd_dev->rd_page_count);
+ return -1;
+ }
+ total_sg_needed = rd_dev->rd_page_count;
+
+ sg_tables = (total_sg_needed / max_sg_per_table) + 1;
+
+ sg_table = kzalloc(sg_tables * sizeof(struct rd_dev_sg_table), GFP_KERNEL);
+ if (!(sg_table)) {
+ printk(KERN_ERR "Unable to allocate memory for Ramdisk"
+ " scatterlist tables\n");
+ return -1;
+ }
+
+ rd_dev->sg_table_array = sg_table;
+ rd_dev->sg_table_count = sg_tables;
+
+ while (total_sg_needed) {
+ sg_per_table = (total_sg_needed > max_sg_per_table) ?
+ max_sg_per_table : total_sg_needed;
+
+ sg = kzalloc(sg_per_table * sizeof(struct scatterlist),
+ GFP_KERNEL);
+ if (!(sg)) {
+ printk(KERN_ERR "Unable to allocate scatterlist array"
+ " for struct rd_dev\n");
+ return -1;
+ }
+
+ sg_init_table((struct scatterlist *)&sg[0], sg_per_table);
+
+ sg_table[i].sg_table = sg;
+ sg_table[i].rd_sg_count = sg_per_table;
+ sg_table[i].page_start_offset = page_offset;
+ sg_table[i++].page_end_offset = (page_offset + sg_per_table)
+ - 1;
+
+ for (j = 0; j < sg_per_table; j++) {
+ pg = alloc_pages(GFP_KERNEL, 0);
+ if (!(pg)) {
+ printk(KERN_ERR "Unable to allocate scatterlist"
+ " pages for struct rd_dev_sg_table\n");
+ return -1;
+ }
+ sg_assign_page(&sg[j], pg);
+ sg[j].length = PAGE_SIZE;
+ }
+
+ page_offset += sg_per_table;
+ total_sg_needed -= sg_per_table;
+ }
+
+ printk(KERN_INFO "CORE_RD[%u] - Built Ramdisk Device ID: %u space of"
+ " %u pages in %u tables\n", rd_dev->rd_host->rd_host_id,
+ rd_dev->rd_dev_id, rd_dev->rd_page_count,
+ rd_dev->sg_table_count);
+
+ return 0;
+}
+
+static void *rd_allocate_virtdevice(
+ struct se_hba *hba,
+ const char *name,
+ int rd_direct)
+{
+ struct rd_dev *rd_dev;
+ struct rd_host *rd_host = hba->hba_ptr;
+
+ rd_dev = kzalloc(sizeof(struct rd_dev), GFP_KERNEL);
+ if (!(rd_dev)) {
+ printk(KERN_ERR "Unable to allocate memory for struct rd_dev\n");
+ return NULL;
+ }
+
+ rd_dev->rd_host = rd_host;
+ rd_dev->rd_direct = rd_direct;
+
+ return rd_dev;
+}
+
+static void *rd_DIRECT_allocate_virtdevice(struct se_hba *hba, const char *name)
+{
+ return rd_allocate_virtdevice(hba, name, 1);
+}
+
+static void *rd_MEMCPY_allocate_virtdevice(struct se_hba *hba, const char *name)
+{
+ return rd_allocate_virtdevice(hba, name, 0);
+}
+
+/* rd_create_virtdevice():
+ *
+ *
+ */
+static struct se_device *rd_create_virtdevice(
+ struct se_hba *hba,
+ struct se_subsystem_dev *se_dev,
+ void *p,
+ int rd_direct)
+{
+ struct se_device *dev;
+ struct se_dev_limits dev_limits;
+ struct rd_dev *rd_dev = p;
+ struct rd_host *rd_host = hba->hba_ptr;
+ int dev_flags = 0;
+ char prod[16], rev[4];
+
+ memset(&dev_limits, 0, sizeof(struct se_dev_limits));
+
+ if (rd_build_device_space(rd_dev) < 0)
+ goto fail;
+
+ snprintf(prod, 16, "RAMDISK-%s", (rd_dev->rd_direct) ? "DR" : "MCP");
+ snprintf(rev, 4, "%s", (rd_dev->rd_direct) ? RD_DR_VERSION :
+ RD_MCP_VERSION);
+
+ dev_limits.limits.logical_block_size = RD_BLOCKSIZE;
+ dev_limits.limits.max_hw_sectors = RD_MAX_SECTORS;
+ dev_limits.limits.max_sectors = RD_MAX_SECTORS;
+ dev_limits.hw_queue_depth = RD_MAX_DEVICE_QUEUE_DEPTH;
+ dev_limits.queue_depth = RD_DEVICE_QUEUE_DEPTH;
+
+ dev = transport_add_device_to_core_hba(hba,
+ (rd_dev->rd_direct) ? &rd_dr_template :
+ &rd_mcp_template, se_dev, dev_flags, (void *)rd_dev,
+ &dev_limits, prod, rev);
+ if (!(dev))
+ goto fail;
+
+ rd_dev->rd_dev_id = rd_host->rd_host_dev_id_count++;
+ rd_dev->rd_queue_depth = dev->queue_depth;
+
+ printk(KERN_INFO "CORE_RD[%u] - Added TCM %s Ramdisk Device ID: %u of"
+ " %u pages in %u tables, %lu total bytes\n",
+ rd_host->rd_host_id, (!rd_dev->rd_direct) ? "MEMCPY" :
+ "DIRECT", rd_dev->rd_dev_id, rd_dev->rd_page_count,
+ rd_dev->sg_table_count,
+ (unsigned long)(rd_dev->rd_page_count * PAGE_SIZE));
+
+ return dev;
+
+fail:
+ rd_release_device_space(rd_dev);
+ return NULL;
+}
+
+static struct se_device *rd_DIRECT_create_virtdevice(
+ struct se_hba *hba,
+ struct se_subsystem_dev *se_dev,
+ void *p)
+{
+ return rd_create_virtdevice(hba, se_dev, p, 1);
+}
+
+static struct se_device *rd_MEMCPY_create_virtdevice(
+ struct se_hba *hba,
+ struct se_subsystem_dev *se_dev,
+ void *p)
+{
+ return rd_create_virtdevice(hba, se_dev, p, 0);
+}
+
+/* rd_free_device(): (Part of se_subsystem_api_t template)
+ *
+ *
+ */
+static void rd_free_device(void *p)
+{
+ struct rd_dev *rd_dev = p;
+
+ rd_release_device_space(rd_dev);
+ kfree(rd_dev);
+}
+
+static inline struct rd_request *RD_REQ(struct se_task *task)
+{
+ return container_of(task, struct rd_request, rd_task);
+}
+
+static struct se_task *
+rd_alloc_task(struct se_cmd *cmd)
+{
+ struct rd_request *rd_req;
+
+ rd_req = kzalloc(sizeof(struct rd_request), GFP_KERNEL);
+ if (!rd_req) {
+ printk(KERN_ERR "Unable to allocate struct rd_request\n");
+ return NULL;
+ }
+ rd_req->rd_dev = SE_DEV(cmd)->dev_ptr;
+
+ return &rd_req->rd_task;
+}
+
+/* rd_get_sg_table():
+ *
+ *
+ */
+static struct rd_dev_sg_table *rd_get_sg_table(struct rd_dev *rd_dev, u32 page)
+{
+ u32 i;
+ struct rd_dev_sg_table *sg_table;
+
+ for (i = 0; i < rd_dev->sg_table_count; i++) {
+ sg_table = &rd_dev->sg_table_array[i];
+ if ((sg_table->page_start_offset <= page) &&
+ (sg_table->page_end_offset >= page))
+ return sg_table;
+ }
+
+ printk(KERN_ERR "Unable to locate struct rd_dev_sg_table for page: %u\n",
+ page);
+
+ return NULL;
+}
+
+/* rd_MEMCPY_read():
+ *
+ *
+ */
+static int rd_MEMCPY_read(struct rd_request *req)
+{
+ struct se_task *task = &req->rd_task;
+ struct rd_dev *dev = req->rd_dev;
+ struct rd_dev_sg_table *table;
+ struct scatterlist *sg_d, *sg_s;
+ void *dst, *src;
+ u32 i = 0, j = 0, dst_offset = 0, src_offset = 0;
+ u32 length, page_end = 0, table_sg_end;
+ u32 rd_offset = req->rd_offset;
+
+ table = rd_get_sg_table(dev, req->rd_page);
+ if (!(table))
+ return -1;
+
+ table_sg_end = (table->page_end_offset - req->rd_page);
+ sg_d = task->task_sg;
+ sg_s = &table->sg_table[req->rd_page - table->page_start_offset];
+#ifdef DEBUG_RAMDISK_MCP
+ printk(KERN_INFO "RD[%u]: Read LBA: %llu, Size: %u Page: %u, Offset:"
+ " %u\n", dev->rd_dev_id, task->task_lba, req->rd_size,
+ req->rd_page, req->rd_offset);
+#endif
+ src_offset = rd_offset;
+
+ while (req->rd_size) {
+ if ((sg_d[i].length - dst_offset) <
+ (sg_s[j].length - src_offset)) {
+ length = (sg_d[i].length - dst_offset);
+#ifdef DEBUG_RAMDISK_MCP
+ printk(KERN_INFO "Step 1 - sg_d[%d]: %p length: %d"
+ " offset: %u sg_s[%d].length: %u\n", i,
+ &sg_d[i], sg_d[i].length, sg_d[i].offset, j,
+ sg_s[j].length);
+ printk(KERN_INFO "Step 1 - length: %u dst_offset: %u"
+ " src_offset: %u\n", length, dst_offset,
+ src_offset);
+#endif
+ if (length > req->rd_size)
+ length = req->rd_size;
+
+ dst = sg_virt(&sg_d[i++]) + dst_offset;
+ if (!dst)
+ BUG();
+
+ src = sg_virt(&sg_s[j]) + src_offset;
+ if (!src)
+ BUG();
+
+ dst_offset = 0;
+ src_offset = length;
+ page_end = 0;
+ } else {
+ length = (sg_s[j].length - src_offset);
+#ifdef DEBUG_RAMDISK_MCP
+ printk(KERN_INFO "Step 2 - sg_d[%d]: %p length: %d"
+ " offset: %u sg_s[%d].length: %u\n", i,
+ &sg_d[i], sg_d[i].length, sg_d[i].offset,
+ j, sg_s[j].length);
+ printk(KERN_INFO "Step 2 - length: %u dst_offset: %u"
+ " src_offset: %u\n", length, dst_offset,
+ src_offset);
+#endif
+ if (length > req->rd_size)
+ length = req->rd_size;
+
+ dst = sg_virt(&sg_d[i]) + dst_offset;
+ if (!dst)
+ BUG();
+
+ if (sg_d[i].length == length) {
+ i++;
+ dst_offset = 0;
+ } else
+ dst_offset = length;
+
+ src = sg_virt(&sg_s[j++]) + src_offset;
+ if (!src)
+ BUG();
+
+ src_offset = 0;
+ page_end = 1;
+ }
+
+ memcpy(dst, src, length);
+
+#ifdef DEBUG_RAMDISK_MCP
+ printk(KERN_INFO "page: %u, remaining size: %u, length: %u,"
+ " i: %u, j: %u\n", req->rd_page,
+ (req->rd_size - length), length, i, j);
+#endif
+ req->rd_size -= length;
+ if (!(req->rd_size))
+ return 0;
+
+ if (!page_end)
+ continue;
+
+ if (++req->rd_page <= table->page_end_offset) {
+#ifdef DEBUG_RAMDISK_MCP
+ printk(KERN_INFO "page: %u in same page table\n",
+ req->rd_page);
+#endif
+ continue;
+ }
+#ifdef DEBUG_RAMDISK_MCP
+ printk(KERN_INFO "getting new page table for page: %u\n",
+ req->rd_page);
+#endif
+ table = rd_get_sg_table(dev, req->rd_page);
+ if (!(table))
+ return -1;
+
+ sg_s = &table->sg_table[j = 0];
+ }
+
+ return 0;
+}
+
+/* rd_MEMCPY_write():
+ *
+ *
+ */
+static int rd_MEMCPY_write(struct rd_request *req)
+{
+ struct se_task *task = &req->rd_task;
+ struct rd_dev *dev = req->rd_dev;
+ struct rd_dev_sg_table *table;
+ struct scatterlist *sg_d, *sg_s;
+ void *dst, *src;
+ u32 i = 0, j = 0, dst_offset = 0, src_offset = 0;
+ u32 length, page_end = 0, table_sg_end;
+ u32 rd_offset = req->rd_offset;
+
+ table = rd_get_sg_table(dev, req->rd_page);
+ if (!(table))
+ return -1;
+
+ table_sg_end = (table->page_end_offset - req->rd_page);
+ sg_d = &table->sg_table[req->rd_page - table->page_start_offset];
+ sg_s = task->task_sg;
+#ifdef DEBUG_RAMDISK_MCP
+ printk(KERN_INFO "RD[%d] Write LBA: %llu, Size: %u, Page: %u,"
+ " Offset: %u\n", dev->rd_dev_id, task->task_lba, req->rd_size,
+ req->rd_page, req->rd_offset);
+#endif
+ dst_offset = rd_offset;
+
+ while (req->rd_size) {
+ if ((sg_s[i].length - src_offset) <
+ (sg_d[j].length - dst_offset)) {
+ length = (sg_s[i].length - src_offset);
+#ifdef DEBUG_RAMDISK_MCP
+ printk(KERN_INFO "Step 1 - sg_s[%d]: %p length: %d"
+ " offset: %d sg_d[%d].length: %u\n", i,
+ &sg_s[i], sg_s[i].length, sg_s[i].offset,
+ j, sg_d[j].length);
+ printk(KERN_INFO "Step 1 - length: %u src_offset: %u"
+ " dst_offset: %u\n", length, src_offset,
+ dst_offset);
+#endif
+ if (length > req->rd_size)
+ length = req->rd_size;
+
+ src = sg_virt(&sg_s[i++]) + src_offset;
+ if (!src)
+ BUG();
+
+ dst = sg_virt(&sg_d[j]) + dst_offset;
+ if (!dst)
+ BUG();
+
+ src_offset = 0;
+ dst_offset = length;
+ page_end = 0;
+ } else {
+ length = (sg_d[j].length - dst_offset);
+#ifdef DEBUG_RAMDISK_MCP
+ printk(KERN_INFO "Step 2 - sg_s[%d]: %p length: %d"
+ " offset: %d sg_d[%d].length: %u\n", i,
+ &sg_s[i], sg_s[i].length, sg_s[i].offset,
+ j, sg_d[j].length);
+ printk(KERN_INFO "Step 2 - length: %u src_offset: %u"
+ " dst_offset: %u\n", length, src_offset,
+ dst_offset);
+#endif
+ if (length > req->rd_size)
+ length = req->rd_size;
+
+ src = sg_virt(&sg_s[i]) + src_offset;
+ if (!src)
+ BUG();
+
+ if (sg_s[i].length == length) {
+ i++;
+ src_offset = 0;
+ } else
+ src_offset = length;
+
+ dst = sg_virt(&sg_d[j++]) + dst_offset;
+ if (!dst)
+ BUG();
+
+ dst_offset = 0;
+ page_end = 1;
+ }
+
+ memcpy(dst, src, length);
+
+#ifdef DEBUG_RAMDISK_MCP
+ printk(KERN_INFO "page: %u, remaining size: %u, length: %u,"
+ " i: %u, j: %u\n", req->rd_page,
+ (req->rd_size - length), length, i, j);
+#endif
+ req->rd_size -= length;
+ if (!(req->rd_size))
+ return 0;
+
+ if (!page_end)
+ continue;
+
+ if (++req->rd_page <= table->page_end_offset) {
+#ifdef DEBUG_RAMDISK_MCP
+ printk(KERN_INFO "page: %u in same page table\n",
+ req->rd_page);
+#endif
+ continue;
+ }
+#ifdef DEBUG_RAMDISK_MCP
+ printk(KERN_INFO "getting new page table for page: %u\n",
+ req->rd_page);
+#endif
+ table = rd_get_sg_table(dev, req->rd_page);
+ if (!(table))
+ return -1;
+
+ sg_d = &table->sg_table[j = 0];
+ }
+
+ return 0;
+}
+
+/* rd_MEMCPY_do_task(): (Part of se_subsystem_api_t template)
+ *
+ *
+ */
+static int rd_MEMCPY_do_task(struct se_task *task)
+{
+ struct se_device *dev = task->se_dev;
+ struct rd_request *req = RD_REQ(task);
+ unsigned long long lba;
+ int ret;
+
+ req->rd_page = (task->task_lba * DEV_ATTRIB(dev)->block_size) / PAGE_SIZE;
+ lba = task->task_lba;
+ req->rd_offset = (do_div(lba,
+ (PAGE_SIZE / DEV_ATTRIB(dev)->block_size))) *
+ DEV_ATTRIB(dev)->block_size;
+ req->rd_size = task->task_size;
+
+ if (task->task_data_direction == DMA_FROM_DEVICE)
+ ret = rd_MEMCPY_read(req);
+ else
+ ret = rd_MEMCPY_write(req);
+
+ if (ret != 0)
+ return ret;
+
+ task->task_scsi_status = GOOD;
+ transport_complete_task(task, 1);
+
+ return PYX_TRANSPORT_SENT_TO_TRANSPORT;
+}
+
+/* rd_DIRECT_with_offset():
+ *
+ *
+ */
+static int rd_DIRECT_with_offset(
+ struct se_task *task,
+ struct list_head *se_mem_list,
+ u32 *se_mem_cnt,
+ u32 *task_offset)
+{
+ struct rd_request *req = RD_REQ(task);
+ struct rd_dev *dev = req->rd_dev;
+ struct rd_dev_sg_table *table;
+ struct se_mem *se_mem;
+ struct scatterlist *sg_s;
+ u32 j = 0, set_offset = 1;
+ u32 get_next_table = 0, offset_length, table_sg_end;
+
+ table = rd_get_sg_table(dev, req->rd_page);
+ if (!(table))
+ return -1;
+
+ table_sg_end = (table->page_end_offset - req->rd_page);
+ sg_s = &table->sg_table[req->rd_page - table->page_start_offset];
+#ifdef DEBUG_RAMDISK_DR
+ printk(KERN_INFO "%s DIRECT LBA: %llu, Size: %u Page: %u, Offset: %u\n",
+ (task->task_data_direction == DMA_TO_DEVICE) ?
+ "Write" : "Read",
+ task->task_lba, req->rd_size, req->rd_page, req->rd_offset);
+#endif
+ while (req->rd_size) {
+ se_mem = kmem_cache_zalloc(se_mem_cache, GFP_KERNEL);
+ if (!(se_mem)) {
+ printk(KERN_ERR "Unable to allocate struct se_mem\n");
+ return -1;
+ }
+ INIT_LIST_HEAD(&se_mem->se_list);
+
+ if (set_offset) {
+ offset_length = sg_s[j].length - req->rd_offset;
+ if (offset_length > req->rd_size)
+ offset_length = req->rd_size;
+
+ se_mem->se_page = sg_page(&sg_s[j++]);
+ se_mem->se_off = req->rd_offset;
+ se_mem->se_len = offset_length;
+
+ set_offset = 0;
+ get_next_table = (j > table_sg_end);
+ goto check_eot;
+ }
+
+ offset_length = (req->rd_size < req->rd_offset) ?
+ req->rd_size : req->rd_offset;
+
+ se_mem->se_page = sg_page(&sg_s[j]);
+ se_mem->se_len = offset_length;
+
+ set_offset = 1;
+
+check_eot:
+#ifdef DEBUG_RAMDISK_DR
+ printk(KERN_INFO "page: %u, size: %u, offset_length: %u, j: %u"
+ " se_mem: %p, se_page: %p se_off: %u se_len: %u\n",
+ req->rd_page, req->rd_size, offset_length, j, se_mem,
+ se_mem->se_page, se_mem->se_off, se_mem->se_len);
+#endif
+ list_add_tail(&se_mem->se_list, se_mem_list);
+ (*se_mem_cnt)++;
+
+ req->rd_size -= offset_length;
+ if (!(req->rd_size))
+ goto out;
+
+ if (!set_offset && !get_next_table)
+ continue;
+
+ if (++req->rd_page <= table->page_end_offset) {
+#ifdef DEBUG_RAMDISK_DR
+ printk(KERN_INFO "page: %u in same page table\n",
+ req->rd_page);
+#endif
+ continue;
+ }
+#ifdef DEBUG_RAMDISK_DR
+ printk(KERN_INFO "getting new page table for page: %u\n",
+ req->rd_page);
+#endif
+ table = rd_get_sg_table(dev, req->rd_page);
+ if (!(table))
+ return -1;
+
+ sg_s = &table->sg_table[j = 0];
+ }
+
+out:
+ T_TASK(task->task_se_cmd)->t_tasks_se_num += *se_mem_cnt;
+#ifdef DEBUG_RAMDISK_DR
+ printk(KERN_INFO "RD_DR - Allocated %u struct se_mem segments for task\n",
+ *se_mem_cnt);
+#endif
+ return 0;
+}
+
+/* rd_DIRECT_without_offset():
+ *
+ *
+ */
+static int rd_DIRECT_without_offset(
+ struct se_task *task,
+ struct list_head *se_mem_list,
+ u32 *se_mem_cnt,
+ u32 *task_offset)
+{
+ struct rd_request *req = RD_REQ(task);
+ struct rd_dev *dev = req->rd_dev;
+ struct rd_dev_sg_table *table;
+ struct se_mem *se_mem;
+ struct scatterlist *sg_s;
+ u32 length, j = 0;
+
+ table = rd_get_sg_table(dev, req->rd_page);
+ if (!(table))
+ return -1;
+
+ sg_s = &table->sg_table[req->rd_page - table->page_start_offset];
+#ifdef DEBUG_RAMDISK_DR
+ printk(KERN_INFO "%s DIRECT LBA: %llu, Size: %u, Page: %u\n",
+ (task->task_data_direction == DMA_TO_DEVICE) ?
+ "Write" : "Read",
+ task->task_lba, req->rd_size, req->rd_page);
+#endif
+ while (req->rd_size) {
+ se_mem = kmem_cache_zalloc(se_mem_cache, GFP_KERNEL);
+ if (!(se_mem)) {
+ printk(KERN_ERR "Unable to allocate struct se_mem\n");
+ return -1;
+ }
+ INIT_LIST_HEAD(&se_mem->se_list);
+
+ length = (req->rd_size < sg_s[j].length) ?
+ req->rd_size : sg_s[j].length;
+
+ se_mem->se_page = sg_page(&sg_s[j++]);
+ se_mem->se_len = length;
+
+#ifdef DEBUG_RAMDISK_DR
+ printk(KERN_INFO "page: %u, size: %u, j: %u se_mem: %p,"
+ " se_page: %p se_off: %u se_len: %u\n", req->rd_page,
+ req->rd_size, j, se_mem, se_mem->se_page,
+ se_mem->se_off, se_mem->se_len);
+#endif
+ list_add_tail(&se_mem->se_list, se_mem_list);
+ (*se_mem_cnt)++;
+
+ req->rd_size -= length;
+ if (!(req->rd_size))
+ goto out;
+
+ if (++req->rd_page <= table->page_end_offset) {
+#ifdef DEBUG_RAMDISK_DR
+ printk("page: %u in same page table\n",
+ req->rd_page);
+#endif
+ continue;
+ }
+#ifdef DEBUG_RAMDISK_DR
+ printk(KERN_INFO "getting new page table for page: %u\n",
+ req->rd_page);
+#endif
+ table = rd_get_sg_table(dev, req->rd_page);
+ if (!(table))
+ return -1;
+
+ sg_s = &table->sg_table[j = 0];
+ }
+
+out:
+ T_TASK(task->task_se_cmd)->t_tasks_se_num += *se_mem_cnt;
+#ifdef DEBUG_RAMDISK_DR
+ printk(KERN_INFO "RD_DR - Allocated %u struct se_mem segments for task\n",
+ *se_mem_cnt);
+#endif
+ return 0;
+}
+
+/* rd_DIRECT_do_se_mem_map():
+ *
+ *
+ */
+static int rd_DIRECT_do_se_mem_map(
+ struct se_task *task,
+ struct list_head *se_mem_list,
+ void *in_mem,
+ struct se_mem *in_se_mem,
+ struct se_mem **out_se_mem,
+ u32 *se_mem_cnt,
+ u32 *task_offset_in)
+{
+ struct se_cmd *cmd = task->task_se_cmd;
+ struct rd_request *req = RD_REQ(task);
+ u32 task_offset = *task_offset_in;
+ unsigned long long lba;
+ int ret;
+
+ req->rd_page = ((task->task_lba * DEV_ATTRIB(task->se_dev)->block_size) /
+ PAGE_SIZE);
+ lba = task->task_lba;
+ req->rd_offset = (do_div(lba,
+ (PAGE_SIZE / DEV_ATTRIB(task->se_dev)->block_size))) *
+ DEV_ATTRIB(task->se_dev)->block_size;
+ req->rd_size = task->task_size;
+
+ if (req->rd_offset)
+ ret = rd_DIRECT_with_offset(task, se_mem_list, se_mem_cnt,
+ task_offset_in);
+ else
+ ret = rd_DIRECT_without_offset(task, se_mem_list, se_mem_cnt,
+ task_offset_in);
+
+ if (ret < 0)
+ return ret;
+
+ if (CMD_TFO(cmd)->task_sg_chaining == 0)
+ return 0;
+ /*
+ * Currently prevent writers from multiple HW fabrics doing
+ * pci_map_sg() to RD_DR's internal scatterlist memory.
+ */
+ if (cmd->data_direction == DMA_TO_DEVICE) {
+ printk(KERN_ERR "DMA_TO_DEVICE not supported for"
+ " RAMDISK_DR with task_sg_chaining=1\n");
+ return -1;
+ }
+ /*
+ * Special case for if task_sg_chaining is enabled, then
+ * we setup struct se_task->task_sg[], as it will be used by
+ * transport_do_task_sg_chain() for creating chainged SGLs
+ * across multiple struct se_task->task_sg[].
+ */
+ if (!(transport_calc_sg_num(task,
+ list_entry(T_TASK(cmd)->t_mem_list->next,
+ struct se_mem, se_list),
+ task_offset)))
+ return -1;
+
+ return transport_map_mem_to_sg(task, se_mem_list, task->task_sg,
+ list_entry(T_TASK(cmd)->t_mem_list->next,
+ struct se_mem, se_list),
+ out_se_mem, se_mem_cnt, task_offset_in);
+}
+
+/* rd_DIRECT_do_task(): (Part of se_subsystem_api_t template)
+ *
+ *
+ */
+static int rd_DIRECT_do_task(struct se_task *task)
+{
+ /*
+ * At this point the locally allocated RD tables have been mapped
+ * to struct se_mem elements in rd_DIRECT_do_se_mem_map().
+ */
+ task->task_scsi_status = GOOD;
+ transport_complete_task(task, 1);
+
+ return PYX_TRANSPORT_SENT_TO_TRANSPORT;
+}
+
+/* rd_free_task(): (Part of se_subsystem_api_t template)
+ *
+ *
+ */
+static void rd_free_task(struct se_task *task)
+{
+ kfree(RD_REQ(task));
+}
+
+enum {
+ Opt_rd_pages, Opt_err
+};
+
+static match_table_t tokens = {
+ {Opt_rd_pages, "rd_pages=%d"},
+ {Opt_err, NULL}
+};
+
+static ssize_t rd_set_configfs_dev_params(
+ struct se_hba *hba,
+ struct se_subsystem_dev *se_dev,
+ const char *page,
+ ssize_t count)
+{
+ struct rd_dev *rd_dev = se_dev->se_dev_su_ptr;
+ char *orig, *ptr, *opts;
+ substring_t args[MAX_OPT_ARGS];
+ int ret = 0, arg, token;
+
+ opts = kstrdup(page, GFP_KERNEL);
+ if (!opts)
+ return -ENOMEM;
+
+ orig = opts;
+
+ while ((ptr = strsep(&opts, ",")) != NULL) {
+ if (!*ptr)
+ continue;
+
+ token = match_token(ptr, tokens, args);
+ switch (token) {
+ case Opt_rd_pages:
+ match_int(args, &arg);
+ rd_dev->rd_page_count = arg;
+ printk(KERN_INFO "RAMDISK: Referencing Page"
+ " Count: %u\n", rd_dev->rd_page_count);
+ rd_dev->rd_flags |= RDF_HAS_PAGE_COUNT;
+ break;
+ default:
+ break;
+ }
+ }
+
+ kfree(orig);
+ return (!ret) ? count : ret;
+}
+
+static ssize_t rd_check_configfs_dev_params(struct se_hba *hba, struct se_subsystem_dev *se_dev)
+{
+ struct rd_dev *rd_dev = se_dev->se_dev_su_ptr;
+
+ if (!(rd_dev->rd_flags & RDF_HAS_PAGE_COUNT)) {
+ printk(KERN_INFO "Missing rd_pages= parameter\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static ssize_t rd_show_configfs_dev_params(
+ struct se_hba *hba,
+ struct se_subsystem_dev *se_dev,
+ char *b)
+{
+ struct rd_dev *rd_dev = se_dev->se_dev_su_ptr;
+ ssize_t bl = sprintf(b, "TCM RamDisk ID: %u RamDisk Makeup: %s\n",
+ rd_dev->rd_dev_id, (rd_dev->rd_direct) ?
+ "rd_direct" : "rd_mcp");
+ bl += sprintf(b + bl, " PAGES/PAGE_SIZE: %u*%lu"
+ " SG_table_count: %u\n", rd_dev->rd_page_count,
+ PAGE_SIZE, rd_dev->sg_table_count);
+ return bl;
+}
+
+/* rd_get_cdb(): (Part of se_subsystem_api_t template)
+ *
+ *
+ */
+static unsigned char *rd_get_cdb(struct se_task *task)
+{
+ struct rd_request *req = RD_REQ(task);
+
+ return req->rd_scsi_cdb;
+}
+
+static u32 rd_get_device_rev(struct se_device *dev)
+{
+ return SCSI_SPC_2; /* Returns SPC-3 in Initiator Data */
+}
+
+static u32 rd_get_device_type(struct se_device *dev)
+{
+ return TYPE_DISK;
+}
+
+static sector_t rd_get_blocks(struct se_device *dev)
+{
+ struct rd_dev *rd_dev = dev->dev_ptr;
+ unsigned long long blocks_long = ((rd_dev->rd_page_count * PAGE_SIZE) /
+ DEV_ATTRIB(dev)->block_size) - 1;
+
+ return blocks_long;
+}
+
+static struct se_subsystem_api rd_dr_template = {
+ .name = "rd_dr",
+ .transport_type = TRANSPORT_PLUGIN_VHBA_VDEV,
+ .attach_hba = rd_attach_hba,
+ .detach_hba = rd_detach_hba,
+ .allocate_virtdevice = rd_DIRECT_allocate_virtdevice,
+ .create_virtdevice = rd_DIRECT_create_virtdevice,
+ .free_device = rd_free_device,
+ .alloc_task = rd_alloc_task,
+ .do_task = rd_DIRECT_do_task,
+ .free_task = rd_free_task,
+ .check_configfs_dev_params = rd_check_configfs_dev_params,
+ .set_configfs_dev_params = rd_set_configfs_dev_params,
+ .show_configfs_dev_params = rd_show_configfs_dev_params,
+ .get_cdb = rd_get_cdb,
+ .get_device_rev = rd_get_device_rev,
+ .get_device_type = rd_get_device_type,
+ .get_blocks = rd_get_blocks,
+ .do_se_mem_map = rd_DIRECT_do_se_mem_map,
+};
+
+static struct se_subsystem_api rd_mcp_template = {
+ .name = "rd_mcp",
+ .transport_type = TRANSPORT_PLUGIN_VHBA_VDEV,
+ .attach_hba = rd_attach_hba,
+ .detach_hba = rd_detach_hba,
+ .allocate_virtdevice = rd_MEMCPY_allocate_virtdevice,
+ .create_virtdevice = rd_MEMCPY_create_virtdevice,
+ .free_device = rd_free_device,
+ .alloc_task = rd_alloc_task,
+ .do_task = rd_MEMCPY_do_task,
+ .free_task = rd_free_task,
+ .check_configfs_dev_params = rd_check_configfs_dev_params,
+ .set_configfs_dev_params = rd_set_configfs_dev_params,
+ .show_configfs_dev_params = rd_show_configfs_dev_params,
+ .get_cdb = rd_get_cdb,
+ .get_device_rev = rd_get_device_rev,
+ .get_device_type = rd_get_device_type,
+ .get_blocks = rd_get_blocks,
+};
+
+int __init rd_module_init(void)
+{
+ int ret;
+
+ ret = transport_subsystem_register(&rd_dr_template);
+ if (ret < 0)
+ return ret;
+
+ ret = transport_subsystem_register(&rd_mcp_template);
+ if (ret < 0) {
+ transport_subsystem_release(&rd_dr_template);
+ return ret;
+ }
+
+ return 0;
+}
+
+void rd_module_exit(void)
+{
+ transport_subsystem_release(&rd_dr_template);
+ transport_subsystem_release(&rd_mcp_template);
+}
diff --git a/drivers/target/target_core_rd.h b/drivers/target/target_core_rd.h
new file mode 100644
index 0000000..13badfb
--- /dev/null
+++ b/drivers/target/target_core_rd.h
@@ -0,0 +1,73 @@
+#ifndef TARGET_CORE_RD_H
+#define TARGET_CORE_RD_H
+
+#define RD_HBA_VERSION "v4.0"
+#define RD_DR_VERSION "4.0"
+#define RD_MCP_VERSION "4.0"
+
+/* Largest piece of memory kmalloc can allocate */
+#define RD_MAX_ALLOCATION_SIZE 65536
+/* Maximum queuedepth for the Ramdisk HBA */
+#define RD_HBA_QUEUE_DEPTH 256
+#define RD_DEVICE_QUEUE_DEPTH 32
+#define RD_MAX_DEVICE_QUEUE_DEPTH 128
+#define RD_BLOCKSIZE 512
+#define RD_MAX_SECTORS 1024
+
+extern struct kmem_cache *se_mem_cache;
+
+/* Used in target_core_init_configfs() for virtual LUN 0 access */
+int __init rd_module_init(void);
+void rd_module_exit(void);
+
+#define RRF_EMULATE_CDB 0x01
+#define RRF_GOT_LBA 0x02
+
+struct rd_request {
+ struct se_task rd_task;
+
+ /* SCSI CDB from iSCSI Command PDU */
+ unsigned char rd_scsi_cdb[TCM_MAX_COMMAND_SIZE];
+ /* Offset from start of page */
+ u32 rd_offset;
+ /* Starting page in Ramdisk for request */
+ u32 rd_page;
+ /* Total number of pages needed for request */
+ u32 rd_page_count;
+ /* Scatterlist count */
+ u32 rd_size;
+ /* Ramdisk device */
+ struct rd_dev *rd_dev;
+} ____cacheline_aligned;
+
+struct rd_dev_sg_table {
+ u32 page_start_offset;
+ u32 page_end_offset;
+ u32 rd_sg_count;
+ struct scatterlist *sg_table;
+} ____cacheline_aligned;
+
+#define RDF_HAS_PAGE_COUNT 0x01
+
+struct rd_dev {
+ int rd_direct;
+ u32 rd_flags;
+ /* Unique Ramdisk Device ID in Ramdisk HBA */
+ u32 rd_dev_id;
+ /* Total page count for ramdisk device */
+ u32 rd_page_count;
+ /* Number of SG tables in sg_table_array */
+ u32 sg_table_count;
+ u32 rd_queue_depth;
+ /* Array of rd_dev_sg_table_t containing scatterlists */
+ struct rd_dev_sg_table *sg_table_array;
+ /* Ramdisk HBA device is connected to */
+ struct rd_host *rd_host;
+} ____cacheline_aligned;
+
+struct rd_host {
+ u32 rd_host_dev_id_count;
+ u32 rd_host_id; /* Unique Ramdisk Host ID */
+} ____cacheline_aligned;
+
+#endif /* TARGET_CORE_RD_H */
diff --git a/drivers/target/target_core_scdb.c b/drivers/target/target_core_scdb.c
new file mode 100644
index 0000000..dc6fed0
--- /dev/null
+++ b/drivers/target/target_core_scdb.c
@@ -0,0 +1,105 @@
+/*******************************************************************************
+ * Filename: target_core_scdb.c
+ *
+ * This file contains the generic target engine Split CDB related functions.
+ *
+ * Copyright (c) 2004-2005 PyX Technologies, Inc.
+ * Copyright (c) 2005, 2006, 2007 SBE, Inc.
+ * Copyright (c) 2007-2010 Rising Tide Systems
+ * Copyright (c) 2008-2010 Linux-iSCSI.org
+ *
+ * Nicholas A. Bellinger <nab@kernel.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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ ******************************************************************************/
+
+#include <linux/net.h>
+#include <linux/string.h>
+#include <scsi/scsi.h>
+#include <asm/unaligned.h>
+
+#include <target/target_core_base.h>
+#include <target/target_core_transport.h>
+
+#include "target_core_scdb.h"
+
+/* split_cdb_XX_6():
+ *
+ * 21-bit LBA w/ 8-bit SECTORS
+ */
+void split_cdb_XX_6(
+ unsigned long long lba,
+ u32 *sectors,
+ unsigned char *cdb)
+{
+ cdb[1] = (lba >> 16) & 0x1f;
+ cdb[2] = (lba >> 8) & 0xff;
+ cdb[3] = lba & 0xff;
+ cdb[4] = *sectors & 0xff;
+}
+
+/* split_cdb_XX_10():
+ *
+ * 32-bit LBA w/ 16-bit SECTORS
+ */
+void split_cdb_XX_10(
+ unsigned long long lba,
+ u32 *sectors,
+ unsigned char *cdb)
+{
+ put_unaligned_be32(lba, &cdb[2]);
+ put_unaligned_be16(*sectors, &cdb[7]);
+}
+
+/* split_cdb_XX_12():
+ *
+ * 32-bit LBA w/ 32-bit SECTORS
+ */
+void split_cdb_XX_12(
+ unsigned long long lba,
+ u32 *sectors,
+ unsigned char *cdb)
+{
+ put_unaligned_be32(lba, &cdb[2]);
+ put_unaligned_be32(*sectors, &cdb[6]);
+}
+
+/* split_cdb_XX_16():
+ *
+ * 64-bit LBA w/ 32-bit SECTORS
+ */
+void split_cdb_XX_16(
+ unsigned long long lba,
+ u32 *sectors,
+ unsigned char *cdb)
+{
+ put_unaligned_be64(lba, &cdb[2]);
+ put_unaligned_be32(*sectors, &cdb[10]);
+}
+
+/*
+ * split_cdb_XX_32():
+ *
+ * 64-bit LBA w/ 32-bit SECTORS such as READ_32, WRITE_32 and emulated XDWRITEREAD_32
+ */
+void split_cdb_XX_32(
+ unsigned long long lba,
+ u32 *sectors,
+ unsigned char *cdb)
+{
+ put_unaligned_be64(lba, &cdb[12]);
+ put_unaligned_be32(*sectors, &cdb[28]);
+}
diff --git a/drivers/target/target_core_scdb.h b/drivers/target/target_core_scdb.h
new file mode 100644
index 0000000..98cd1c0
--- /dev/null
+++ b/drivers/target/target_core_scdb.h
@@ -0,0 +1,10 @@
+#ifndef TARGET_CORE_SCDB_H
+#define TARGET_CORE_SCDB_H
+
+extern void split_cdb_XX_6(unsigned long long, u32 *, unsigned char *);
+extern void split_cdb_XX_10(unsigned long long, u32 *, unsigned char *);
+extern void split_cdb_XX_12(unsigned long long, u32 *, unsigned char *);
+extern void split_cdb_XX_16(unsigned long long, u32 *, unsigned char *);
+extern void split_cdb_XX_32(unsigned long long, u32 *, unsigned char *);
+
+#endif /* TARGET_CORE_SCDB_H */
diff --git a/drivers/target/target_core_tmr.c b/drivers/target/target_core_tmr.c
new file mode 100644
index 0000000..158cecb
--- /dev/null
+++ b/drivers/target/target_core_tmr.c
@@ -0,0 +1,404 @@
+/*******************************************************************************
+ * Filename: target_core_tmr.c
+ *
+ * This file contains SPC-3 task management infrastructure
+ *
+ * Copyright (c) 2009,2010 Rising Tide Systems
+ * Copyright (c) 2009,2010 Linux-iSCSI.org
+ *
+ * Nicholas A. Bellinger <nab@kernel.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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ ******************************************************************************/
+
+#include <linux/version.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/list.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+
+#include <target/target_core_base.h>
+#include <target/target_core_device.h>
+#include <target/target_core_tmr.h>
+#include <target/target_core_transport.h>
+#include <target/target_core_fabric_ops.h>
+#include <target/target_core_configfs.h>
+
+#include "target_core_alua.h"
+#include "target_core_pr.h"
+
+#define DEBUG_LUN_RESET
+#ifdef DEBUG_LUN_RESET
+#define DEBUG_LR(x...) printk(KERN_INFO x)
+#else
+#define DEBUG_LR(x...)
+#endif
+
+struct se_tmr_req *core_tmr_alloc_req(
+ struct se_cmd *se_cmd,
+ void *fabric_tmr_ptr,
+ u8 function)
+{
+ struct se_tmr_req *tmr;
+
+ tmr = kmem_cache_zalloc(se_tmr_req_cache, GFP_KERNEL);
+ if (!(tmr)) {
+ printk(KERN_ERR "Unable to allocate struct se_tmr_req\n");
+ return ERR_PTR(-ENOMEM);
+ }
+ tmr->task_cmd = se_cmd;
+ tmr->fabric_tmr_ptr = fabric_tmr_ptr;
+ tmr->function = function;
+ INIT_LIST_HEAD(&tmr->tmr_list);
+
+ return tmr;
+}
+EXPORT_SYMBOL(core_tmr_alloc_req);
+
+void core_tmr_release_req(
+ struct se_tmr_req *tmr)
+{
+ struct se_device *dev = tmr->tmr_dev;
+
+ spin_lock(&dev->se_tmr_lock);
+ list_del(&tmr->tmr_list);
+ kmem_cache_free(se_tmr_req_cache, tmr);
+ spin_unlock(&dev->se_tmr_lock);
+}
+
+static void core_tmr_handle_tas_abort(
+ struct se_node_acl *tmr_nacl,
+ struct se_cmd *cmd,
+ int tas,
+ int fe_count)
+{
+ if (!(fe_count)) {
+ transport_cmd_finish_abort(cmd, 1);
+ return;
+ }
+ /*
+ * TASK ABORTED status (TAS) bit support
+ */
+ if (((tmr_nacl != NULL) &&
+ (tmr_nacl == cmd->se_sess->se_node_acl)) || tas)
+ transport_send_task_abort(cmd);
+
+ transport_cmd_finish_abort(cmd, 0);
+}
+
+int core_tmr_lun_reset(
+ struct se_device *dev,
+ struct se_tmr_req *tmr,
+ struct list_head *preempt_and_abort_list,
+ struct se_cmd *prout_cmd)
+{
+ struct se_cmd *cmd;
+ struct se_queue_req *qr, *qr_tmp;
+ struct se_node_acl *tmr_nacl = NULL;
+ struct se_portal_group *tmr_tpg = NULL;
+ struct se_queue_obj *qobj = dev->dev_queue_obj;
+ struct se_tmr_req *tmr_p, *tmr_pp;
+ struct se_task *task, *task_tmp;
+ unsigned long flags;
+ int fe_count, state, tas;
+ /*
+ * TASK_ABORTED status bit, this is configurable via ConfigFS
+ * struct se_device attributes. spc4r17 section 7.4.6 Control mode page
+ *
+ * A task aborted status (TAS) bit set to zero specifies that aborted
+ * tasks shall be terminated by the device server without any response
+ * to the application client. A TAS bit set to one specifies that tasks
+ * aborted by the actions of an I_T nexus other than the I_T nexus on
+ * which the command was received shall be completed with TASK ABORTED
+ * status (see SAM-4).
+ */
+ tas = DEV_ATTRIB(dev)->emulate_tas;
+ /*
+ * Determine if this se_tmr is coming from a $FABRIC_MOD
+ * or struct se_device passthrough..
+ */
+ if (tmr && tmr->task_cmd && tmr->task_cmd->se_sess) {
+ tmr_nacl = tmr->task_cmd->se_sess->se_node_acl;
+ tmr_tpg = tmr->task_cmd->se_sess->se_tpg;
+ if (tmr_nacl && tmr_tpg) {
+ DEBUG_LR("LUN_RESET: TMR caller fabric: %s"
+ " initiator port %s\n",
+ TPG_TFO(tmr_tpg)->get_fabric_name(),
+ tmr_nacl->initiatorname);
+ }
+ }
+ DEBUG_LR("LUN_RESET: %s starting for [%s], tas: %d\n",
+ (preempt_and_abort_list) ? "Preempt" : "TMR",
+ TRANSPORT(dev)->name, tas);
+ /*
+ * Release all pending and outgoing TMRs aside from the received
+ * LUN_RESET tmr..
+ */
+ spin_lock(&dev->se_tmr_lock);
+ list_for_each_entry_safe(tmr_p, tmr_pp, &dev->dev_tmr_list, tmr_list) {
+ /*
+ * Allow the received TMR to return with FUNCTION_COMPLETE.
+ */
+ if (tmr && (tmr_p == tmr))
+ continue;
+
+ cmd = tmr_p->task_cmd;
+ if (!(cmd)) {
+ printk(KERN_ERR "Unable to locate struct se_cmd for TMR\n");
+ continue;
+ }
+ /*
+ * If this function was called with a valid pr_res_key
+ * parameter (eg: for PROUT PREEMPT_AND_ABORT service action
+ * skip non regisration key matching TMRs.
+ */
+ if ((preempt_and_abort_list != NULL) &&
+ (core_scsi3_check_cdb_abort_and_preempt(
+ preempt_and_abort_list, cmd) != 0))
+ continue;
+ spin_unlock(&dev->se_tmr_lock);
+
+ spin_lock_irqsave(&T_TASK(cmd)->t_state_lock, flags);
+ if (!(atomic_read(&T_TASK(cmd)->t_transport_active))) {
+ spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags);
+ spin_lock(&dev->se_tmr_lock);
+ continue;
+ }
+ if (cmd->t_state == TRANSPORT_ISTATE_PROCESSING) {
+ spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags);
+ spin_lock(&dev->se_tmr_lock);
+ continue;
+ }
+ DEBUG_LR("LUN_RESET: %s releasing TMR %p Function: 0x%02x,"
+ " Response: 0x%02x, t_state: %d\n",
+ (preempt_and_abort_list) ? "Preempt" : "", tmr_p,
+ tmr_p->function, tmr_p->response, cmd->t_state);
+ spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags);
+
+ transport_cmd_finish_abort_tmr(cmd);
+ spin_lock(&dev->se_tmr_lock);
+ }
+ spin_unlock(&dev->se_tmr_lock);
+ /*
+ * Complete outstanding struct se_task CDBs with TASK_ABORTED SAM status.
+ * This is following sam4r17, section 5.6 Aborting commands, Table 38
+ * for TMR LUN_RESET:
+ *
+ * a) "Yes" indicates that each command that is aborted on an I_T nexus
+ * other than the one that caused the SCSI device condition is
+ * completed with TASK ABORTED status, if the TAS bit is set to one in
+ * the Control mode page (see SPC-4). "No" indicates that no status is
+ * returned for aborted commands.
+ *
+ * d) If the logical unit reset is caused by a particular I_T nexus
+ * (e.g., by a LOGICAL UNIT RESET task management function), then "yes"
+ * (TASK_ABORTED status) applies.
+ *
+ * Otherwise (e.g., if triggered by a hard reset), "no"
+ * (no TASK_ABORTED SAM status) applies.
+ *
+ * Note that this seems to be independent of TAS (Task Aborted Status)
+ * in the Control Mode Page.
+ */
+ spin_lock_irqsave(&dev->execute_task_lock, flags);
+ list_for_each_entry_safe(task, task_tmp, &dev->state_task_list,
+ t_state_list) {
+ if (!(TASK_CMD(task))) {
+ printk(KERN_ERR "TASK_CMD(task) is NULL!\n");
+ continue;
+ }
+ cmd = TASK_CMD(task);
+
+ if (!T_TASK(cmd)) {
+ printk(KERN_ERR "T_TASK(cmd) is NULL for task: %p cmd:"
+ " %p ITT: 0x%08x\n", task, cmd,
+ CMD_TFO(cmd)->get_task_tag(cmd));
+ continue;
+ }
+ /*
+ * For PREEMPT_AND_ABORT usage, only process commands
+ * with a matching reservation key.
+ */
+ if ((preempt_and_abort_list != NULL) &&
+ (core_scsi3_check_cdb_abort_and_preempt(
+ preempt_and_abort_list, cmd) != 0))
+ continue;
+ /*
+ * Not aborting PROUT PREEMPT_AND_ABORT CDB..
+ */
+ if (prout_cmd == cmd)
+ continue;
+
+ list_del(&task->t_state_list);
+ atomic_set(&task->task_state_active, 0);
+ spin_unlock_irqrestore(&dev->execute_task_lock, flags);
+
+ spin_lock_irqsave(&T_TASK(cmd)->t_state_lock, flags);
+ DEBUG_LR("LUN_RESET: %s cmd: %p task: %p"
+ " ITT/CmdSN: 0x%08x/0x%08x, i_state: %d, t_state/"
+ "def_t_state: %d/%d cdb: 0x%02x\n",
+ (preempt_and_abort_list) ? "Preempt" : "", cmd, task,
+ CMD_TFO(cmd)->get_task_tag(cmd), 0,
+ CMD_TFO(cmd)->get_cmd_state(cmd), cmd->t_state,
+ cmd->deferred_t_state, T_TASK(cmd)->t_task_cdb[0]);
+ DEBUG_LR("LUN_RESET: ITT[0x%08x] - pr_res_key: 0x%016Lx"
+ " t_task_cdbs: %d t_task_cdbs_left: %d"
+ " t_task_cdbs_sent: %d -- t_transport_active: %d"
+ " t_transport_stop: %d t_transport_sent: %d\n",
+ CMD_TFO(cmd)->get_task_tag(cmd), cmd->pr_res_key,
+ T_TASK(cmd)->t_task_cdbs,
+ atomic_read(&T_TASK(cmd)->t_task_cdbs_left),
+ atomic_read(&T_TASK(cmd)->t_task_cdbs_sent),
+ atomic_read(&T_TASK(cmd)->t_transport_active),
+ atomic_read(&T_TASK(cmd)->t_transport_stop),
+ atomic_read(&T_TASK(cmd)->t_transport_sent));
+
+ if (atomic_read(&task->task_active)) {
+ atomic_set(&task->task_stop, 1);
+ spin_unlock_irqrestore(
+ &T_TASK(cmd)->t_state_lock, flags);
+
+ DEBUG_LR("LUN_RESET: Waiting for task: %p to shutdown"
+ " for dev: %p\n", task, dev);
+ wait_for_completion(&task->task_stop_comp);
+ DEBUG_LR("LUN_RESET Completed task: %p shutdown for"
+ " dev: %p\n", task, dev);
+ spin_lock_irqsave(&T_TASK(cmd)->t_state_lock, flags);
+ atomic_dec(&T_TASK(cmd)->t_task_cdbs_left);
+
+ atomic_set(&task->task_active, 0);
+ atomic_set(&task->task_stop, 0);
+ }
+ __transport_stop_task_timer(task, &flags);
+
+ if (!(atomic_dec_and_test(&T_TASK(cmd)->t_task_cdbs_ex_left))) {
+ spin_unlock_irqrestore(
+ &T_TASK(cmd)->t_state_lock, flags);
+ DEBUG_LR("LUN_RESET: Skipping task: %p, dev: %p for"
+ " t_task_cdbs_ex_left: %d\n", task, dev,
+ atomic_read(&T_TASK(cmd)->t_task_cdbs_ex_left));
+
+ spin_lock_irqsave(&dev->execute_task_lock, flags);
+ continue;
+ }
+ fe_count = atomic_read(&T_TASK(cmd)->t_fe_count);
+
+ if (atomic_read(&T_TASK(cmd)->t_transport_active)) {
+ DEBUG_LR("LUN_RESET: got t_transport_active = 1 for"
+ " task: %p, t_fe_count: %d dev: %p\n", task,
+ fe_count, dev);
+ spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock,
+ flags);
+ core_tmr_handle_tas_abort(tmr_nacl, cmd, tas, fe_count);
+
+ spin_lock_irqsave(&dev->execute_task_lock, flags);
+ continue;
+ }
+ DEBUG_LR("LUN_RESET: Got t_transport_active = 0 for task: %p,"
+ " t_fe_count: %d dev: %p\n", task, fe_count, dev);
+ spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags);
+ core_tmr_handle_tas_abort(tmr_nacl, cmd, tas, fe_count);
+
+ spin_lock_irqsave(&dev->execute_task_lock, flags);
+ }
+ spin_unlock_irqrestore(&dev->execute_task_lock, flags);
+ /*
+ * Release all commands remaining in the struct se_device cmd queue.
+ *
+ * This follows the same logic as above for the struct se_device
+ * struct se_task state list, where commands are returned with
+ * TASK_ABORTED status, if there is an outstanding $FABRIC_MOD
+ * reference, otherwise the struct se_cmd is released.
+ */
+ spin_lock_irqsave(&qobj->cmd_queue_lock, flags);
+ list_for_each_entry_safe(qr, qr_tmp, &qobj->qobj_list, qr_list) {
+ cmd = (struct se_cmd *)qr->cmd;
+ if (!(cmd)) {
+ /*
+ * Skip these for non PREEMPT_AND_ABORT usage..
+ */
+ if (preempt_and_abort_list != NULL)
+ continue;
+
+ atomic_dec(&qobj->queue_cnt);
+ list_del(&qr->qr_list);
+ kfree(qr);
+ continue;
+ }
+ /*
+ * For PREEMPT_AND_ABORT usage, only process commands
+ * with a matching reservation key.
+ */
+ if ((preempt_and_abort_list != NULL) &&
+ (core_scsi3_check_cdb_abort_and_preempt(
+ preempt_and_abort_list, cmd) != 0))
+ continue;
+ /*
+ * Not aborting PROUT PREEMPT_AND_ABORT CDB..
+ */
+ if (prout_cmd == cmd)
+ continue;
+
+ atomic_dec(&T_TASK(cmd)->t_transport_queue_active);
+ atomic_dec(&qobj->queue_cnt);
+ list_del(&qr->qr_list);
+ spin_unlock_irqrestore(&qobj->cmd_queue_lock, flags);
+
+ state = qr->state;
+ kfree(qr);
+
+ DEBUG_LR("LUN_RESET: %s from Device Queue: cmd: %p t_state:"
+ " %d t_fe_count: %d\n", (preempt_and_abort_list) ?
+ "Preempt" : "", cmd, state,
+ atomic_read(&T_TASK(cmd)->t_fe_count));
+ /*
+ * Signal that the command has failed via cmd->se_cmd_flags,
+ * and call TFO->new_cmd_failure() to wakeup any fabric
+ * dependent code used to wait for unsolicited data out
+ * allocation to complete. The fabric module is expected
+ * to dump any remaining unsolicited data out for the aborted
+ * command at this point.
+ */
+ transport_new_cmd_failure(cmd);
+
+ core_tmr_handle_tas_abort(tmr_nacl, cmd, tas,
+ atomic_read(&T_TASK(cmd)->t_fe_count));
+ spin_lock_irqsave(&qobj->cmd_queue_lock, flags);
+ }
+ spin_unlock_irqrestore(&qobj->cmd_queue_lock, flags);
+ /*
+ * Clear any legacy SPC-2 reservation when called during
+ * LOGICAL UNIT RESET
+ */
+ if (!(preempt_and_abort_list) &&
+ (dev->dev_flags & DF_SPC2_RESERVATIONS)) {
+ spin_lock(&dev->dev_reservation_lock);
+ dev->dev_reserved_node_acl = NULL;
+ dev->dev_flags &= ~DF_SPC2_RESERVATIONS;
+ spin_unlock(&dev->dev_reservation_lock);
+ printk(KERN_INFO "LUN_RESET: SCSI-2 Released reservation\n");
+ }
+
+ spin_lock(&dev->stats_lock);
+ dev->num_resets++;
+ spin_unlock(&dev->stats_lock);
+
+ DEBUG_LR("LUN_RESET: %s for [%s] Complete\n",
+ (preempt_and_abort_list) ? "Preempt" : "TMR",
+ TRANSPORT(dev)->name);
+ return 0;
+}
diff --git a/drivers/target/target_core_tpg.c b/drivers/target/target_core_tpg.c
new file mode 100644
index 0000000..abfa81a
--- /dev/null
+++ b/drivers/target/target_core_tpg.c
@@ -0,0 +1,826 @@
+/*******************************************************************************
+ * Filename: target_core_tpg.c
+ *
+ * This file contains generic Target Portal Group related functions.
+ *
+ * Copyright (c) 2002, 2003, 2004, 2005 PyX Technologies, Inc.
+ * Copyright (c) 2005, 2006, 2007 SBE, Inc.
+ * Copyright (c) 2007-2010 Rising Tide Systems
+ * Copyright (c) 2008-2010 Linux-iSCSI.org
+ *
+ * Nicholas A. Bellinger <nab@kernel.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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ ******************************************************************************/
+
+#include <linux/net.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/smp_lock.h>
+#include <linux/in.h>
+#include <net/sock.h>
+#include <net/tcp.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+
+#include <target/target_core_base.h>
+#include <target/target_core_device.h>
+#include <target/target_core_tpg.h>
+#include <target/target_core_transport.h>
+#include <target/target_core_fabric_ops.h>
+
+#include "target_core_hba.h"
+
+/* core_clear_initiator_node_from_tpg():
+ *
+ *
+ */
+static void core_clear_initiator_node_from_tpg(
+ struct se_node_acl *nacl,
+ struct se_portal_group *tpg)
+{
+ int i;
+ struct se_dev_entry *deve;
+ struct se_lun *lun;
+ struct se_lun_acl *acl, *acl_tmp;
+
+ spin_lock_irq(&nacl->device_list_lock);
+ for (i = 0; i < TRANSPORT_MAX_LUNS_PER_TPG; i++) {
+ deve = &nacl->device_list[i];
+
+ if (!(deve->lun_flags & TRANSPORT_LUNFLAGS_INITIATOR_ACCESS))
+ continue;
+
+ if (!deve->se_lun) {
+ printk(KERN_ERR "%s device entries device pointer is"
+ " NULL, but Initiator has access.\n",
+ TPG_TFO(tpg)->get_fabric_name());
+ continue;
+ }
+
+ lun = deve->se_lun;
+ spin_unlock_irq(&nacl->device_list_lock);
+ core_update_device_list_for_node(lun, NULL, deve->mapped_lun,
+ TRANSPORT_LUNFLAGS_NO_ACCESS, nacl, tpg, 0);
+
+ spin_lock(&lun->lun_acl_lock);
+ list_for_each_entry_safe(acl, acl_tmp,
+ &lun->lun_acl_list, lacl_list) {
+ if (!(strcmp(acl->initiatorname,
+ nacl->initiatorname)) &&
+ (acl->mapped_lun == deve->mapped_lun))
+ break;
+ }
+
+ if (!acl) {
+ printk(KERN_ERR "Unable to locate struct se_lun_acl for %s,"
+ " mapped_lun: %u\n", nacl->initiatorname,
+ deve->mapped_lun);
+ spin_unlock(&lun->lun_acl_lock);
+ spin_lock_irq(&nacl->device_list_lock);
+ continue;
+ }
+
+ list_del(&acl->lacl_list);
+ spin_unlock(&lun->lun_acl_lock);
+
+ spin_lock_irq(&nacl->device_list_lock);
+ kfree(acl);
+ }
+ spin_unlock_irq(&nacl->device_list_lock);
+}
+
+/* __core_tpg_get_initiator_node_acl():
+ *
+ * spin_lock_bh(&tpg->acl_node_lock); must be held when calling
+ */
+struct se_node_acl *__core_tpg_get_initiator_node_acl(
+ struct se_portal_group *tpg,
+ const char *initiatorname)
+{
+ struct se_node_acl *acl;
+
+ list_for_each_entry(acl, &tpg->acl_node_list, acl_list) {
+ if (!(strcmp(acl->initiatorname, initiatorname)))
+ return acl;
+ }
+
+ return NULL;
+}
+
+/* core_tpg_get_initiator_node_acl():
+ *
+ *
+ */
+struct se_node_acl *core_tpg_get_initiator_node_acl(
+ struct se_portal_group *tpg,
+ unsigned char *initiatorname)
+{
+ struct se_node_acl *acl;
+
+ spin_lock_bh(&tpg->acl_node_lock);
+ list_for_each_entry(acl, &tpg->acl_node_list, acl_list) {
+ if (!(strcmp(acl->initiatorname, initiatorname)) &&
+ (!(acl->dynamic_node_acl))) {
+ spin_unlock_bh(&tpg->acl_node_lock);
+ return acl;
+ }
+ }
+ spin_unlock_bh(&tpg->acl_node_lock);
+
+ return NULL;
+}
+
+/* core_tpg_add_node_to_devs():
+ *
+ *
+ */
+void core_tpg_add_node_to_devs(
+ struct se_node_acl *acl,
+ struct se_portal_group *tpg)
+{
+ int i = 0;
+ u32 lun_access = 0;
+ struct se_lun *lun;
+ struct se_device *dev;
+
+ spin_lock(&tpg->tpg_lun_lock);
+ for (i = 0; i < TRANSPORT_MAX_LUNS_PER_TPG; i++) {
+ lun = &tpg->tpg_lun_list[i];
+ if (lun->lun_status != TRANSPORT_LUN_STATUS_ACTIVE)
+ continue;
+
+ spin_unlock(&tpg->tpg_lun_lock);
+
+ dev = lun->lun_se_dev;
+ /*
+ * By default in LIO-Target $FABRIC_MOD,
+ * demo_mode_write_protect is ON, or READ_ONLY;
+ */
+ if (!(TPG_TFO(tpg)->tpg_check_demo_mode_write_protect(tpg))) {
+ if (dev->dev_flags & DF_READ_ONLY)
+ lun_access = TRANSPORT_LUNFLAGS_READ_ONLY;
+ else
+ lun_access = TRANSPORT_LUNFLAGS_READ_WRITE;
+ } else {
+ /*
+ * Allow only optical drives to issue R/W in default RO
+ * demo mode.
+ */
+ if (TRANSPORT(dev)->get_device_type(dev) == TYPE_DISK)
+ lun_access = TRANSPORT_LUNFLAGS_READ_ONLY;
+ else
+ lun_access = TRANSPORT_LUNFLAGS_READ_WRITE;
+ }
+
+ printk(KERN_INFO "TARGET_CORE[%s]->TPG[%u]_LUN[%u] - Adding %s"
+ " access for LUN in Demo Mode\n",
+ TPG_TFO(tpg)->get_fabric_name(),
+ TPG_TFO(tpg)->tpg_get_tag(tpg), lun->unpacked_lun,
+ (lun_access == TRANSPORT_LUNFLAGS_READ_WRITE) ?
+ "READ-WRITE" : "READ-ONLY");
+
+ core_update_device_list_for_node(lun, NULL, lun->unpacked_lun,
+ lun_access, acl, tpg, 1);
+ spin_lock(&tpg->tpg_lun_lock);
+ }
+ spin_unlock(&tpg->tpg_lun_lock);
+}
+
+/* core_set_queue_depth_for_node():
+ *
+ *
+ */
+static int core_set_queue_depth_for_node(
+ struct se_portal_group *tpg,
+ struct se_node_acl *acl)
+{
+ if (!acl->queue_depth) {
+ printk(KERN_ERR "Queue depth for %s Initiator Node: %s is 0,"
+ "defaulting to 1.\n", TPG_TFO(tpg)->get_fabric_name(),
+ acl->initiatorname);
+ acl->queue_depth = 1;
+ }
+
+ return 0;
+}
+
+/* core_create_device_list_for_node():
+ *
+ *
+ */
+static int core_create_device_list_for_node(struct se_node_acl *nacl)
+{
+ struct se_dev_entry *deve;
+ int i;
+
+ nacl->device_list = kzalloc(sizeof(struct se_dev_entry) *
+ TRANSPORT_MAX_LUNS_PER_TPG, GFP_KERNEL);
+ if (!(nacl->device_list)) {
+ printk(KERN_ERR "Unable to allocate memory for"
+ " struct se_node_acl->device_list\n");
+ return -1;
+ }
+ for (i = 0; i < TRANSPORT_MAX_LUNS_PER_TPG; i++) {
+ deve = &nacl->device_list[i];
+
+ atomic_set(&deve->ua_count, 0);
+ atomic_set(&deve->pr_ref_count, 0);
+ spin_lock_init(&deve->ua_lock);
+ INIT_LIST_HEAD(&deve->alua_port_list);
+ INIT_LIST_HEAD(&deve->ua_list);
+ }
+
+ return 0;
+}
+
+/* core_tpg_check_initiator_node_acl()
+ *
+ *
+ */
+struct se_node_acl *core_tpg_check_initiator_node_acl(
+ struct se_portal_group *tpg,
+ unsigned char *initiatorname)
+{
+ struct se_node_acl *acl;
+
+ acl = core_tpg_get_initiator_node_acl(tpg, initiatorname);
+ if ((acl))
+ return acl;
+
+ if (!(TPG_TFO(tpg)->tpg_check_demo_mode(tpg)))
+ return NULL;
+
+ acl = TPG_TFO(tpg)->tpg_alloc_fabric_acl(tpg);
+ if (!(acl))
+ return NULL;
+
+ INIT_LIST_HEAD(&acl->acl_list);
+ INIT_LIST_HEAD(&acl->acl_sess_list);
+ spin_lock_init(&acl->device_list_lock);
+ spin_lock_init(&acl->nacl_sess_lock);
+ atomic_set(&acl->acl_pr_ref_count, 0);
+ atomic_set(&acl->mib_ref_count, 0);
+ acl->queue_depth = TPG_TFO(tpg)->tpg_get_default_depth(tpg);
+ snprintf(acl->initiatorname, TRANSPORT_IQN_LEN, "%s", initiatorname);
+ acl->se_tpg = tpg;
+ acl->acl_index = scsi_get_new_index(SCSI_AUTH_INTR_INDEX);
+ spin_lock_init(&acl->stats_lock);
+ acl->dynamic_node_acl = 1;
+
+ TPG_TFO(tpg)->set_default_node_attributes(acl);
+
+ if (core_create_device_list_for_node(acl) < 0) {
+ TPG_TFO(tpg)->tpg_release_fabric_acl(tpg, acl);
+ return NULL;
+ }
+
+ if (core_set_queue_depth_for_node(tpg, acl) < 0) {
+ core_free_device_list_for_node(acl, tpg);
+ TPG_TFO(tpg)->tpg_release_fabric_acl(tpg, acl);
+ return NULL;
+ }
+
+ core_tpg_add_node_to_devs(acl, tpg);
+
+ spin_lock_bh(&tpg->acl_node_lock);
+ list_add_tail(&acl->acl_list, &tpg->acl_node_list);
+ tpg->num_node_acls++;
+ spin_unlock_bh(&tpg->acl_node_lock);
+
+ printk("%s_TPG[%u] - Added DYNAMIC ACL with TCQ Depth: %d for %s"
+ " Initiator Node: %s\n", TPG_TFO(tpg)->get_fabric_name(),
+ TPG_TFO(tpg)->tpg_get_tag(tpg), acl->queue_depth,
+ TPG_TFO(tpg)->get_fabric_name(), initiatorname);
+
+ return acl;
+}
+EXPORT_SYMBOL(core_tpg_check_initiator_node_acl);
+
+void core_tpg_wait_for_nacl_pr_ref(struct se_node_acl *nacl)
+{
+ while (atomic_read(&nacl->acl_pr_ref_count) != 0)
+ cpu_relax();
+}
+
+void core_tpg_wait_for_mib_ref(struct se_node_acl *nacl)
+{
+ while (atomic_read(&nacl->mib_ref_count) != 0)
+ cpu_relax();
+}
+
+void core_tpg_clear_object_luns(struct se_portal_group *tpg)
+{
+ int i, ret;
+ struct se_lun *lun;
+
+ spin_lock(&tpg->tpg_lun_lock);
+ for (i = 0; i < TRANSPORT_MAX_LUNS_PER_TPG; i++) {
+ lun = &tpg->tpg_lun_list[i];
+
+ if ((lun->lun_status != TRANSPORT_LUN_STATUS_ACTIVE) ||
+ (lun->lun_se_dev == NULL))
+ continue;
+
+ spin_unlock(&tpg->tpg_lun_lock);
+ ret = core_dev_del_lun(tpg, lun->unpacked_lun);
+ spin_lock(&tpg->tpg_lun_lock);
+ }
+ spin_unlock(&tpg->tpg_lun_lock);
+}
+EXPORT_SYMBOL(core_tpg_clear_object_luns);
+
+/* core_tpg_add_initiator_node_acl():
+ *
+ *
+ */
+struct se_node_acl *core_tpg_add_initiator_node_acl(
+ struct se_portal_group *tpg,
+ struct se_node_acl *se_nacl,
+ const char *initiatorname,
+ u32 queue_depth)
+{
+ struct se_node_acl *acl = NULL;
+
+ spin_lock_bh(&tpg->acl_node_lock);
+ acl = __core_tpg_get_initiator_node_acl(tpg, initiatorname);
+ if ((acl)) {
+ if (acl->dynamic_node_acl) {
+ acl->dynamic_node_acl = 0;
+ printk(KERN_INFO "%s_TPG[%u] - Replacing dynamic ACL"
+ " for %s\n", TPG_TFO(tpg)->get_fabric_name(),
+ TPG_TFO(tpg)->tpg_get_tag(tpg), initiatorname);
+ spin_unlock_bh(&tpg->acl_node_lock);
+ /*
+ * Release the locally allocated struct se_node_acl
+ * because * core_tpg_add_initiator_node_acl() returned
+ * a pointer to an existing demo mode node ACL.
+ */
+ if (se_nacl)
+ TPG_TFO(tpg)->tpg_release_fabric_acl(tpg,
+ se_nacl);
+ goto done;
+ }
+
+ printk(KERN_ERR "ACL entry for %s Initiator"
+ " Node %s already exists for TPG %u, ignoring"
+ " request.\n", TPG_TFO(tpg)->get_fabric_name(),
+ initiatorname, TPG_TFO(tpg)->tpg_get_tag(tpg));
+ spin_unlock_bh(&tpg->acl_node_lock);
+ return ERR_PTR(-EEXIST);
+ }
+ spin_unlock_bh(&tpg->acl_node_lock);
+
+ if (!(se_nacl)) {
+ printk("struct se_node_acl pointer is NULL\n");
+ return ERR_PTR(-EINVAL);
+ }
+ /*
+ * For v4.x logic the se_node_acl_s is hanging off a fabric
+ * dependent structure allocated via
+ * struct target_core_fabric_ops->fabric_make_nodeacl()
+ */
+ acl = se_nacl;
+
+ INIT_LIST_HEAD(&acl->acl_list);
+ INIT_LIST_HEAD(&acl->acl_sess_list);
+ spin_lock_init(&acl->device_list_lock);
+ spin_lock_init(&acl->nacl_sess_lock);
+ atomic_set(&acl->acl_pr_ref_count, 0);
+ acl->queue_depth = queue_depth;
+ snprintf(acl->initiatorname, TRANSPORT_IQN_LEN, "%s", initiatorname);
+ acl->se_tpg = tpg;
+ acl->acl_index = scsi_get_new_index(SCSI_AUTH_INTR_INDEX);
+ spin_lock_init(&acl->stats_lock);
+
+ TPG_TFO(tpg)->set_default_node_attributes(acl);
+
+ if (core_create_device_list_for_node(acl) < 0) {
+ TPG_TFO(tpg)->tpg_release_fabric_acl(tpg, acl);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ if (core_set_queue_depth_for_node(tpg, acl) < 0) {
+ core_free_device_list_for_node(acl, tpg);
+ TPG_TFO(tpg)->tpg_release_fabric_acl(tpg, acl);
+ return ERR_PTR(-EINVAL);
+ }
+
+ spin_lock_bh(&tpg->acl_node_lock);
+ list_add_tail(&acl->acl_list, &tpg->acl_node_list);
+ tpg->num_node_acls++;
+ spin_unlock_bh(&tpg->acl_node_lock);
+
+done:
+ printk(KERN_INFO "%s_TPG[%hu] - Added ACL with TCQ Depth: %d for %s"
+ " Initiator Node: %s\n", TPG_TFO(tpg)->get_fabric_name(),
+ TPG_TFO(tpg)->tpg_get_tag(tpg), acl->queue_depth,
+ TPG_TFO(tpg)->get_fabric_name(), initiatorname);
+
+ return acl;
+}
+EXPORT_SYMBOL(core_tpg_add_initiator_node_acl);
+
+/* core_tpg_del_initiator_node_acl():
+ *
+ *
+ */
+int core_tpg_del_initiator_node_acl(
+ struct se_portal_group *tpg,
+ struct se_node_acl *acl,
+ int force)
+{
+ struct se_session *sess, *sess_tmp;
+ int dynamic_acl = 0;
+
+ spin_lock_bh(&tpg->acl_node_lock);
+ if (acl->dynamic_node_acl) {
+ acl->dynamic_node_acl = 0;
+ dynamic_acl = 1;
+ }
+ list_del(&acl->acl_list);
+ tpg->num_node_acls--;
+ spin_unlock_bh(&tpg->acl_node_lock);
+
+ spin_lock_bh(&tpg->session_lock);
+ list_for_each_entry_safe(sess, sess_tmp,
+ &tpg->tpg_sess_list, sess_list) {
+ if (sess->se_node_acl != acl)
+ continue;
+ /*
+ * Determine if the session needs to be closed by our context.
+ */
+ if (!(TPG_TFO(tpg)->shutdown_session(sess)))
+ continue;
+
+ spin_unlock_bh(&tpg->session_lock);
+ /*
+ * If the $FABRIC_MOD session for the Initiator Node ACL exists,
+ * forcefully shutdown the $FABRIC_MOD session/nexus.
+ */
+ TPG_TFO(tpg)->close_session(sess);
+
+ spin_lock_bh(&tpg->session_lock);
+ }
+ spin_unlock_bh(&tpg->session_lock);
+
+ core_tpg_wait_for_nacl_pr_ref(acl);
+ core_tpg_wait_for_mib_ref(acl);
+ core_clear_initiator_node_from_tpg(acl, tpg);
+ core_free_device_list_for_node(acl, tpg);
+
+ printk(KERN_INFO "%s_TPG[%hu] - Deleted ACL with TCQ Depth: %d for %s"
+ " Initiator Node: %s\n", TPG_TFO(tpg)->get_fabric_name(),
+ TPG_TFO(tpg)->tpg_get_tag(tpg), acl->queue_depth,
+ TPG_TFO(tpg)->get_fabric_name(), acl->initiatorname);
+
+ return 0;
+}
+EXPORT_SYMBOL(core_tpg_del_initiator_node_acl);
+
+/* core_tpg_set_initiator_node_queue_depth():
+ *
+ *
+ */
+int core_tpg_set_initiator_node_queue_depth(
+ struct se_portal_group *tpg,
+ unsigned char *initiatorname,
+ u32 queue_depth,
+ int force)
+{
+ struct se_session *sess, *init_sess = NULL;
+ struct se_node_acl *acl;
+ int dynamic_acl = 0;
+
+ spin_lock_bh(&tpg->acl_node_lock);
+ acl = __core_tpg_get_initiator_node_acl(tpg, initiatorname);
+ if (!(acl)) {
+ printk(KERN_ERR "Access Control List entry for %s Initiator"
+ " Node %s does not exists for TPG %hu, ignoring"
+ " request.\n", TPG_TFO(tpg)->get_fabric_name(),
+ initiatorname, TPG_TFO(tpg)->tpg_get_tag(tpg));
+ spin_unlock_bh(&tpg->acl_node_lock);
+ return -ENODEV;
+ }
+ if (acl->dynamic_node_acl) {
+ acl->dynamic_node_acl = 0;
+ dynamic_acl = 1;
+ }
+ spin_unlock_bh(&tpg->acl_node_lock);
+
+ spin_lock_bh(&tpg->session_lock);
+ list_for_each_entry(sess, &tpg->tpg_sess_list, sess_list) {
+ if (sess->se_node_acl != acl)
+ continue;
+
+ if (!force) {
+ printk(KERN_ERR "Unable to change queue depth for %s"
+ " Initiator Node: %s while session is"
+ " operational. To forcefully change the queue"
+ " depth and force session reinstatement"
+ " use the \"force=1\" parameter.\n",
+ TPG_TFO(tpg)->get_fabric_name(), initiatorname);
+ spin_unlock_bh(&tpg->session_lock);
+
+ spin_lock_bh(&tpg->acl_node_lock);
+ if (dynamic_acl)
+ acl->dynamic_node_acl = 1;
+ spin_unlock_bh(&tpg->acl_node_lock);
+ return -EEXIST;
+ }
+ /*
+ * Determine if the session needs to be closed by our context.
+ */
+ if (!(TPG_TFO(tpg)->shutdown_session(sess)))
+ continue;
+
+ init_sess = sess;
+ break;
+ }
+
+ /*
+ * User has requested to change the queue depth for a Initiator Node.
+ * Change the value in the Node's struct se_node_acl, and call
+ * core_set_queue_depth_for_node() to add the requested queue depth.
+ *
+ * Finally call TPG_TFO(tpg)->close_session() to force session
+ * reinstatement to occur if there is an active session for the
+ * $FABRIC_MOD Initiator Node in question.
+ */
+ acl->queue_depth = queue_depth;
+
+ if (core_set_queue_depth_for_node(tpg, acl) < 0) {
+ spin_unlock_bh(&tpg->session_lock);
+ /*
+ * Force session reinstatement if
+ * core_set_queue_depth_for_node() failed, because we assume
+ * the $FABRIC_MOD has already the set session reinstatement
+ * bit from TPG_TFO(tpg)->shutdown_session() called above.
+ */
+ if (init_sess)
+ TPG_TFO(tpg)->close_session(init_sess);
+
+ spin_lock_bh(&tpg->acl_node_lock);
+ if (dynamic_acl)
+ acl->dynamic_node_acl = 1;
+ spin_unlock_bh(&tpg->acl_node_lock);
+ return -EINVAL;
+ }
+ spin_unlock_bh(&tpg->session_lock);
+ /*
+ * If the $FABRIC_MOD session for the Initiator Node ACL exists,
+ * forcefully shutdown the $FABRIC_MOD session/nexus.
+ */
+ if (init_sess)
+ TPG_TFO(tpg)->close_session(init_sess);
+
+ printk(KERN_INFO "Successfuly changed queue depth to: %d for Initiator"
+ " Node: %s on %s Target Portal Group: %u\n", queue_depth,
+ initiatorname, TPG_TFO(tpg)->get_fabric_name(),
+ TPG_TFO(tpg)->tpg_get_tag(tpg));
+
+ spin_lock_bh(&tpg->acl_node_lock);
+ if (dynamic_acl)
+ acl->dynamic_node_acl = 1;
+ spin_unlock_bh(&tpg->acl_node_lock);
+
+ return 0;
+}
+EXPORT_SYMBOL(core_tpg_set_initiator_node_queue_depth);
+
+static int core_tpg_setup_virtual_lun0(struct se_portal_group *se_tpg)
+{
+ /* Set in core_dev_setup_virtual_lun0() */
+ struct se_device *dev = se_global->g_lun0_dev;
+ struct se_lun *lun = &se_tpg->tpg_virt_lun0;
+ u32 lun_access = TRANSPORT_LUNFLAGS_READ_ONLY;
+ int ret;
+
+ lun->unpacked_lun = 0;
+ lun->lun_status = TRANSPORT_LUN_STATUS_FREE;
+ atomic_set(&lun->lun_acl_count, 0);
+ init_completion(&lun->lun_shutdown_comp);
+ INIT_LIST_HEAD(&lun->lun_acl_list);
+ INIT_LIST_HEAD(&lun->lun_cmd_list);
+ spin_lock_init(&lun->lun_acl_lock);
+ spin_lock_init(&lun->lun_cmd_lock);
+ spin_lock_init(&lun->lun_sep_lock);
+
+ ret = core_tpg_post_addlun(se_tpg, lun, lun_access, dev);
+ if (ret < 0)
+ return -1;
+
+ return 0;
+}
+
+static void core_tpg_release_virtual_lun0(struct se_portal_group *se_tpg)
+{
+ struct se_lun *lun = &se_tpg->tpg_virt_lun0;
+
+ core_tpg_post_dellun(se_tpg, lun);
+}
+
+int core_tpg_register(
+ struct target_core_fabric_ops *tfo,
+ struct se_wwn *se_wwn,
+ struct se_portal_group *se_tpg,
+ void *tpg_fabric_ptr,
+ int se_tpg_type)
+{
+ struct se_lun *lun;
+ u32 i;
+
+ se_tpg->tpg_lun_list = kzalloc((sizeof(struct se_lun) *
+ TRANSPORT_MAX_LUNS_PER_TPG), GFP_KERNEL);
+ if (!(se_tpg->tpg_lun_list)) {
+ printk(KERN_ERR "Unable to allocate struct se_portal_group->"
+ "tpg_lun_list\n");
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < TRANSPORT_MAX_LUNS_PER_TPG; i++) {
+ lun = &se_tpg->tpg_lun_list[i];
+ lun->unpacked_lun = i;
+ lun->lun_status = TRANSPORT_LUN_STATUS_FREE;
+ atomic_set(&lun->lun_acl_count, 0);
+ init_completion(&lun->lun_shutdown_comp);
+ INIT_LIST_HEAD(&lun->lun_acl_list);
+ INIT_LIST_HEAD(&lun->lun_cmd_list);
+ spin_lock_init(&lun->lun_acl_lock);
+ spin_lock_init(&lun->lun_cmd_lock);
+ spin_lock_init(&lun->lun_sep_lock);
+ }
+
+ se_tpg->se_tpg_type = se_tpg_type;
+ se_tpg->se_tpg_fabric_ptr = tpg_fabric_ptr;
+ se_tpg->se_tpg_tfo = tfo;
+ se_tpg->se_tpg_wwn = se_wwn;
+ atomic_set(&se_tpg->tpg_pr_ref_count, 0);
+ INIT_LIST_HEAD(&se_tpg->acl_node_list);
+ INIT_LIST_HEAD(&se_tpg->se_tpg_list);
+ INIT_LIST_HEAD(&se_tpg->tpg_sess_list);
+ spin_lock_init(&se_tpg->acl_node_lock);
+ spin_lock_init(&se_tpg->session_lock);
+ spin_lock_init(&se_tpg->tpg_lun_lock);
+
+ if (se_tpg->se_tpg_type == TRANSPORT_TPG_TYPE_NORMAL) {
+ if (core_tpg_setup_virtual_lun0(se_tpg) < 0) {
+ kfree(se_tpg);
+ return -ENOMEM;
+ }
+ }
+
+ spin_lock_bh(&se_global->se_tpg_lock);
+ list_add_tail(&se_tpg->se_tpg_list, &se_global->g_se_tpg_list);
+ spin_unlock_bh(&se_global->se_tpg_lock);
+
+ printk(KERN_INFO "TARGET_CORE[%s]: Allocated %s struct se_portal_group for"
+ " endpoint: %s, Portal Tag: %u\n", tfo->get_fabric_name(),
+ (se_tpg->se_tpg_type == TRANSPORT_TPG_TYPE_NORMAL) ?
+ "Normal" : "Discovery", (tfo->tpg_get_wwn(se_tpg) == NULL) ?
+ "None" : tfo->tpg_get_wwn(se_tpg), tfo->tpg_get_tag(se_tpg));
+
+ return 0;
+}
+EXPORT_SYMBOL(core_tpg_register);
+
+int core_tpg_deregister(struct se_portal_group *se_tpg)
+{
+ printk(KERN_INFO "TARGET_CORE[%s]: Deallocating %s struct se_portal_group"
+ " for endpoint: %s Portal Tag %u\n",
+ (se_tpg->se_tpg_type == TRANSPORT_TPG_TYPE_NORMAL) ?
+ "Normal" : "Discovery", TPG_TFO(se_tpg)->get_fabric_name(),
+ TPG_TFO(se_tpg)->tpg_get_wwn(se_tpg),
+ TPG_TFO(se_tpg)->tpg_get_tag(se_tpg));
+
+ spin_lock_bh(&se_global->se_tpg_lock);
+ list_del(&se_tpg->se_tpg_list);
+ spin_unlock_bh(&se_global->se_tpg_lock);
+
+ while (atomic_read(&se_tpg->tpg_pr_ref_count) != 0)
+ cpu_relax();
+
+ if (se_tpg->se_tpg_type == TRANSPORT_TPG_TYPE_NORMAL)
+ core_tpg_release_virtual_lun0(se_tpg);
+
+ se_tpg->se_tpg_fabric_ptr = NULL;
+ kfree(se_tpg->tpg_lun_list);
+ return 0;
+}
+EXPORT_SYMBOL(core_tpg_deregister);
+
+struct se_lun *core_tpg_pre_addlun(
+ struct se_portal_group *tpg,
+ u32 unpacked_lun)
+{
+ struct se_lun *lun;
+
+ if (unpacked_lun > (TRANSPORT_MAX_LUNS_PER_TPG-1)) {
+ printk(KERN_ERR "%s LUN: %u exceeds TRANSPORT_MAX_LUNS_PER_TPG"
+ "-1: %u for Target Portal Group: %u\n",
+ TPG_TFO(tpg)->get_fabric_name(),
+ unpacked_lun, TRANSPORT_MAX_LUNS_PER_TPG-1,
+ TPG_TFO(tpg)->tpg_get_tag(tpg));
+ return ERR_PTR(-EOVERFLOW);
+ }
+
+ spin_lock(&tpg->tpg_lun_lock);
+ lun = &tpg->tpg_lun_list[unpacked_lun];
+ if (lun->lun_status == TRANSPORT_LUN_STATUS_ACTIVE) {
+ printk(KERN_ERR "TPG Logical Unit Number: %u is already active"
+ " on %s Target Portal Group: %u, ignoring request.\n",
+ unpacked_lun, TPG_TFO(tpg)->get_fabric_name(),
+ TPG_TFO(tpg)->tpg_get_tag(tpg));
+ spin_unlock(&tpg->tpg_lun_lock);
+ return ERR_PTR(-EINVAL);
+ }
+ spin_unlock(&tpg->tpg_lun_lock);
+
+ return lun;
+}
+
+int core_tpg_post_addlun(
+ struct se_portal_group *tpg,
+ struct se_lun *lun,
+ u32 lun_access,
+ void *lun_ptr)
+{
+ if (core_dev_export(lun_ptr, tpg, lun) < 0)
+ return -1;
+
+ spin_lock(&tpg->tpg_lun_lock);
+ lun->lun_access = lun_access;
+ lun->lun_status = TRANSPORT_LUN_STATUS_ACTIVE;
+ spin_unlock(&tpg->tpg_lun_lock);
+
+ return 0;
+}
+
+static void core_tpg_shutdown_lun(
+ struct se_portal_group *tpg,
+ struct se_lun *lun)
+{
+ core_clear_lun_from_tpg(lun, tpg);
+ transport_clear_lun_from_sessions(lun);
+}
+
+struct se_lun *core_tpg_pre_dellun(
+ struct se_portal_group *tpg,
+ u32 unpacked_lun,
+ int *ret)
+{
+ struct se_lun *lun;
+
+ if (unpacked_lun > (TRANSPORT_MAX_LUNS_PER_TPG-1)) {
+ printk(KERN_ERR "%s LUN: %u exceeds TRANSPORT_MAX_LUNS_PER_TPG"
+ "-1: %u for Target Portal Group: %u\n",
+ TPG_TFO(tpg)->get_fabric_name(), unpacked_lun,
+ TRANSPORT_MAX_LUNS_PER_TPG-1,
+ TPG_TFO(tpg)->tpg_get_tag(tpg));
+ return ERR_PTR(-EOVERFLOW);
+ }
+
+ spin_lock(&tpg->tpg_lun_lock);
+ lun = &tpg->tpg_lun_list[unpacked_lun];
+ if (lun->lun_status != TRANSPORT_LUN_STATUS_ACTIVE) {
+ printk(KERN_ERR "%s Logical Unit Number: %u is not active on"
+ " Target Portal Group: %u, ignoring request.\n",
+ TPG_TFO(tpg)->get_fabric_name(), unpacked_lun,
+ TPG_TFO(tpg)->tpg_get_tag(tpg));
+ spin_unlock(&tpg->tpg_lun_lock);
+ return ERR_PTR(-ENODEV);
+ }
+ spin_unlock(&tpg->tpg_lun_lock);
+
+ return lun;
+}
+
+int core_tpg_post_dellun(
+ struct se_portal_group *tpg,
+ struct se_lun *lun)
+{
+ core_tpg_shutdown_lun(tpg, lun);
+
+ core_dev_unexport(lun->lun_se_dev, tpg, lun);
+
+ spin_lock(&tpg->tpg_lun_lock);
+ lun->lun_status = TRANSPORT_LUN_STATUS_FREE;
+ spin_unlock(&tpg->tpg_lun_lock);
+
+ return 0;
+}
diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c
new file mode 100644
index 0000000..28b6292ff
--- /dev/null
+++ b/drivers/target/target_core_transport.c
@@ -0,0 +1,6134 @@
+/*******************************************************************************
+ * Filename: target_core_transport.c
+ *
+ * This file contains the Generic Target Engine Core.
+ *
+ * Copyright (c) 2002, 2003, 2004, 2005 PyX Technologies, Inc.
+ * Copyright (c) 2005, 2006, 2007 SBE, Inc.
+ * Copyright (c) 2007-2010 Rising Tide Systems
+ * Copyright (c) 2008-2010 Linux-iSCSI.org
+ *
+ * Nicholas A. Bellinger <nab@kernel.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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ ******************************************************************************/
+
+#include <linux/version.h>
+#include <linux/net.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/slab.h>
+#include <linux/blkdev.h>
+#include <linux/spinlock.h>
+#include <linux/smp_lock.h>
+#include <linux/kthread.h>
+#include <linux/in.h>
+#include <linux/cdrom.h>
+#include <asm/unaligned.h>
+#include <net/sock.h>
+#include <net/tcp.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/libsas.h> /* For TASK_ATTR_* */
+
+#include <target/target_core_base.h>
+#include <target/target_core_device.h>
+#include <target/target_core_tmr.h>
+#include <target/target_core_tpg.h>
+#include <target/target_core_transport.h>
+#include <target/target_core_fabric_ops.h>
+#include <target/target_core_configfs.h>
+
+#include "target_core_alua.h"
+#include "target_core_hba.h"
+#include "target_core_pr.h"
+#include "target_core_scdb.h"
+#include "target_core_ua.h"
+
+/* #define DEBUG_CDB_HANDLER */
+#ifdef DEBUG_CDB_HANDLER
+#define DEBUG_CDB_H(x...) printk(KERN_INFO x)
+#else
+#define DEBUG_CDB_H(x...)
+#endif
+
+/* #define DEBUG_CMD_MAP */
+#ifdef DEBUG_CMD_MAP
+#define DEBUG_CMD_M(x...) printk(KERN_INFO x)
+#else
+#define DEBUG_CMD_M(x...)
+#endif
+
+/* #define DEBUG_MEM_ALLOC */
+#ifdef DEBUG_MEM_ALLOC
+#define DEBUG_MEM(x...) printk(KERN_INFO x)
+#else
+#define DEBUG_MEM(x...)
+#endif
+
+/* #define DEBUG_MEM2_ALLOC */
+#ifdef DEBUG_MEM2_ALLOC
+#define DEBUG_MEM2(x...) printk(KERN_INFO x)
+#else
+#define DEBUG_MEM2(x...)
+#endif
+
+/* #define DEBUG_SG_CALC */
+#ifdef DEBUG_SG_CALC
+#define DEBUG_SC(x...) printk(KERN_INFO x)
+#else
+#define DEBUG_SC(x...)
+#endif
+
+/* #define DEBUG_SE_OBJ */
+#ifdef DEBUG_SE_OBJ
+#define DEBUG_SO(x...) printk(KERN_INFO x)
+#else
+#define DEBUG_SO(x...)
+#endif
+
+/* #define DEBUG_CMD_VOL */
+#ifdef DEBUG_CMD_VOL
+#define DEBUG_VOL(x...) printk(KERN_INFO x)
+#else
+#define DEBUG_VOL(x...)
+#endif
+
+/* #define DEBUG_CMD_STOP */
+#ifdef DEBUG_CMD_STOP
+#define DEBUG_CS(x...) printk(KERN_INFO x)
+#else
+#define DEBUG_CS(x...)
+#endif
+
+/* #define DEBUG_PASSTHROUGH */
+#ifdef DEBUG_PASSTHROUGH
+#define DEBUG_PT(x...) printk(KERN_INFO x)
+#else
+#define DEBUG_PT(x...)
+#endif
+
+/* #define DEBUG_TASK_STOP */
+#ifdef DEBUG_TASK_STOP
+#define DEBUG_TS(x...) printk(KERN_INFO x)
+#else
+#define DEBUG_TS(x...)
+#endif
+
+/* #define DEBUG_TRANSPORT_STOP */
+#ifdef DEBUG_TRANSPORT_STOP
+#define DEBUG_TRANSPORT_S(x...) printk(KERN_INFO x)
+#else
+#define DEBUG_TRANSPORT_S(x...)
+#endif
+
+/* #define DEBUG_TASK_FAILURE */
+#ifdef DEBUG_TASK_FAILURE
+#define DEBUG_TF(x...) printk(KERN_INFO x)
+#else
+#define DEBUG_TF(x...)
+#endif
+
+/* #define DEBUG_DEV_OFFLINE */
+#ifdef DEBUG_DEV_OFFLINE
+#define DEBUG_DO(x...) printk(KERN_INFO x)
+#else
+#define DEBUG_DO(x...)
+#endif
+
+/* #define DEBUG_TASK_STATE */
+#ifdef DEBUG_TASK_STATE
+#define DEBUG_TSTATE(x...) printk(KERN_INFO x)
+#else
+#define DEBUG_TSTATE(x...)
+#endif
+
+/* #define DEBUG_STATUS_THR */
+#ifdef DEBUG_STATUS_THR
+#define DEBUG_ST(x...) printk(KERN_INFO x)
+#else
+#define DEBUG_ST(x...)
+#endif
+
+/* #define DEBUG_TASK_TIMEOUT */
+#ifdef DEBUG_TASK_TIMEOUT
+#define DEBUG_TT(x...) printk(KERN_INFO x)
+#else
+#define DEBUG_TT(x...)
+#endif
+
+/* #define DEBUG_GENERIC_REQUEST_FAILURE */
+#ifdef DEBUG_GENERIC_REQUEST_FAILURE
+#define DEBUG_GRF(x...) printk(KERN_INFO x)
+#else
+#define DEBUG_GRF(x...)
+#endif
+
+/* #define DEBUG_SAM_TASK_ATTRS */
+#ifdef DEBUG_SAM_TASK_ATTRS
+#define DEBUG_STA(x...) printk(KERN_INFO x)
+#else
+#define DEBUG_STA(x...)
+#endif
+
+struct se_global *se_global;
+
+static struct kmem_cache *se_cmd_cache;
+static struct kmem_cache *se_sess_cache;
+struct kmem_cache *se_tmr_req_cache;
+struct kmem_cache *se_ua_cache;
+struct kmem_cache *se_mem_cache;
+struct kmem_cache *t10_pr_reg_cache;
+struct kmem_cache *t10_alua_lu_gp_cache;
+struct kmem_cache *t10_alua_lu_gp_mem_cache;
+struct kmem_cache *t10_alua_tg_pt_gp_cache;
+struct kmem_cache *t10_alua_tg_pt_gp_mem_cache;
+
+/* Used for transport_dev_get_map_*() */
+typedef int (*map_func_t)(struct se_task *, u32);
+
+static int transport_generic_write_pending(struct se_cmd *);
+static int transport_processing_thread(void *);
+static int __transport_execute_tasks(struct se_device *dev);
+static void transport_complete_task_attr(struct se_cmd *cmd);
+static void transport_direct_request_timeout(struct se_cmd *cmd);
+static void transport_free_dev_tasks(struct se_cmd *cmd);
+static u32 transport_generic_get_cdb_count(struct se_cmd *cmd,
+ unsigned long long starting_lba, u32 sectors,
+ enum dma_data_direction data_direction,
+ struct list_head *mem_list, int set_counts);
+static int transport_generic_get_mem(struct se_cmd *cmd, u32 length,
+ u32 dma_size);
+static int transport_generic_remove(struct se_cmd *cmd,
+ int release_to_pool, int session_reinstatement);
+static int transport_get_sectors(struct se_cmd *cmd);
+static struct list_head *transport_init_se_mem_list(void);
+static int transport_map_sg_to_mem(struct se_cmd *cmd,
+ struct list_head *se_mem_list, void *in_mem,
+ u32 *se_mem_cnt);
+static void transport_memcpy_se_mem_read_contig(struct se_cmd *cmd,
+ unsigned char *dst, struct list_head *se_mem_list);
+static void transport_release_fe_cmd(struct se_cmd *cmd);
+static void transport_remove_cmd_from_queue(struct se_cmd *cmd,
+ struct se_queue_obj *qobj);
+static int transport_set_sense_codes(struct se_cmd *cmd, u8 asc, u8 ascq);
+static void transport_stop_all_task_timers(struct se_cmd *cmd);
+
+int transport_emulate_control_cdb(struct se_task *task);
+
+int init_se_global(void)
+{
+ struct se_global *global;
+
+ global = kzalloc(sizeof(struct se_global), GFP_KERNEL);
+ if (!(global)) {
+ printk(KERN_ERR "Unable to allocate memory for struct se_global\n");
+ return -1;
+ }
+
+ INIT_LIST_HEAD(&global->g_lu_gps_list);
+ INIT_LIST_HEAD(&global->g_se_tpg_list);
+ INIT_LIST_HEAD(&global->g_hba_list);
+ INIT_LIST_HEAD(&global->g_se_dev_list);
+ spin_lock_init(&global->g_device_lock);
+ spin_lock_init(&global->hba_lock);
+ spin_lock_init(&global->se_tpg_lock);
+ spin_lock_init(&global->lu_gps_lock);
+ spin_lock_init(&global->plugin_class_lock);
+
+ se_cmd_cache = kmem_cache_create("se_cmd_cache",
+ sizeof(struct se_cmd), __alignof__(struct se_cmd), 0, NULL);
+ if (!(se_cmd_cache)) {
+ printk(KERN_ERR "kmem_cache_create for struct se_cmd failed\n");
+ goto out;
+ }
+ se_tmr_req_cache = kmem_cache_create("se_tmr_cache",
+ sizeof(struct se_tmr_req), __alignof__(struct se_tmr_req),
+ 0, NULL);
+ if (!(se_tmr_req_cache)) {
+ printk(KERN_ERR "kmem_cache_create() for struct se_tmr_req"
+ " failed\n");
+ goto out;
+ }
+ se_sess_cache = kmem_cache_create("se_sess_cache",
+ sizeof(struct se_session), __alignof__(struct se_session),
+ 0, NULL);
+ if (!(se_sess_cache)) {
+ printk(KERN_ERR "kmem_cache_create() for struct se_session"
+ " failed\n");
+ goto out;
+ }
+ se_ua_cache = kmem_cache_create("se_ua_cache",
+ sizeof(struct se_ua), __alignof__(struct se_ua),
+ 0, NULL);
+ if (!(se_ua_cache)) {
+ printk(KERN_ERR "kmem_cache_create() for struct se_ua failed\n");
+ goto out;
+ }
+ se_mem_cache = kmem_cache_create("se_mem_cache",
+ sizeof(struct se_mem), __alignof__(struct se_mem), 0, NULL);
+ if (!(se_mem_cache)) {
+ printk(KERN_ERR "kmem_cache_create() for struct se_mem failed\n");
+ goto out;
+ }
+ t10_pr_reg_cache = kmem_cache_create("t10_pr_reg_cache",
+ sizeof(struct t10_pr_registration),
+ __alignof__(struct t10_pr_registration), 0, NULL);
+ if (!(t10_pr_reg_cache)) {
+ printk(KERN_ERR "kmem_cache_create() for struct t10_pr_registration"
+ " failed\n");
+ goto out;
+ }
+ t10_alua_lu_gp_cache = kmem_cache_create("t10_alua_lu_gp_cache",
+ sizeof(struct t10_alua_lu_gp), __alignof__(struct t10_alua_lu_gp),
+ 0, NULL);
+ if (!(t10_alua_lu_gp_cache)) {
+ printk(KERN_ERR "kmem_cache_create() for t10_alua_lu_gp_cache"
+ " failed\n");
+ goto out;
+ }
+ t10_alua_lu_gp_mem_cache = kmem_cache_create("t10_alua_lu_gp_mem_cache",
+ sizeof(struct t10_alua_lu_gp_member),
+ __alignof__(struct t10_alua_lu_gp_member), 0, NULL);
+ if (!(t10_alua_lu_gp_mem_cache)) {
+ printk(KERN_ERR "kmem_cache_create() for t10_alua_lu_gp_mem_"
+ "cache failed\n");
+ goto out;
+ }
+ t10_alua_tg_pt_gp_cache = kmem_cache_create("t10_alua_tg_pt_gp_cache",
+ sizeof(struct t10_alua_tg_pt_gp),
+ __alignof__(struct t10_alua_tg_pt_gp), 0, NULL);
+ if (!(t10_alua_tg_pt_gp_cache)) {
+ printk(KERN_ERR "kmem_cache_create() for t10_alua_tg_pt_gp_"
+ "cache failed\n");
+ goto out;
+ }
+ t10_alua_tg_pt_gp_mem_cache = kmem_cache_create(
+ "t10_alua_tg_pt_gp_mem_cache",
+ sizeof(struct t10_alua_tg_pt_gp_member),
+ __alignof__(struct t10_alua_tg_pt_gp_member),
+ 0, NULL);
+ if (!(t10_alua_tg_pt_gp_mem_cache)) {
+ printk(KERN_ERR "kmem_cache_create() for t10_alua_tg_pt_gp_"
+ "mem_t failed\n");
+ goto out;
+ }
+
+ se_global = global;
+
+ return 0;
+out:
+ if (se_cmd_cache)
+ kmem_cache_destroy(se_cmd_cache);
+ if (se_tmr_req_cache)
+ kmem_cache_destroy(se_tmr_req_cache);
+ if (se_sess_cache)
+ kmem_cache_destroy(se_sess_cache);
+ if (se_ua_cache)
+ kmem_cache_destroy(se_ua_cache);
+ if (se_mem_cache)
+ kmem_cache_destroy(se_mem_cache);
+ if (t10_pr_reg_cache)
+ kmem_cache_destroy(t10_pr_reg_cache);
+ if (t10_alua_lu_gp_cache)
+ kmem_cache_destroy(t10_alua_lu_gp_cache);
+ if (t10_alua_lu_gp_mem_cache)
+ kmem_cache_destroy(t10_alua_lu_gp_mem_cache);
+ if (t10_alua_tg_pt_gp_cache)
+ kmem_cache_destroy(t10_alua_tg_pt_gp_cache);
+ if (t10_alua_tg_pt_gp_mem_cache)
+ kmem_cache_destroy(t10_alua_tg_pt_gp_mem_cache);
+ kfree(global);
+ return -1;
+}
+
+void release_se_global(void)
+{
+ struct se_global *global;
+
+ global = se_global;
+ if (!(global))
+ return;
+
+ kmem_cache_destroy(se_cmd_cache);
+ kmem_cache_destroy(se_tmr_req_cache);
+ kmem_cache_destroy(se_sess_cache);
+ kmem_cache_destroy(se_ua_cache);
+ kmem_cache_destroy(se_mem_cache);
+ kmem_cache_destroy(t10_pr_reg_cache);
+ kmem_cache_destroy(t10_alua_lu_gp_cache);
+ kmem_cache_destroy(t10_alua_lu_gp_mem_cache);
+ kmem_cache_destroy(t10_alua_tg_pt_gp_cache);
+ kmem_cache_destroy(t10_alua_tg_pt_gp_mem_cache);
+ kfree(global);
+
+ se_global = NULL;
+}
+
+void transport_init_queue_obj(struct se_queue_obj *qobj)
+{
+ atomic_set(&qobj->queue_cnt, 0);
+ INIT_LIST_HEAD(&qobj->qobj_list);
+ init_waitqueue_head(&qobj->thread_wq);
+ spin_lock_init(&qobj->cmd_queue_lock);
+}
+EXPORT_SYMBOL(transport_init_queue_obj);
+
+static int transport_subsystem_reqmods(void)
+{
+ int ret;
+
+ ret = request_module("target_core_iblock");
+ if (ret != 0)
+ printk(KERN_ERR "Unable to load target_core_iblock\n");
+
+ ret = request_module("target_core_file");
+ if (ret != 0)
+ printk(KERN_ERR "Unable to load target_core_file\n");
+
+ ret = request_module("target_core_pscsi");
+ if (ret != 0)
+ printk(KERN_ERR "Unable to load target_core_pscsi\n");
+
+ ret = request_module("target_core_stgt");
+ if (ret != 0)
+ printk(KERN_ERR "Unable to load target_core_stgt\n");
+
+ return 0;
+}
+
+int transport_subsystem_check_init(void)
+{
+ if (se_global->g_sub_api_initialized)
+ return 0;
+ /*
+ * Request the loading of known TCM subsystem plugins..
+ */
+ if (transport_subsystem_reqmods() < 0)
+ return -1;
+
+ se_global->g_sub_api_initialized = 1;
+ return 0;
+}
+
+struct se_session *transport_init_session(void)
+{
+ struct se_session *se_sess;
+
+ se_sess = kmem_cache_zalloc(se_sess_cache, GFP_KERNEL);
+ if (!(se_sess)) {
+ printk(KERN_ERR "Unable to allocate struct se_session from"
+ " se_sess_cache\n");
+ return ERR_PTR(-ENOMEM);
+ }
+ INIT_LIST_HEAD(&se_sess->sess_list);
+ INIT_LIST_HEAD(&se_sess->sess_acl_list);
+ atomic_set(&se_sess->mib_ref_count, 0);
+
+ return se_sess;
+}
+EXPORT_SYMBOL(transport_init_session);
+
+/*
+ * Called with spin_lock_bh(&struct se_portal_group->session_lock called.
+ */
+void __transport_register_session(
+ struct se_portal_group *se_tpg,
+ struct se_node_acl *se_nacl,
+ struct se_session *se_sess,
+ void *fabric_sess_ptr)
+{
+ unsigned char buf[PR_REG_ISID_LEN];
+
+ se_sess->se_tpg = se_tpg;
+ se_sess->fabric_sess_ptr = fabric_sess_ptr;
+ /*
+ * Used by struct se_node_acl's under ConfigFS to locate active se_session-t
+ *
+ * Only set for struct se_session's that will actually be moving I/O.
+ * eg: *NOT* discovery sessions.
+ */
+ if (se_nacl) {
+ /*
+ * If the fabric module supports an ISID based TransportID,
+ * save this value in binary from the fabric I_T Nexus now.
+ */
+ if (TPG_TFO(se_tpg)->sess_get_initiator_sid != NULL) {
+ memset(&buf[0], 0, PR_REG_ISID_LEN);
+ TPG_TFO(se_tpg)->sess_get_initiator_sid(se_sess,
+ &buf[0], PR_REG_ISID_LEN);
+ se_sess->sess_bin_isid = get_unaligned_be64(&buf[0]);
+ }
+ spin_lock_irq(&se_nacl->nacl_sess_lock);
+ /*
+ * The se_nacl->nacl_sess pointer will be set to the
+ * last active I_T Nexus for each struct se_node_acl.
+ */
+ se_nacl->nacl_sess = se_sess;
+
+ list_add_tail(&se_sess->sess_acl_list,
+ &se_nacl->acl_sess_list);
+ spin_unlock_irq(&se_nacl->nacl_sess_lock);
+ }
+ list_add_tail(&se_sess->sess_list, &se_tpg->tpg_sess_list);
+
+ printk(KERN_INFO "TARGET_CORE[%s]: Registered fabric_sess_ptr: %p\n",
+ TPG_TFO(se_tpg)->get_fabric_name(), se_sess->fabric_sess_ptr);
+}
+EXPORT_SYMBOL(__transport_register_session);
+
+void transport_register_session(
+ struct se_portal_group *se_tpg,
+ struct se_node_acl *se_nacl,
+ struct se_session *se_sess,
+ void *fabric_sess_ptr)
+{
+ spin_lock_bh(&se_tpg->session_lock);
+ __transport_register_session(se_tpg, se_nacl, se_sess, fabric_sess_ptr);
+ spin_unlock_bh(&se_tpg->session_lock);
+}
+EXPORT_SYMBOL(transport_register_session);
+
+void transport_deregister_session_configfs(struct se_session *se_sess)
+{
+ struct se_node_acl *se_nacl;
+
+ /*
+ * Used by struct se_node_acl's under ConfigFS to locate active struct se_session
+ */
+ se_nacl = se_sess->se_node_acl;
+ if ((se_nacl)) {
+ spin_lock_irq(&se_nacl->nacl_sess_lock);
+ list_del(&se_sess->sess_acl_list);
+ /*
+ * If the session list is empty, then clear the pointer.
+ * Otherwise, set the struct se_session pointer from the tail
+ * element of the per struct se_node_acl active session list.
+ */
+ if (list_empty(&se_nacl->acl_sess_list))
+ se_nacl->nacl_sess = NULL;
+ else {
+ se_nacl->nacl_sess = container_of(
+ se_nacl->acl_sess_list.prev,
+ struct se_session, sess_acl_list);
+ }
+ spin_unlock_irq(&se_nacl->nacl_sess_lock);
+ }
+}
+EXPORT_SYMBOL(transport_deregister_session_configfs);
+
+void transport_free_session(struct se_session *se_sess)
+{
+ kmem_cache_free(se_sess_cache, se_sess);
+}
+EXPORT_SYMBOL(transport_free_session);
+
+void transport_deregister_session(struct se_session *se_sess)
+{
+ struct se_portal_group *se_tpg = se_sess->se_tpg;
+ struct se_node_acl *se_nacl;
+
+ if (!(se_tpg)) {
+ transport_free_session(se_sess);
+ return;
+ }
+ /*
+ * Wait for possible reference in drivers/target/target_core_mib.c:
+ * scsi_att_intr_port_seq_show()
+ */
+ while (atomic_read(&se_sess->mib_ref_count) != 0)
+ cpu_relax();
+
+ spin_lock_bh(&se_tpg->session_lock);
+ list_del(&se_sess->sess_list);
+ se_sess->se_tpg = NULL;
+ se_sess->fabric_sess_ptr = NULL;
+ spin_unlock_bh(&se_tpg->session_lock);
+
+ /*
+ * Determine if we need to do extra work for this initiator node's
+ * struct se_node_acl if it had been previously dynamically generated.
+ */
+ se_nacl = se_sess->se_node_acl;
+ if ((se_nacl)) {
+ spin_lock_bh(&se_tpg->acl_node_lock);
+ if (se_nacl->dynamic_node_acl) {
+ if (!(TPG_TFO(se_tpg)->tpg_check_demo_mode_cache(
+ se_tpg))) {
+ list_del(&se_nacl->acl_list);
+ se_tpg->num_node_acls--;
+ spin_unlock_bh(&se_tpg->acl_node_lock);
+
+ core_tpg_wait_for_nacl_pr_ref(se_nacl);
+ core_tpg_wait_for_mib_ref(se_nacl);
+ core_free_device_list_for_node(se_nacl, se_tpg);
+ TPG_TFO(se_tpg)->tpg_release_fabric_acl(se_tpg,
+ se_nacl);
+ spin_lock_bh(&se_tpg->acl_node_lock);
+ }
+ }
+ spin_unlock_bh(&se_tpg->acl_node_lock);
+ }
+
+ transport_free_session(se_sess);
+
+ printk(KERN_INFO "TARGET_CORE[%s]: Deregistered fabric_sess\n",
+ TPG_TFO(se_tpg)->get_fabric_name());
+}
+EXPORT_SYMBOL(transport_deregister_session);
+
+/*
+ * Called with T_TASK(cmd)->t_state_lock held.
+ */
+static void transport_all_task_dev_remove_state(struct se_cmd *cmd)
+{
+ struct se_device *dev;
+ struct se_task *task;
+ unsigned long flags;
+
+ if (!T_TASK(cmd))
+ return;
+
+ list_for_each_entry(task, &T_TASK(cmd)->t_task_list, t_list) {
+ dev = task->se_dev;
+ if (!(dev))
+ continue;
+
+ if (atomic_read(&task->task_active))
+ continue;
+
+ if (!(atomic_read(&task->task_state_active)))
+ continue;
+
+ spin_lock_irqsave(&dev->execute_task_lock, flags);
+ list_del(&task->t_state_list);
+ DEBUG_TSTATE("Removed ITT: 0x%08x dev: %p task[%p]\n",
+ CMD_TFO(cmd)->tfo_get_task_tag(cmd), dev, task);
+ spin_unlock_irqrestore(&dev->execute_task_lock, flags);
+
+ atomic_set(&task->task_state_active, 0);
+ atomic_dec(&T_TASK(cmd)->t_task_cdbs_ex_left);
+ }
+}
+
+/* transport_cmd_check_stop():
+ *
+ * 'transport_off = 1' determines if t_transport_active should be cleared.
+ * 'transport_off = 2' determines if task_dev_state should be removed.
+ *
+ * A non-zero u8 t_state sets cmd->t_state.
+ * Returns 1 when command is stopped, else 0.
+ */
+static int transport_cmd_check_stop(
+ struct se_cmd *cmd,
+ int transport_off,
+ u8 t_state)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&T_TASK(cmd)->t_state_lock, flags);
+ /*
+ * Determine if IOCTL context caller in requesting the stopping of this
+ * command for LUN shutdown purposes.
+ */
+ if (atomic_read(&T_TASK(cmd)->transport_lun_stop)) {
+ DEBUG_CS("%s:%d atomic_read(&T_TASK(cmd)->transport_lun_stop)"
+ " == TRUE for ITT: 0x%08x\n", __func__, __LINE__,
+ CMD_TFO(cmd)->get_task_tag(cmd));
+
+ cmd->deferred_t_state = cmd->t_state;
+ cmd->t_state = TRANSPORT_DEFERRED_CMD;
+ atomic_set(&T_TASK(cmd)->t_transport_active, 0);
+ if (transport_off == 2)
+ transport_all_task_dev_remove_state(cmd);
+ spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags);
+
+ complete(&T_TASK(cmd)->transport_lun_stop_comp);
+ return 1;
+ }
+ /*
+ * Determine if frontend context caller is requesting the stopping of
+ * this command for frontend excpections.
+ */
+ if (atomic_read(&T_TASK(cmd)->t_transport_stop)) {
+ DEBUG_CS("%s:%d atomic_read(&T_TASK(cmd)->t_transport_stop) =="
+ " TRUE for ITT: 0x%08x\n", __func__, __LINE__,
+ CMD_TFO(cmd)->get_task_tag(cmd));
+
+ cmd->deferred_t_state = cmd->t_state;
+ cmd->t_state = TRANSPORT_DEFERRED_CMD;
+ if (transport_off == 2)
+ transport_all_task_dev_remove_state(cmd);
+
+ /*
+ * Clear struct se_cmd->se_lun before the transport_off == 2 handoff
+ * to FE.
+ */
+ if (transport_off == 2)
+ cmd->se_lun = NULL;
+ spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags);
+
+ complete(&T_TASK(cmd)->t_transport_stop_comp);
+ return 1;
+ }
+ if (transport_off) {
+ atomic_set(&T_TASK(cmd)->t_transport_active, 0);
+ if (transport_off == 2) {
+ transport_all_task_dev_remove_state(cmd);
+ /*
+ * Clear struct se_cmd->se_lun before the transport_off == 2
+ * handoff to fabric module.
+ */
+ cmd->se_lun = NULL;
+ /*
+ * Some fabric modules like tcm_loop can release
+ * their internally allocated I/O refrence now and
+ * struct se_cmd now.
+ */
+ if (CMD_TFO(cmd)->check_stop_free != NULL) {
+ spin_unlock_irqrestore(
+ &T_TASK(cmd)->t_state_lock, flags);
+
+ CMD_TFO(cmd)->check_stop_free(cmd);
+ return 1;
+ }
+ }
+ spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags);
+
+ return 0;
+ } else if (t_state)
+ cmd->t_state = t_state;
+ spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags);
+
+ return 0;
+}
+
+static int transport_cmd_check_stop_to_fabric(struct se_cmd *cmd)
+{
+ return transport_cmd_check_stop(cmd, 2, 0);
+}
+
+static void transport_lun_remove_cmd(struct se_cmd *cmd)
+{
+ struct se_lun *lun = SE_LUN(cmd);
+ unsigned long flags;
+
+ if (!lun)
+ return;
+
+ spin_lock_irqsave(&T_TASK(cmd)->t_state_lock, flags);
+ if (!(atomic_read(&T_TASK(cmd)->transport_dev_active))) {
+ spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags);
+ goto check_lun;
+ }
+ atomic_set(&T_TASK(cmd)->transport_dev_active, 0);
+ transport_all_task_dev_remove_state(cmd);
+ spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags);
+
+ transport_free_dev_tasks(cmd);
+
+check_lun:
+ spin_lock_irqsave(&lun->lun_cmd_lock, flags);
+ if (atomic_read(&T_TASK(cmd)->transport_lun_active)) {
+ list_del(&cmd->se_lun_list);
+ atomic_set(&T_TASK(cmd)->transport_lun_active, 0);
+#if 0
+ printk(KERN_INFO "Removed ITT: 0x%08x from LUN LIST[%d]\n"
+ CMD_TFO(cmd)->get_task_tag(cmd), lun->unpacked_lun);
+#endif
+ }
+ spin_unlock_irqrestore(&lun->lun_cmd_lock, flags);
+}
+
+void transport_cmd_finish_abort(struct se_cmd *cmd, int remove)
+{
+ transport_remove_cmd_from_queue(cmd, SE_DEV(cmd)->dev_queue_obj);
+ transport_lun_remove_cmd(cmd);
+
+ if (transport_cmd_check_stop_to_fabric(cmd))
+ return;
+ if (remove)
+ transport_generic_remove(cmd, 0, 0);
+}
+
+void transport_cmd_finish_abort_tmr(struct se_cmd *cmd)
+{
+ transport_remove_cmd_from_queue(cmd, SE_DEV(cmd)->dev_queue_obj);
+
+ if (transport_cmd_check_stop_to_fabric(cmd))
+ return;
+
+ transport_generic_remove(cmd, 0, 0);
+}
+
+static int transport_add_cmd_to_queue(
+ struct se_cmd *cmd,
+ int t_state)
+{
+ struct se_device *dev = cmd->se_dev;
+ struct se_queue_obj *qobj = dev->dev_queue_obj;
+ struct se_queue_req *qr;
+ unsigned long flags;
+
+ qr = kzalloc(sizeof(struct se_queue_req), GFP_ATOMIC);
+ if (!(qr)) {
+ printk(KERN_ERR "Unable to allocate memory for"
+ " struct se_queue_req\n");
+ return -1;
+ }
+ INIT_LIST_HEAD(&qr->qr_list);
+
+ qr->cmd = (void *)cmd;
+ qr->state = t_state;
+
+ if (t_state) {
+ spin_lock_irqsave(&T_TASK(cmd)->t_state_lock, flags);
+ cmd->t_state = t_state;
+ atomic_set(&T_TASK(cmd)->t_transport_active, 1);
+ spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags);
+ }
+
+ spin_lock_irqsave(&qobj->cmd_queue_lock, flags);
+ list_add_tail(&qr->qr_list, &qobj->qobj_list);
+ atomic_inc(&T_TASK(cmd)->t_transport_queue_active);
+ spin_unlock_irqrestore(&qobj->cmd_queue_lock, flags);
+
+ atomic_inc(&qobj->queue_cnt);
+ wake_up_interruptible(&qobj->thread_wq);
+ return 0;
+}
+
+/*
+ * Called with struct se_queue_obj->cmd_queue_lock held.
+ */
+static struct se_queue_req *
+__transport_get_qr_from_queue(struct se_queue_obj *qobj)
+{
+ struct se_cmd *cmd;
+ struct se_queue_req *qr = NULL;
+
+ if (list_empty(&qobj->qobj_list))
+ return NULL;
+
+ list_for_each_entry(qr, &qobj->qobj_list, qr_list)
+ break;
+
+ if (qr->cmd) {
+ cmd = (struct se_cmd *)qr->cmd;
+ atomic_dec(&T_TASK(cmd)->t_transport_queue_active);
+ }
+ list_del(&qr->qr_list);
+ atomic_dec(&qobj->queue_cnt);
+
+ return qr;
+}
+
+static struct se_queue_req *
+transport_get_qr_from_queue(struct se_queue_obj *qobj)
+{
+ struct se_cmd *cmd;
+ struct se_queue_req *qr;
+ unsigned long flags;
+
+ spin_lock_irqsave(&qobj->cmd_queue_lock, flags);
+ if (list_empty(&qobj->qobj_list)) {
+ spin_unlock_irqrestore(&qobj->cmd_queue_lock, flags);
+ return NULL;
+ }
+
+ list_for_each_entry(qr, &qobj->qobj_list, qr_list)
+ break;
+
+ if (qr->cmd) {
+ cmd = (struct se_cmd *)qr->cmd;
+ atomic_dec(&T_TASK(cmd)->t_transport_queue_active);
+ }
+ list_del(&qr->qr_list);
+ atomic_dec(&qobj->queue_cnt);
+ spin_unlock_irqrestore(&qobj->cmd_queue_lock, flags);
+
+ return qr;
+}
+
+static void transport_remove_cmd_from_queue(struct se_cmd *cmd,
+ struct se_queue_obj *qobj)
+{
+ struct se_cmd *q_cmd;
+ struct se_queue_req *qr = NULL, *qr_p = NULL;
+ unsigned long flags;
+
+ spin_lock_irqsave(&qobj->cmd_queue_lock, flags);
+ if (!(atomic_read(&T_TASK(cmd)->t_transport_queue_active))) {
+ spin_unlock_irqrestore(&qobj->cmd_queue_lock, flags);
+ return;
+ }
+
+ list_for_each_entry_safe(qr, qr_p, &qobj->qobj_list, qr_list) {
+ q_cmd = (struct se_cmd *)qr->cmd;
+ if (q_cmd != cmd)
+ continue;
+
+ atomic_dec(&T_TASK(q_cmd)->t_transport_queue_active);
+ atomic_dec(&qobj->queue_cnt);
+ list_del(&qr->qr_list);
+ kfree(qr);
+ }
+ spin_unlock_irqrestore(&qobj->cmd_queue_lock, flags);
+
+ if (atomic_read(&T_TASK(cmd)->t_transport_queue_active)) {
+ printk(KERN_ERR "ITT: 0x%08x t_transport_queue_active: %d\n",
+ CMD_TFO(cmd)->get_task_tag(cmd),
+ atomic_read(&T_TASK(cmd)->t_transport_queue_active));
+ }
+}
+
+/*
+ * Completion function used by TCM subsystem plugins (such as FILEIO)
+ * for queueing up response from struct se_subsystem_api->do_task()
+ */
+void transport_complete_sync_cache(struct se_cmd *cmd, int good)
+{
+ struct se_task *task = list_entry(T_TASK(cmd)->t_task_list.next,
+ struct se_task, t_list);
+
+ if (good) {
+ cmd->scsi_status = SAM_STAT_GOOD;
+ task->task_scsi_status = GOOD;
+ } else {
+ task->task_scsi_status = SAM_STAT_CHECK_CONDITION;
+ task->task_error_status = PYX_TRANSPORT_ILLEGAL_REQUEST;
+ TASK_CMD(task)->transport_error_status =
+ PYX_TRANSPORT_ILLEGAL_REQUEST;
+ }
+
+ transport_complete_task(task, good);
+}
+EXPORT_SYMBOL(transport_complete_sync_cache);
+
+/* transport_complete_task():
+ *
+ * Called from interrupt and non interrupt context depending
+ * on the transport plugin.
+ */
+void transport_complete_task(struct se_task *task, int success)
+{
+ struct se_cmd *cmd = TASK_CMD(task);
+ struct se_device *dev = task->se_dev;
+ int t_state;
+ unsigned long flags;
+#if 0
+ printk(KERN_INFO "task: %p CDB: 0x%02x obj_ptr: %p\n", task,
+ T_TASK(cmd)->t_task_cdb[0], dev);
+#endif
+ if (dev) {
+ spin_lock_irqsave(&SE_HBA(dev)->hba_queue_lock, flags);
+ atomic_inc(&dev->depth_left);
+ atomic_inc(&SE_HBA(dev)->left_queue_depth);
+ spin_unlock_irqrestore(&SE_HBA(dev)->hba_queue_lock, flags);
+ }
+
+ spin_lock_irqsave(&T_TASK(cmd)->t_state_lock, flags);
+ atomic_set(&task->task_active, 0);
+
+ /*
+ * See if any sense data exists, if so set the TASK_SENSE flag.
+ * Also check for any other post completion work that needs to be
+ * done by the plugins.
+ */
+ if (dev && dev->transport->transport_complete) {
+ if (dev->transport->transport_complete(task) != 0) {
+ cmd->se_cmd_flags |= SCF_TRANSPORT_TASK_SENSE;
+ task->task_sense = 1;
+ success = 1;
+ }
+ }
+
+ /*
+ * See if we are waiting for outstanding struct se_task
+ * to complete for an exception condition
+ */
+ if (atomic_read(&task->task_stop)) {
+ /*
+ * Decrement T_TASK(cmd)->t_se_count if this task had
+ * previously thrown its timeout exception handler.
+ */
+ if (atomic_read(&task->task_timeout)) {
+ atomic_dec(&T_TASK(cmd)->t_se_count);
+ atomic_set(&task->task_timeout, 0);
+ }
+ spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags);
+
+ complete(&task->task_stop_comp);
+ return;
+ }
+ /*
+ * If the task's timeout handler has fired, use the t_task_cdbs_timeout
+ * left counter to determine when the struct se_cmd is ready to be queued to
+ * the processing thread.
+ */
+ if (atomic_read(&task->task_timeout)) {
+ if (!(atomic_dec_and_test(
+ &T_TASK(cmd)->t_task_cdbs_timeout_left))) {
+ spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock,
+ flags);
+ return;
+ }
+ t_state = TRANSPORT_COMPLETE_TIMEOUT;
+ spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags);
+
+ transport_add_cmd_to_queue(cmd, t_state);
+ return;
+ }
+ atomic_dec(&T_TASK(cmd)->t_task_cdbs_timeout_left);
+
+ /*
+ * Decrement the outstanding t_task_cdbs_left count. The last
+ * struct se_task from struct se_cmd will complete itself into the
+ * device queue depending upon int success.
+ */
+ if (!(atomic_dec_and_test(&T_TASK(cmd)->t_task_cdbs_left))) {
+ if (!success)
+ T_TASK(cmd)->t_tasks_failed = 1;
+
+ spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags);
+ return;
+ }
+
+ if (!success || T_TASK(cmd)->t_tasks_failed) {
+ t_state = TRANSPORT_COMPLETE_FAILURE;
+ if (!task->task_error_status) {
+ task->task_error_status =
+ PYX_TRANSPORT_UNKNOWN_SAM_OPCODE;
+ cmd->transport_error_status =
+ PYX_TRANSPORT_UNKNOWN_SAM_OPCODE;
+ }
+ } else {
+ atomic_set(&T_TASK(cmd)->t_transport_complete, 1);
+ t_state = TRANSPORT_COMPLETE_OK;
+ }
+ spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags);
+
+ transport_add_cmd_to_queue(cmd, t_state);
+}
+EXPORT_SYMBOL(transport_complete_task);
+
+/*
+ * Called by transport_add_tasks_from_cmd() once a struct se_cmd's
+ * struct se_task list are ready to be added to the active execution list
+ * struct se_device
+
+ * Called with se_dev_t->execute_task_lock called.
+ */
+static inline int transport_add_task_check_sam_attr(
+ struct se_task *task,
+ struct se_task *task_prev,
+ struct se_device *dev)
+{
+ /*
+ * No SAM Task attribute emulation enabled, add to tail of
+ * execution queue
+ */
+ if (dev->dev_task_attr_type != SAM_TASK_ATTR_EMULATED) {
+ list_add_tail(&task->t_execute_list, &dev->execute_task_list);
+ return 0;
+ }
+ /*
+ * HEAD_OF_QUEUE attribute for received CDB, which means
+ * the first task that is associated with a struct se_cmd goes to
+ * head of the struct se_device->execute_task_list, and task_prev
+ * after that for each subsequent task
+ */
+ if (task->task_se_cmd->sam_task_attr == TASK_ATTR_HOQ) {
+ list_add(&task->t_execute_list,
+ (task_prev != NULL) ?
+ &task_prev->t_execute_list :
+ &dev->execute_task_list);
+
+ DEBUG_STA("Set HEAD_OF_QUEUE for task CDB: 0x%02x"
+ " in execution queue\n",
+ T_TASK(task->task_se_cmd)->t_task_cdb[0]);
+ return 1;
+ }
+ /*
+ * For ORDERED, SIMPLE or UNTAGGED attribute tasks once they have been
+ * transitioned from Dermant -> Active state, and are added to the end
+ * of the struct se_device->execute_task_list
+ */
+ list_add_tail(&task->t_execute_list, &dev->execute_task_list);
+ return 0;
+}
+
+/* __transport_add_task_to_execute_queue():
+ *
+ * Called with se_dev_t->execute_task_lock called.
+ */
+static void __transport_add_task_to_execute_queue(
+ struct se_task *task,
+ struct se_task *task_prev,
+ struct se_device *dev)
+{
+ int head_of_queue;
+
+ head_of_queue = transport_add_task_check_sam_attr(task, task_prev, dev);
+ atomic_inc(&dev->execute_tasks);
+
+ if (atomic_read(&task->task_state_active))
+ return;
+ /*
+ * Determine if this task needs to go to HEAD_OF_QUEUE for the
+ * state list as well. Running with SAM Task Attribute emulation
+ * will always return head_of_queue == 0 here
+ */
+ if (head_of_queue)
+ list_add(&task->t_state_list, (task_prev) ?
+ &task_prev->t_state_list :
+ &dev->state_task_list);
+ else
+ list_add_tail(&task->t_state_list, &dev->state_task_list);
+
+ atomic_set(&task->task_state_active, 1);
+
+ DEBUG_TSTATE("Added ITT: 0x%08x task[%p] to dev: %p\n",
+ CMD_TFO(task->task_se_cmd)->get_task_tag(task->task_se_cmd),
+ task, dev);
+}
+
+static void transport_add_tasks_to_state_queue(struct se_cmd *cmd)
+{
+ struct se_device *dev;
+ struct se_task *task;
+ unsigned long flags;
+
+ spin_lock_irqsave(&T_TASK(cmd)->t_state_lock, flags);
+ list_for_each_entry(task, &T_TASK(cmd)->t_task_list, t_list) {
+ dev = task->se_dev;
+
+ if (atomic_read(&task->task_state_active))
+ continue;
+
+ spin_lock(&dev->execute_task_lock);
+ list_add_tail(&task->t_state_list, &dev->state_task_list);
+ atomic_set(&task->task_state_active, 1);
+
+ DEBUG_TSTATE("Added ITT: 0x%08x task[%p] to dev: %p\n",
+ CMD_TFO(task->task_se_cmd)->get_task_tag(
+ task->task_se_cmd), task, dev);
+
+ spin_unlock(&dev->execute_task_lock);
+ }
+ spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags);
+}
+
+static void transport_add_tasks_from_cmd(struct se_cmd *cmd)
+{
+ struct se_device *dev = SE_DEV(cmd);
+ struct se_task *task, *task_prev = NULL;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->execute_task_lock, flags);
+ list_for_each_entry(task, &T_TASK(cmd)->t_task_list, t_list) {
+ if (atomic_read(&task->task_execute_queue))
+ continue;
+ /*
+ * __transport_add_task_to_execute_queue() handles the
+ * SAM Task Attribute emulation if enabled
+ */
+ __transport_add_task_to_execute_queue(task, task_prev, dev);
+ atomic_set(&task->task_execute_queue, 1);
+ task_prev = task;
+ }
+ spin_unlock_irqrestore(&dev->execute_task_lock, flags);
+
+ return;
+}
+
+/* transport_get_task_from_execute_queue():
+ *
+ * Called with dev->execute_task_lock held.
+ */
+static struct se_task *
+transport_get_task_from_execute_queue(struct se_device *dev)
+{
+ struct se_task *task;
+
+ if (list_empty(&dev->execute_task_list))
+ return NULL;
+
+ list_for_each_entry(task, &dev->execute_task_list, t_execute_list)
+ break;
+
+ list_del(&task->t_execute_list);
+ atomic_dec(&dev->execute_tasks);
+
+ return task;
+}
+
+/* transport_remove_task_from_execute_queue():
+ *
+ *
+ */
+static void transport_remove_task_from_execute_queue(
+ struct se_task *task,
+ struct se_device *dev)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->execute_task_lock, flags);
+ list_del(&task->t_execute_list);
+ atomic_dec(&dev->execute_tasks);
+ spin_unlock_irqrestore(&dev->execute_task_lock, flags);
+}
+
+unsigned char *transport_dump_cmd_direction(struct se_cmd *cmd)
+{
+ switch (cmd->data_direction) {
+ case DMA_NONE:
+ return "NONE";
+ case DMA_FROM_DEVICE:
+ return "READ";
+ case DMA_TO_DEVICE:
+ return "WRITE";
+ case DMA_BIDIRECTIONAL:
+ return "BIDI";
+ default:
+ break;
+ }
+
+ return "UNKNOWN";
+}
+
+void transport_dump_dev_state(
+ struct se_device *dev,
+ char *b,
+ int *bl)
+{
+ *bl += sprintf(b + *bl, "Status: ");
+ switch (dev->dev_status) {
+ case TRANSPORT_DEVICE_ACTIVATED:
+ *bl += sprintf(b + *bl, "ACTIVATED");
+ break;
+ case TRANSPORT_DEVICE_DEACTIVATED:
+ *bl += sprintf(b + *bl, "DEACTIVATED");
+ break;
+ case TRANSPORT_DEVICE_SHUTDOWN:
+ *bl += sprintf(b + *bl, "SHUTDOWN");
+ break;
+ case TRANSPORT_DEVICE_OFFLINE_ACTIVATED:
+ case TRANSPORT_DEVICE_OFFLINE_DEACTIVATED:
+ *bl += sprintf(b + *bl, "OFFLINE");
+ break;
+ default:
+ *bl += sprintf(b + *bl, "UNKNOWN=%d", dev->dev_status);
+ break;
+ }
+
+ *bl += sprintf(b + *bl, " Execute/Left/Max Queue Depth: %d/%d/%d",
+ atomic_read(&dev->execute_tasks), atomic_read(&dev->depth_left),
+ dev->queue_depth);
+ *bl += sprintf(b + *bl, " SectorSize: %u MaxSectors: %u\n",
+ DEV_ATTRIB(dev)->block_size, DEV_ATTRIB(dev)->max_sectors);
+ *bl += sprintf(b + *bl, " ");
+}
+
+/* transport_release_all_cmds():
+ *
+ *
+ */
+static void transport_release_all_cmds(struct se_device *dev)
+{
+ struct se_cmd *cmd = NULL;
+ struct se_queue_req *qr = NULL, *qr_p = NULL;
+ int bug_out = 0, t_state;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->dev_queue_obj->cmd_queue_lock, flags);
+ list_for_each_entry_safe(qr, qr_p, &dev->dev_queue_obj->qobj_list,
+ qr_list) {
+
+ cmd = (struct se_cmd *)qr->cmd;
+ t_state = qr->state;
+ list_del(&qr->qr_list);
+ kfree(qr);
+ spin_unlock_irqrestore(&dev->dev_queue_obj->cmd_queue_lock,
+ flags);
+
+ printk(KERN_ERR "Releasing ITT: 0x%08x, i_state: %u,"
+ " t_state: %u directly\n",
+ CMD_TFO(cmd)->get_task_tag(cmd),
+ CMD_TFO(cmd)->get_cmd_state(cmd), t_state);
+
+ transport_release_fe_cmd(cmd);
+ bug_out = 1;
+
+ spin_lock_irqsave(&dev->dev_queue_obj->cmd_queue_lock, flags);
+ }
+ spin_unlock_irqrestore(&dev->dev_queue_obj->cmd_queue_lock, flags);
+#if 0
+ if (bug_out)
+ BUG();
+#endif
+}
+
+void transport_dump_vpd_proto_id(
+ struct t10_vpd *vpd,
+ unsigned char *p_buf,
+ int p_buf_len)
+{
+ unsigned char buf[VPD_TMP_BUF_SIZE];
+ int len;
+
+ memset(buf, 0, VPD_TMP_BUF_SIZE);
+ len = sprintf(buf, "T10 VPD Protocol Identifier: ");
+
+ switch (vpd->protocol_identifier) {
+ case 0x00:
+ sprintf(buf+len, "Fibre Channel\n");
+ break;
+ case 0x10:
+ sprintf(buf+len, "Parallel SCSI\n");
+ break;
+ case 0x20:
+ sprintf(buf+len, "SSA\n");
+ break;
+ case 0x30:
+ sprintf(buf+len, "IEEE 1394\n");
+ break;
+ case 0x40:
+ sprintf(buf+len, "SCSI Remote Direct Memory Access"
+ " Protocol\n");
+ break;
+ case 0x50:
+ sprintf(buf+len, "Internet SCSI (iSCSI)\n");
+ break;
+ case 0x60:
+ sprintf(buf+len, "SAS Serial SCSI Protocol\n");
+ break;
+ case 0x70:
+ sprintf(buf+len, "Automation/Drive Interface Transport"
+ " Protocol\n");
+ break;
+ case 0x80:
+ sprintf(buf+len, "AT Attachment Interface ATA/ATAPI\n");
+ break;
+ default:
+ sprintf(buf+len, "Unknown 0x%02x\n",
+ vpd->protocol_identifier);
+ break;
+ }
+
+ if (p_buf)
+ strncpy(p_buf, buf, p_buf_len);
+ else
+ printk(KERN_INFO "%s", buf);
+}
+
+void
+transport_set_vpd_proto_id(struct t10_vpd *vpd, unsigned char *page_83)
+{
+ /*
+ * Check if the Protocol Identifier Valid (PIV) bit is set..
+ *
+ * from spc3r23.pdf section 7.5.1
+ */
+ if (page_83[1] & 0x80) {
+ vpd->protocol_identifier = (page_83[0] & 0xf0);
+ vpd->protocol_identifier_set = 1;
+ transport_dump_vpd_proto_id(vpd, NULL, 0);
+ }
+}
+EXPORT_SYMBOL(transport_set_vpd_proto_id);
+
+int transport_dump_vpd_assoc(
+ struct t10_vpd *vpd,
+ unsigned char *p_buf,
+ int p_buf_len)
+{
+ unsigned char buf[VPD_TMP_BUF_SIZE];
+ int ret = 0, len;
+
+ memset(buf, 0, VPD_TMP_BUF_SIZE);
+ len = sprintf(buf, "T10 VPD Identifier Association: ");
+
+ switch (vpd->association) {
+ case 0x00:
+ sprintf(buf+len, "addressed logical unit\n");
+ break;
+ case 0x10:
+ sprintf(buf+len, "target port\n");
+ break;
+ case 0x20:
+ sprintf(buf+len, "SCSI target device\n");
+ break;
+ default:
+ sprintf(buf+len, "Unknown 0x%02x\n", vpd->association);
+ ret = -1;
+ break;
+ }
+
+ if (p_buf)
+ strncpy(p_buf, buf, p_buf_len);
+ else
+ printk("%s", buf);
+
+ return ret;
+}
+
+int transport_set_vpd_assoc(struct t10_vpd *vpd, unsigned char *page_83)
+{
+ /*
+ * The VPD identification association..
+ *
+ * from spc3r23.pdf Section 7.6.3.1 Table 297
+ */
+ vpd->association = (page_83[1] & 0x30);
+ return transport_dump_vpd_assoc(vpd, NULL, 0);
+}
+EXPORT_SYMBOL(transport_set_vpd_assoc);
+
+int transport_dump_vpd_ident_type(
+ struct t10_vpd *vpd,
+ unsigned char *p_buf,
+ int p_buf_len)
+{
+ unsigned char buf[VPD_TMP_BUF_SIZE];
+ int ret = 0, len;
+
+ memset(buf, 0, VPD_TMP_BUF_SIZE);
+ len = sprintf(buf, "T10 VPD Identifier Type: ");
+
+ switch (vpd->device_identifier_type) {
+ case 0x00:
+ sprintf(buf+len, "Vendor specific\n");
+ break;
+ case 0x01:
+ sprintf(buf+len, "T10 Vendor ID based\n");
+ break;
+ case 0x02:
+ sprintf(buf+len, "EUI-64 based\n");
+ break;
+ case 0x03:
+ sprintf(buf+len, "NAA\n");
+ break;
+ case 0x04:
+ sprintf(buf+len, "Relative target port identifier\n");
+ break;
+ case 0x08:
+ sprintf(buf+len, "SCSI name string\n");
+ break;
+ default:
+ sprintf(buf+len, "Unsupported: 0x%02x\n",
+ vpd->device_identifier_type);
+ ret = -1;
+ break;
+ }
+
+ if (p_buf)
+ strncpy(p_buf, buf, p_buf_len);
+ else
+ printk("%s", buf);
+
+ return ret;
+}
+
+int transport_set_vpd_ident_type(struct t10_vpd *vpd, unsigned char *page_83)
+{
+ /*
+ * The VPD identifier type..
+ *
+ * from spc3r23.pdf Section 7.6.3.1 Table 298
+ */
+ vpd->device_identifier_type = (page_83[1] & 0x0f);
+ return transport_dump_vpd_ident_type(vpd, NULL, 0);
+}
+EXPORT_SYMBOL(transport_set_vpd_ident_type);
+
+int transport_dump_vpd_ident(
+ struct t10_vpd *vpd,
+ unsigned char *p_buf,
+ int p_buf_len)
+{
+ unsigned char buf[VPD_TMP_BUF_SIZE];
+ int ret = 0;
+
+ memset(buf, 0, VPD_TMP_BUF_SIZE);
+
+ switch (vpd->device_identifier_code_set) {
+ case 0x01: /* Binary */
+ sprintf(buf, "T10 VPD Binary Device Identifier: %s\n",
+ &vpd->device_identifier[0]);
+ break;
+ case 0x02: /* ASCII */
+ sprintf(buf, "T10 VPD ASCII Device Identifier: %s\n",
+ &vpd->device_identifier[0]);
+ break;
+ case 0x03: /* UTF-8 */
+ sprintf(buf, "T10 VPD UTF-8 Device Identifier: %s\n",
+ &vpd->device_identifier[0]);
+ break;
+ default:
+ sprintf(buf, "T10 VPD Device Identifier encoding unsupported:"
+ " 0x%02x", vpd->device_identifier_code_set);
+ ret = -1;
+ break;
+ }
+
+ if (p_buf)
+ strncpy(p_buf, buf, p_buf_len);
+ else
+ printk("%s", buf);
+
+ return ret;
+}
+
+int
+transport_set_vpd_ident(struct t10_vpd *vpd, unsigned char *page_83)
+{
+ static const char hex_str[] = "0123456789abcdef";
+ int j = 0, i = 4; /* offset to start of the identifer */
+
+ /*
+ * The VPD Code Set (encoding)
+ *
+ * from spc3r23.pdf Section 7.6.3.1 Table 296
+ */
+ vpd->device_identifier_code_set = (page_83[0] & 0x0f);
+ switch (vpd->device_identifier_code_set) {
+ case 0x01: /* Binary */
+ vpd->device_identifier[j++] =
+ hex_str[vpd->device_identifier_type];
+ while (i < (4 + page_83[3])) {
+ vpd->device_identifier[j++] =
+ hex_str[(page_83[i] & 0xf0) >> 4];
+ vpd->device_identifier[j++] =
+ hex_str[page_83[i] & 0x0f];
+ i++;
+ }
+ break;
+ case 0x02: /* ASCII */
+ case 0x03: /* UTF-8 */
+ while (i < (4 + page_83[3]))
+ vpd->device_identifier[j++] = page_83[i++];
+ break;
+ default:
+ break;
+ }
+
+ return transport_dump_vpd_ident(vpd, NULL, 0);
+}
+EXPORT_SYMBOL(transport_set_vpd_ident);
+
+static void core_setup_task_attr_emulation(struct se_device *dev)
+{
+ /*
+ * If this device is from Target_Core_Mod/pSCSI, disable the
+ * SAM Task Attribute emulation.
+ *
+ * This is currently not available in upsream Linux/SCSI Target
+ * mode code, and is assumed to be disabled while using TCM/pSCSI.
+ */
+ if (TRANSPORT(dev)->transport_type == TRANSPORT_PLUGIN_PHBA_PDEV) {
+ dev->dev_task_attr_type = SAM_TASK_ATTR_PASSTHROUGH;
+ return;
+ }
+
+ dev->dev_task_attr_type = SAM_TASK_ATTR_EMULATED;
+ DEBUG_STA("%s: Using SAM_TASK_ATTR_EMULATED for SPC: 0x%02x"
+ " device\n", TRANSPORT(dev)->name,
+ TRANSPORT(dev)->get_device_rev(dev));
+}
+
+static void scsi_dump_inquiry(struct se_device *dev)
+{
+ struct t10_wwn *wwn = DEV_T10_WWN(dev);
+ int i, device_type;
+ /*
+ * Print Linux/SCSI style INQUIRY formatting to the kernel ring buffer
+ */
+ printk(" Vendor: ");
+ for (i = 0; i < 8; i++)
+ if (wwn->vendor[i] >= 0x20)
+ printk("%c", wwn->vendor[i]);
+ else
+ printk(" ");
+
+ printk(" Model: ");
+ for (i = 0; i < 16; i++)
+ if (wwn->model[i] >= 0x20)
+ printk("%c", wwn->model[i]);
+ else
+ printk(" ");
+
+ printk(" Revision: ");
+ for (i = 0; i < 4; i++)
+ if (wwn->revision[i] >= 0x20)
+ printk("%c", wwn->revision[i]);
+ else
+ printk(" ");
+
+ printk("\n");
+
+ device_type = TRANSPORT(dev)->get_device_type(dev);
+ printk(" Type: %s ", scsi_device_type(device_type));
+ printk(" ANSI SCSI revision: %02x\n",
+ TRANSPORT(dev)->get_device_rev(dev));
+}
+
+struct se_device *transport_add_device_to_core_hba(
+ struct se_hba *hba,
+ struct se_subsystem_api *transport,
+ struct se_subsystem_dev *se_dev,
+ u32 device_flags,
+ void *transport_dev,
+ struct se_dev_limits *dev_limits,
+ const char *inquiry_prod,
+ const char *inquiry_rev)
+{
+ int ret = 0, force_pt;
+ struct se_device *dev;
+
+ dev = kzalloc(sizeof(struct se_device), GFP_KERNEL);
+ if (!(dev)) {
+ printk(KERN_ERR "Unable to allocate memory for se_dev_t\n");
+ return NULL;
+ }
+ dev->dev_queue_obj = kzalloc(sizeof(struct se_queue_obj), GFP_KERNEL);
+ if (!(dev->dev_queue_obj)) {
+ printk(KERN_ERR "Unable to allocate memory for"
+ " dev->dev_queue_obj\n");
+ kfree(dev);
+ return NULL;
+ }
+ transport_init_queue_obj(dev->dev_queue_obj);
+
+ dev->dev_status_queue_obj = kzalloc(sizeof(struct se_queue_obj),
+ GFP_KERNEL);
+ if (!(dev->dev_status_queue_obj)) {
+ printk(KERN_ERR "Unable to allocate memory for"
+ " dev->dev_status_queue_obj\n");
+ kfree(dev->dev_queue_obj);
+ kfree(dev);
+ return NULL;
+ }
+ transport_init_queue_obj(dev->dev_status_queue_obj);
+
+ dev->dev_flags = device_flags;
+ dev->dev_status |= TRANSPORT_DEVICE_DEACTIVATED;
+ dev->dev_ptr = (void *) transport_dev;
+ dev->se_hba = hba;
+ dev->se_sub_dev = se_dev;
+ dev->transport = transport;
+ atomic_set(&dev->active_cmds, 0);
+ INIT_LIST_HEAD(&dev->dev_list);
+ INIT_LIST_HEAD(&dev->dev_sep_list);
+ INIT_LIST_HEAD(&dev->dev_tmr_list);
+ INIT_LIST_HEAD(&dev->execute_task_list);
+ INIT_LIST_HEAD(&dev->delayed_cmd_list);
+ INIT_LIST_HEAD(&dev->ordered_cmd_list);
+ INIT_LIST_HEAD(&dev->state_task_list);
+ spin_lock_init(&dev->execute_task_lock);
+ spin_lock_init(&dev->delayed_cmd_lock);
+ spin_lock_init(&dev->ordered_cmd_lock);
+ spin_lock_init(&dev->state_task_lock);
+ spin_lock_init(&dev->dev_alua_lock);
+ spin_lock_init(&dev->dev_reservation_lock);
+ spin_lock_init(&dev->dev_status_lock);
+ spin_lock_init(&dev->dev_status_thr_lock);
+ spin_lock_init(&dev->se_port_lock);
+ spin_lock_init(&dev->se_tmr_lock);
+
+ dev->queue_depth = dev_limits->queue_depth;
+ atomic_set(&dev->depth_left, dev->queue_depth);
+ atomic_set(&dev->dev_ordered_id, 0);
+
+ se_dev_set_default_attribs(dev, dev_limits);
+
+ dev->dev_index = scsi_get_new_index(SCSI_DEVICE_INDEX);
+ dev->creation_time = get_jiffies_64();
+ spin_lock_init(&dev->stats_lock);
+
+ spin_lock(&hba->device_lock);
+ list_add_tail(&dev->dev_list, &hba->hba_dev_list);
+ hba->dev_count++;
+ spin_unlock(&hba->device_lock);
+ /*
+ * Setup the SAM Task Attribute emulation for struct se_device
+ */
+ core_setup_task_attr_emulation(dev);
+ /*
+ * Force PR and ALUA passthrough emulation with internal object use.
+ */
+ force_pt = (hba->hba_flags & HBA_FLAGS_INTERNAL_USE);
+ /*
+ * Setup the Reservations infrastructure for struct se_device
+ */
+ core_setup_reservations(dev, force_pt);
+ /*
+ * Setup the Asymmetric Logical Unit Assignment for struct se_device
+ */
+ if (core_setup_alua(dev, force_pt) < 0)
+ goto out;
+
+ /*
+ * Startup the struct se_device processing thread
+ */
+ dev->process_thread = kthread_run(transport_processing_thread, dev,
+ "LIO_%s", TRANSPORT(dev)->name);
+ if (IS_ERR(dev->process_thread)) {
+ printk(KERN_ERR "Unable to create kthread: LIO_%s\n",
+ TRANSPORT(dev)->name);
+ goto out;
+ }
+
+ /*
+ * Preload the initial INQUIRY const values if we are doing
+ * anything virtual (IBLOCK, FILEIO, RAMDISK), but not for TCM/pSCSI
+ * passthrough because this is being provided by the backend LLD.
+ * This is required so that transport_get_inquiry() copies these
+ * originals once back into DEV_T10_WWN(dev) for the virtual device
+ * setup.
+ */
+ if (TRANSPORT(dev)->transport_type != TRANSPORT_PLUGIN_PHBA_PDEV) {
+ if (!(inquiry_prod) || !(inquiry_prod)) {
+ printk(KERN_ERR "All non TCM/pSCSI plugins require"
+ " INQUIRY consts\n");
+ goto out;
+ }
+
+ strncpy(&DEV_T10_WWN(dev)->vendor[0], "LIO-ORG", 8);
+ strncpy(&DEV_T10_WWN(dev)->model[0], inquiry_prod, 16);
+ strncpy(&DEV_T10_WWN(dev)->revision[0], inquiry_rev, 4);
+ }
+ scsi_dump_inquiry(dev);
+
+out:
+ if (!ret)
+ return dev;
+ kthread_stop(dev->process_thread);
+
+ spin_lock(&hba->device_lock);
+ list_del(&dev->dev_list);
+ hba->dev_count--;
+ spin_unlock(&hba->device_lock);
+
+ se_release_vpd_for_dev(dev);
+
+ kfree(dev->dev_status_queue_obj);
+ kfree(dev->dev_queue_obj);
+ kfree(dev);
+
+ return NULL;
+}
+EXPORT_SYMBOL(transport_add_device_to_core_hba);
+
+/* transport_generic_prepare_cdb():
+ *
+ * Since the Initiator sees iSCSI devices as LUNs, the SCSI CDB will
+ * contain the iSCSI LUN in bits 7-5 of byte 1 as per SAM-2.
+ * The point of this is since we are mapping iSCSI LUNs to
+ * SCSI Target IDs having a non-zero LUN in the CDB will throw the
+ * devices and HBAs for a loop.
+ */
+static inline void transport_generic_prepare_cdb(
+ unsigned char *cdb)
+{
+ switch (cdb[0]) {
+ case READ_10: /* SBC - RDProtect */
+ case READ_12: /* SBC - RDProtect */
+ case READ_16: /* SBC - RDProtect */
+ case SEND_DIAGNOSTIC: /* SPC - SELF-TEST Code */
+ case VERIFY: /* SBC - VRProtect */
+ case VERIFY_16: /* SBC - VRProtect */
+ case WRITE_VERIFY: /* SBC - VRProtect */
+ case WRITE_VERIFY_12: /* SBC - VRProtect */
+ break;
+ default:
+ cdb[1] &= 0x1f; /* clear logical unit number */
+ break;
+ }
+}
+
+static struct se_task *
+transport_generic_get_task(struct se_cmd *cmd,
+ enum dma_data_direction data_direction)
+{
+ struct se_task *task;
+ struct se_device *dev = SE_DEV(cmd);
+ unsigned long flags;
+
+ task = dev->transport->alloc_task(cmd);
+ if (!task) {
+ printk(KERN_ERR "Unable to allocate struct se_task\n");
+ return NULL;
+ }
+
+ INIT_LIST_HEAD(&task->t_list);
+ INIT_LIST_HEAD(&task->t_execute_list);
+ INIT_LIST_HEAD(&task->t_state_list);
+ init_completion(&task->task_stop_comp);
+ task->task_no = T_TASK(cmd)->t_tasks_no++;
+ task->task_se_cmd = cmd;
+ task->se_dev = dev;
+ task->task_data_direction = data_direction;
+
+ spin_lock_irqsave(&T_TASK(cmd)->t_state_lock, flags);
+ list_add_tail(&task->t_list, &T_TASK(cmd)->t_task_list);
+ spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags);
+
+ return task;
+}
+
+static int transport_generic_cmd_sequencer(struct se_cmd *, unsigned char *);
+
+void transport_device_setup_cmd(struct se_cmd *cmd)
+{
+ cmd->se_dev = SE_LUN(cmd)->lun_se_dev;
+}
+EXPORT_SYMBOL(transport_device_setup_cmd);
+
+/*
+ * Used by fabric modules containing a local struct se_cmd within their
+ * fabric dependent per I/O descriptor.
+ */
+void transport_init_se_cmd(
+ struct se_cmd *cmd,
+ struct target_core_fabric_ops *tfo,
+ struct se_session *se_sess,
+ u32 data_length,
+ int data_direction,
+ int task_attr,
+ unsigned char *sense_buffer)
+{
+ INIT_LIST_HEAD(&cmd->se_lun_list);
+ INIT_LIST_HEAD(&cmd->se_delayed_list);
+ INIT_LIST_HEAD(&cmd->se_ordered_list);
+ /*
+ * Setup t_task pointer to t_task_backstore
+ */
+ cmd->t_task = &cmd->t_task_backstore;
+
+ INIT_LIST_HEAD(&T_TASK(cmd)->t_task_list);
+ init_completion(&T_TASK(cmd)->transport_lun_fe_stop_comp);
+ init_completion(&T_TASK(cmd)->transport_lun_stop_comp);
+ init_completion(&T_TASK(cmd)->t_transport_stop_comp);
+ spin_lock_init(&T_TASK(cmd)->t_state_lock);
+ atomic_set(&T_TASK(cmd)->transport_dev_active, 1);
+
+ cmd->se_tfo = tfo;
+ cmd->se_sess = se_sess;
+ cmd->data_length = data_length;
+ cmd->data_direction = data_direction;
+ cmd->sam_task_attr = task_attr;
+ cmd->sense_buffer = sense_buffer;
+}
+EXPORT_SYMBOL(transport_init_se_cmd);
+
+static int transport_check_alloc_task_attr(struct se_cmd *cmd)
+{
+ /*
+ * Check if SAM Task Attribute emulation is enabled for this
+ * struct se_device storage object
+ */
+ if (SE_DEV(cmd)->dev_task_attr_type != SAM_TASK_ATTR_EMULATED)
+ return 0;
+
+ if (cmd->sam_task_attr == TASK_ATTR_ACA) {
+ DEBUG_STA("SAM Task Attribute ACA"
+ " emulation is not supported\n");
+ return -1;
+ }
+ /*
+ * Used to determine when ORDERED commands should go from
+ * Dormant to Active status.
+ */
+ cmd->se_ordered_id = atomic_inc_return(&SE_DEV(cmd)->dev_ordered_id);
+ smp_mb__after_atomic_inc();
+ DEBUG_STA("Allocated se_ordered_id: %u for Task Attr: 0x%02x on %s\n",
+ cmd->se_ordered_id, cmd->sam_task_attr,
+ TRANSPORT(cmd->se_dev)->name);
+ return 0;
+}
+
+void transport_free_se_cmd(
+ struct se_cmd *se_cmd)
+{
+ if (se_cmd->se_tmr_req)
+ core_tmr_release_req(se_cmd->se_tmr_req);
+ /*
+ * Check and free any extended CDB buffer that was allocated
+ */
+ if (T_TASK(se_cmd)->t_task_cdb != T_TASK(se_cmd)->__t_task_cdb)
+ kfree(T_TASK(se_cmd)->t_task_cdb);
+}
+EXPORT_SYMBOL(transport_free_se_cmd);
+
+static void transport_generic_wait_for_tasks(struct se_cmd *, int, int);
+
+/* transport_generic_allocate_tasks():
+ *
+ * Called from fabric RX Thread.
+ */
+int transport_generic_allocate_tasks(
+ struct se_cmd *cmd,
+ unsigned char *cdb)
+{
+ int ret;
+
+ transport_generic_prepare_cdb(cdb);
+
+ /*
+ * This is needed for early exceptions.
+ */
+ cmd->transport_wait_for_tasks = &transport_generic_wait_for_tasks;
+
+ transport_device_setup_cmd(cmd);
+ /*
+ * Ensure that the received CDB is less than the max (252 + 8) bytes
+ * for VARIABLE_LENGTH_CMD
+ */
+ if (scsi_command_size(cdb) > SCSI_MAX_VARLEN_CDB_SIZE) {
+ printk(KERN_ERR "Received SCSI CDB with command_size: %d that"
+ " exceeds SCSI_MAX_VARLEN_CDB_SIZE: %d\n",
+ scsi_command_size(cdb), SCSI_MAX_VARLEN_CDB_SIZE);
+ return -1;
+ }
+ /*
+ * If the received CDB is larger than TCM_MAX_COMMAND_SIZE,
+ * allocate the additional extended CDB buffer now.. Otherwise
+ * setup the pointer from __t_task_cdb to t_task_cdb.
+ */
+ if (scsi_command_size(cdb) > sizeof(T_TASK(cmd)->__t_task_cdb)) {
+ T_TASK(cmd)->t_task_cdb = kzalloc(scsi_command_size(cdb),
+ GFP_KERNEL);
+ if (!(T_TASK(cmd)->t_task_cdb)) {
+ printk(KERN_ERR "Unable to allocate T_TASK(cmd)->t_task_cdb"
+ " %u > sizeof(T_TASK(cmd)->__t_task_cdb): %lu ops\n",
+ scsi_command_size(cdb),
+ (unsigned long)sizeof(T_TASK(cmd)->__t_task_cdb));
+ return -1;
+ }
+ } else
+ T_TASK(cmd)->t_task_cdb = &T_TASK(cmd)->__t_task_cdb[0];
+ /*
+ * Copy the original CDB into T_TASK(cmd).
+ */
+ memcpy(T_TASK(cmd)->t_task_cdb, cdb, scsi_command_size(cdb));
+ /*
+ * Setup the received CDB based on SCSI defined opcodes and
+ * perform unit attention, persistent reservations and ALUA
+ * checks for virtual device backends. The T_TASK(cmd)->t_task_cdb
+ * pointer is expected to be setup before we reach this point.
+ */
+ ret = transport_generic_cmd_sequencer(cmd, cdb);
+ if (ret < 0)
+ return ret;
+ /*
+ * Check for SAM Task Attribute Emulation
+ */
+ if (transport_check_alloc_task_attr(cmd) < 0) {
+ cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION;
+ cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD;
+ return -2;
+ }
+ spin_lock(&cmd->se_lun->lun_sep_lock);
+ if (cmd->se_lun->lun_sep)
+ cmd->se_lun->lun_sep->sep_stats.cmd_pdus++;
+ spin_unlock(&cmd->se_lun->lun_sep_lock);
+ return 0;
+}
+EXPORT_SYMBOL(transport_generic_allocate_tasks);
+
+/*
+ * Used by fabric module frontends not defining a TFO->new_cmd_map()
+ * to queue up a newly setup se_cmd w/ TRANSPORT_NEW_CMD statis
+ */
+int transport_generic_handle_cdb(
+ struct se_cmd *cmd)
+{
+ if (!SE_LUN(cmd)) {
+ dump_stack();
+ printk(KERN_ERR "SE_LUN(cmd) is NULL\n");
+ return -1;
+ }
+
+ transport_add_cmd_to_queue(cmd, TRANSPORT_NEW_CMD);
+ return 0;
+}
+EXPORT_SYMBOL(transport_generic_handle_cdb);
+
+/*
+ * Used by fabric module frontends defining a TFO->new_cmd_map() caller
+ * to queue up a newly setup se_cmd w/ TRANSPORT_NEW_CMD_MAP in order to
+ * complete setup in TCM process context w/ TFO->new_cmd_map().
+ */
+int transport_generic_handle_cdb_map(
+ struct se_cmd *cmd)
+{
+ if (!SE_LUN(cmd)) {
+ dump_stack();
+ printk(KERN_ERR "SE_LUN(cmd) is NULL\n");
+ return -1;
+ }
+
+ transport_add_cmd_to_queue(cmd, TRANSPORT_NEW_CMD_MAP);
+ return 0;
+}
+EXPORT_SYMBOL(transport_generic_handle_cdb_map);
+
+/* transport_generic_handle_data():
+ *
+ *
+ */
+int transport_generic_handle_data(
+ struct se_cmd *cmd)
+{
+ /*
+ * For the software fabric case, then we assume the nexus is being
+ * failed/shutdown when signals are pending from the kthread context
+ * caller, so we return a failure. For the HW target mode case running
+ * in interrupt code, the signal_pending() check is skipped.
+ */
+ if (!in_interrupt() && signal_pending(current))
+ return -1;
+ /*
+ * If the received CDB has aleady been ABORTED by the generic
+ * target engine, we now call transport_check_aborted_status()
+ * to queue any delated TASK_ABORTED status for the received CDB to the
+ * fabric module as we are expecting no futher incoming DATA OUT
+ * sequences at this point.
+ */
+ if (transport_check_aborted_status(cmd, 1) != 0)
+ return 0;
+
+ transport_add_cmd_to_queue(cmd, TRANSPORT_PROCESS_WRITE);
+ return 0;
+}
+EXPORT_SYMBOL(transport_generic_handle_data);
+
+/* transport_generic_handle_tmr():
+ *
+ *
+ */
+int transport_generic_handle_tmr(
+ struct se_cmd *cmd)
+{
+ /*
+ * This is needed for early exceptions.
+ */
+ cmd->transport_wait_for_tasks = &transport_generic_wait_for_tasks;
+ transport_device_setup_cmd(cmd);
+
+ transport_add_cmd_to_queue(cmd, TRANSPORT_PROCESS_TMR);
+ return 0;
+}
+EXPORT_SYMBOL(transport_generic_handle_tmr);
+
+static int transport_stop_tasks_for_cmd(struct se_cmd *cmd)
+{
+ struct se_task *task, *task_tmp;
+ unsigned long flags;
+ int ret = 0;
+
+ DEBUG_TS("ITT[0x%08x] - Stopping tasks\n",
+ CMD_TFO(cmd)->get_task_tag(cmd));
+
+ /*
+ * No tasks remain in the execution queue
+ */
+ spin_lock_irqsave(&T_TASK(cmd)->t_state_lock, flags);
+ list_for_each_entry_safe(task, task_tmp,
+ &T_TASK(cmd)->t_task_list, t_list) {
+ DEBUG_TS("task_no[%d] - Processing task %p\n",
+ task->task_no, task);
+ /*
+ * If the struct se_task has not been sent and is not active,
+ * remove the struct se_task from the execution queue.
+ */
+ if (!atomic_read(&task->task_sent) &&
+ !atomic_read(&task->task_active)) {
+ spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock,
+ flags);
+ transport_remove_task_from_execute_queue(task,
+ task->se_dev);
+
+ DEBUG_TS("task_no[%d] - Removed from execute queue\n",
+ task->task_no);
+ spin_lock_irqsave(&T_TASK(cmd)->t_state_lock, flags);
+ continue;
+ }
+
+ /*
+ * If the struct se_task is active, sleep until it is returned
+ * from the plugin.
+ */
+ if (atomic_read(&task->task_active)) {
+ atomic_set(&task->task_stop, 1);
+ spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock,
+ flags);
+
+ DEBUG_TS("task_no[%d] - Waiting to complete\n",
+ task->task_no);
+ wait_for_completion(&task->task_stop_comp);
+ DEBUG_TS("task_no[%d] - Stopped successfully\n",
+ task->task_no);
+
+ spin_lock_irqsave(&T_TASK(cmd)->t_state_lock, flags);
+ atomic_dec(&T_TASK(cmd)->t_task_cdbs_left);
+
+ atomic_set(&task->task_active, 0);
+ atomic_set(&task->task_stop, 0);
+ } else {
+ DEBUG_TS("task_no[%d] - Did nothing\n", task->task_no);
+ ret++;
+ }
+
+ __transport_stop_task_timer(task, &flags);
+ }
+ spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags);
+
+ return ret;
+}
+
+static void transport_failure_reset_queue_depth(struct se_device *dev)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&SE_HBA(dev)->hba_queue_lock, flags);;
+ atomic_inc(&dev->depth_left);
+ atomic_inc(&SE_HBA(dev)->left_queue_depth);
+ spin_unlock_irqrestore(&SE_HBA(dev)->hba_queue_lock, flags);
+}
+
+/*
+ * Handle SAM-esque emulation for generic transport request failures.
+ */
+static void transport_generic_request_failure(
+ struct se_cmd *cmd,
+ struct se_device *dev,
+ int complete,
+ int sc)
+{
+ DEBUG_GRF("-----[ Storage Engine Exception for cmd: %p ITT: 0x%08x"
+ " CDB: 0x%02x\n", cmd, CMD_TFO(cmd)->get_task_tag(cmd),
+ T_TASK(cmd)->t_task_cdb[0]);
+ DEBUG_GRF("-----[ i_state: %d t_state/def_t_state:"
+ " %d/%d transport_error_status: %d\n",
+ CMD_TFO(cmd)->get_cmd_state(cmd),
+ cmd->t_state, cmd->deferred_t_state,
+ cmd->transport_error_status);
+ DEBUG_GRF("-----[ t_task_cdbs: %d t_task_cdbs_left: %d"
+ " t_task_cdbs_sent: %d t_task_cdbs_ex_left: %d --"
+ " t_transport_active: %d t_transport_stop: %d"
+ " t_transport_sent: %d\n", T_TASK(cmd)->t_task_cdbs,
+ atomic_read(&T_TASK(cmd)->t_task_cdbs_left),
+ atomic_read(&T_TASK(cmd)->t_task_cdbs_sent),
+ atomic_read(&T_TASK(cmd)->t_task_cdbs_ex_left),
+ atomic_read(&T_TASK(cmd)->t_transport_active),
+ atomic_read(&T_TASK(cmd)->t_transport_stop),
+ atomic_read(&T_TASK(cmd)->t_transport_sent));
+
+ transport_stop_all_task_timers(cmd);
+
+ if (dev)
+ transport_failure_reset_queue_depth(dev);
+ /*
+ * For SAM Task Attribute emulation for failed struct se_cmd
+ */
+ if (cmd->se_dev->dev_task_attr_type == SAM_TASK_ATTR_EMULATED)
+ transport_complete_task_attr(cmd);
+
+ if (complete) {
+ transport_direct_request_timeout(cmd);
+ cmd->transport_error_status = PYX_TRANSPORT_LU_COMM_FAILURE;
+ }
+
+ switch (cmd->transport_error_status) {
+ case PYX_TRANSPORT_UNKNOWN_SAM_OPCODE:
+ cmd->scsi_sense_reason = TCM_UNSUPPORTED_SCSI_OPCODE;
+ break;
+ case PYX_TRANSPORT_REQ_TOO_MANY_SECTORS:
+ cmd->scsi_sense_reason = TCM_SECTOR_COUNT_TOO_MANY;
+ break;
+ case PYX_TRANSPORT_INVALID_CDB_FIELD:
+ cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD;
+ break;
+ case PYX_TRANSPORT_INVALID_PARAMETER_LIST:
+ cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST;
+ break;
+ case PYX_TRANSPORT_OUT_OF_MEMORY_RESOURCES:
+ if (!sc)
+ transport_new_cmd_failure(cmd);
+ /*
+ * Currently for PYX_TRANSPORT_OUT_OF_MEMORY_RESOURCES,
+ * we force this session to fall back to session
+ * recovery.
+ */
+ CMD_TFO(cmd)->fall_back_to_erl0(cmd->se_sess);
+ CMD_TFO(cmd)->stop_session(cmd->se_sess, 0, 0);
+
+ goto check_stop;
+ case PYX_TRANSPORT_LU_COMM_FAILURE:
+ case PYX_TRANSPORT_ILLEGAL_REQUEST:
+ cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
+ break;
+ case PYX_TRANSPORT_UNKNOWN_MODE_PAGE:
+ cmd->scsi_sense_reason = TCM_UNKNOWN_MODE_PAGE;
+ break;
+ case PYX_TRANSPORT_WRITE_PROTECTED:
+ cmd->scsi_sense_reason = TCM_WRITE_PROTECTED;
+ break;
+ case PYX_TRANSPORT_RESERVATION_CONFLICT:
+ /*
+ * No SENSE Data payload for this case, set SCSI Status
+ * and queue the response to $FABRIC_MOD.
+ *
+ * Uses linux/include/scsi/scsi.h SAM status codes defs
+ */
+ cmd->scsi_status = SAM_STAT_RESERVATION_CONFLICT;
+ /*
+ * For UA Interlock Code 11b, a RESERVATION CONFLICT will
+ * establish a UNIT ATTENTION with PREVIOUS RESERVATION
+ * CONFLICT STATUS.
+ *
+ * See spc4r17, section 7.4.6 Control Mode Page, Table 349
+ */
+ if (SE_SESS(cmd) &&
+ DEV_ATTRIB(cmd->se_dev)->emulate_ua_intlck_ctrl == 2)
+ core_scsi3_ua_allocate(SE_SESS(cmd)->se_node_acl,
+ cmd->orig_fe_lun, 0x2C,
+ ASCQ_2CH_PREVIOUS_RESERVATION_CONFLICT_STATUS);
+
+ CMD_TFO(cmd)->queue_status(cmd);
+ goto check_stop;
+ case PYX_TRANSPORT_USE_SENSE_REASON:
+ /*
+ * struct se_cmd->scsi_sense_reason already set
+ */
+ break;
+ default:
+ printk(KERN_ERR "Unknown transport error for CDB 0x%02x: %d\n",
+ T_TASK(cmd)->t_task_cdb[0],
+ cmd->transport_error_status);
+ cmd->scsi_sense_reason = TCM_UNSUPPORTED_SCSI_OPCODE;
+ break;
+ }
+
+ if (!sc)
+ transport_new_cmd_failure(cmd);
+ else
+ transport_send_check_condition_and_sense(cmd,
+ cmd->scsi_sense_reason, 0);
+check_stop:
+ transport_lun_remove_cmd(cmd);
+ if (!(transport_cmd_check_stop_to_fabric(cmd)))
+ ;
+}
+
+static void transport_direct_request_timeout(struct se_cmd *cmd)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&T_TASK(cmd)->t_state_lock, flags);
+ if (!(atomic_read(&T_TASK(cmd)->t_transport_timeout))) {
+ spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags);
+ return;
+ }
+ if (atomic_read(&T_TASK(cmd)->t_task_cdbs_timeout_left)) {
+ spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags);
+ return;
+ }
+
+ atomic_sub(atomic_read(&T_TASK(cmd)->t_transport_timeout),
+ &T_TASK(cmd)->t_se_count);
+ spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags);
+}
+
+static void transport_generic_request_timeout(struct se_cmd *cmd)
+{
+ unsigned long flags;
+
+ /*
+ * Reset T_TASK(cmd)->t_se_count to allow transport_generic_remove()
+ * to allow last call to free memory resources.
+ */
+ spin_lock_irqsave(&T_TASK(cmd)->t_state_lock, flags);
+ if (atomic_read(&T_TASK(cmd)->t_transport_timeout) > 1) {
+ int tmp = (atomic_read(&T_TASK(cmd)->t_transport_timeout) - 1);
+
+ atomic_sub(tmp, &T_TASK(cmd)->t_se_count);
+ }
+ spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags);
+
+ transport_generic_remove(cmd, 0, 0);
+}
+
+static int
+transport_generic_allocate_buf(struct se_cmd *cmd, u32 data_length)
+{
+ unsigned char *buf;
+
+ buf = kzalloc(data_length, GFP_KERNEL);
+ if (!(buf)) {
+ printk(KERN_ERR "Unable to allocate memory for buffer\n");
+ return -1;
+ }
+
+ T_TASK(cmd)->t_tasks_se_num = 0;
+ T_TASK(cmd)->t_task_buf = buf;
+
+ return 0;
+}
+
+static inline u32 transport_lba_21(unsigned char *cdb)
+{
+ return ((cdb[1] & 0x1f) << 16) | (cdb[2] << 8) | cdb[3];
+}
+
+static inline u32 transport_lba_32(unsigned char *cdb)
+{
+ return (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5];
+}
+
+static inline unsigned long long transport_lba_64(unsigned char *cdb)
+{
+ unsigned int __v1, __v2;
+
+ __v1 = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5];
+ __v2 = (cdb[6] << 24) | (cdb[7] << 16) | (cdb[8] << 8) | cdb[9];
+
+ return ((unsigned long long)__v2) | (unsigned long long)__v1 << 32;
+}
+
+/*
+ * For VARIABLE_LENGTH_CDB w/ 32 byte extended CDBs
+ */
+static inline unsigned long long transport_lba_64_ext(unsigned char *cdb)
+{
+ unsigned int __v1, __v2;
+
+ __v1 = (cdb[12] << 24) | (cdb[13] << 16) | (cdb[14] << 8) | cdb[15];
+ __v2 = (cdb[16] << 24) | (cdb[17] << 16) | (cdb[18] << 8) | cdb[19];
+
+ return ((unsigned long long)__v2) | (unsigned long long)__v1 << 32;
+}
+
+static void transport_set_supported_SAM_opcode(struct se_cmd *se_cmd)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&T_TASK(se_cmd)->t_state_lock, flags);
+ se_cmd->se_cmd_flags |= SCF_SUPPORTED_SAM_OPCODE;
+ spin_unlock_irqrestore(&T_TASK(se_cmd)->t_state_lock, flags);
+}
+
+/*
+ * Called from interrupt context.
+ */
+static void transport_task_timeout_handler(unsigned long data)
+{
+ struct se_task *task = (struct se_task *)data;
+ struct se_cmd *cmd = TASK_CMD(task);
+ unsigned long flags;
+
+ DEBUG_TT("transport task timeout fired! task: %p cmd: %p\n", task, cmd);
+
+ spin_lock_irqsave(&T_TASK(cmd)->t_state_lock, flags);
+ if (task->task_flags & TF_STOP) {
+ spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags);
+ return;
+ }
+ task->task_flags &= ~TF_RUNNING;
+
+ /*
+ * Determine if transport_complete_task() has already been called.
+ */
+ if (!(atomic_read(&task->task_active))) {
+ DEBUG_TT("transport task: %p cmd: %p timeout task_active"
+ " == 0\n", task, cmd);
+ spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags);
+ return;
+ }
+
+ atomic_inc(&T_TASK(cmd)->t_se_count);
+ atomic_inc(&T_TASK(cmd)->t_transport_timeout);
+ T_TASK(cmd)->t_tasks_failed = 1;
+
+ atomic_set(&task->task_timeout, 1);
+ task->task_error_status = PYX_TRANSPORT_TASK_TIMEOUT;
+ task->task_scsi_status = 1;
+
+ if (atomic_read(&task->task_stop)) {
+ DEBUG_TT("transport task: %p cmd: %p timeout task_stop"
+ " == 1\n", task, cmd);
+ spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags);
+ complete(&task->task_stop_comp);
+ return;
+ }
+
+ if (!(atomic_dec_and_test(&T_TASK(cmd)->t_task_cdbs_left))) {
+ DEBUG_TT("transport task: %p cmd: %p timeout non zero"
+ " t_task_cdbs_left\n", task, cmd);
+ spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags);
+ return;
+ }
+ DEBUG_TT("transport task: %p cmd: %p timeout ZERO t_task_cdbs_left\n",
+ task, cmd);
+
+ cmd->t_state = TRANSPORT_COMPLETE_FAILURE;
+ spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags);
+
+ transport_add_cmd_to_queue(cmd, TRANSPORT_COMPLETE_FAILURE);
+}
+
+/*
+ * Called with T_TASK(cmd)->t_state_lock held.
+ */
+static void transport_start_task_timer(struct se_task *task)
+{
+ struct se_device *dev = task->se_dev;
+ int timeout;
+
+ if (task->task_flags & TF_RUNNING)
+ return;
+ /*
+ * If the task_timeout is disabled, exit now.
+ */
+ timeout = DEV_ATTRIB(dev)->task_timeout;
+ if (!(timeout))
+ return;
+
+ init_timer(&task->task_timer);
+ task->task_timer.expires = (get_jiffies_64() + timeout * HZ);
+ task->task_timer.data = (unsigned long) task;
+ task->task_timer.function = transport_task_timeout_handler;
+
+ task->task_flags |= TF_RUNNING;
+ add_timer(&task->task_timer);
+#if 0
+ printk(KERN_INFO "Starting task timer for cmd: %p task: %p seconds:"
+ " %d\n", task->task_se_cmd, task, timeout);
+#endif
+}
+
+/*
+ * Called with spin_lock_irq(&T_TASK(cmd)->t_state_lock) held.
+ */
+void __transport_stop_task_timer(struct se_task *task, unsigned long *flags)
+{
+ struct se_cmd *cmd = TASK_CMD(task);
+
+ if (!(task->task_flags & TF_RUNNING))
+ return;
+
+ task->task_flags |= TF_STOP;
+ spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, *flags);
+
+ del_timer_sync(&task->task_timer);
+
+ spin_lock_irqsave(&T_TASK(cmd)->t_state_lock, *flags);
+ task->task_flags &= ~TF_RUNNING;
+ task->task_flags &= ~TF_STOP;
+}
+
+static void transport_stop_all_task_timers(struct se_cmd *cmd)
+{
+ struct se_task *task = NULL, *task_tmp;
+ unsigned long flags;
+
+ spin_lock_irqsave(&T_TASK(cmd)->t_state_lock, flags);
+ list_for_each_entry_safe(task, task_tmp,
+ &T_TASK(cmd)->t_task_list, t_list)
+ __transport_stop_task_timer(task, &flags);
+ spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags);
+}
+
+static inline int transport_tcq_window_closed(struct se_device *dev)
+{
+ if (dev->dev_tcq_window_closed++ <
+ PYX_TRANSPORT_WINDOW_CLOSED_THRESHOLD) {
+ msleep(PYX_TRANSPORT_WINDOW_CLOSED_WAIT_SHORT);
+ } else
+ msleep(PYX_TRANSPORT_WINDOW_CLOSED_WAIT_LONG);
+
+ wake_up_interruptible(&dev->dev_queue_obj->thread_wq);
+ return 0;
+}
+
+/*
+ * Called from Fabric Module context from transport_execute_tasks()
+ *
+ * The return of this function determins if the tasks from struct se_cmd
+ * get added to the execution queue in transport_execute_tasks(),
+ * or are added to the delayed or ordered lists here.
+ */
+static inline int transport_execute_task_attr(struct se_cmd *cmd)
+{
+ if (SE_DEV(cmd)->dev_task_attr_type != SAM_TASK_ATTR_EMULATED)
+ return 1;
+ /*
+ * Check for the existance of HEAD_OF_QUEUE, and if true return 1
+ * to allow the passed struct se_cmd list of tasks to the front of the list.
+ */
+ if (cmd->sam_task_attr == TASK_ATTR_HOQ) {
+ atomic_inc(&SE_DEV(cmd)->dev_hoq_count);
+ smp_mb__after_atomic_inc();
+ DEBUG_STA("Added HEAD_OF_QUEUE for CDB:"
+ " 0x%02x, se_ordered_id: %u\n",
+ T_TASK(cmd)->t_task_cdb[0],
+ cmd->se_ordered_id);
+ return 1;
+ } else if (cmd->sam_task_attr == TASK_ATTR_ORDERED) {
+ spin_lock(&SE_DEV(cmd)->ordered_cmd_lock);
+ list_add_tail(&cmd->se_ordered_list,
+ &SE_DEV(cmd)->ordered_cmd_list);
+ spin_unlock(&SE_DEV(cmd)->ordered_cmd_lock);
+
+ atomic_inc(&SE_DEV(cmd)->dev_ordered_sync);
+ smp_mb__after_atomic_inc();
+
+ DEBUG_STA("Added ORDERED for CDB: 0x%02x to ordered"
+ " list, se_ordered_id: %u\n",
+ T_TASK(cmd)->t_task_cdb[0],
+ cmd->se_ordered_id);
+ /*
+ * Add ORDERED command to tail of execution queue if
+ * no other older commands exist that need to be
+ * completed first.
+ */
+ if (!(atomic_read(&SE_DEV(cmd)->simple_cmds)))
+ return 1;
+ } else {
+ /*
+ * For SIMPLE and UNTAGGED Task Attribute commands
+ */
+ atomic_inc(&SE_DEV(cmd)->simple_cmds);
+ smp_mb__after_atomic_inc();
+ }
+ /*
+ * Otherwise if one or more outstanding ORDERED task attribute exist,
+ * add the dormant task(s) built for the passed struct se_cmd to the
+ * execution queue and become in Active state for this struct se_device.
+ */
+ if (atomic_read(&SE_DEV(cmd)->dev_ordered_sync) != 0) {
+ /*
+ * Otherwise, add cmd w/ tasks to delayed cmd queue that
+ * will be drained upon competion of HEAD_OF_QUEUE task.
+ */
+ spin_lock(&SE_DEV(cmd)->delayed_cmd_lock);
+ cmd->se_cmd_flags |= SCF_DELAYED_CMD_FROM_SAM_ATTR;
+ list_add_tail(&cmd->se_delayed_list,
+ &SE_DEV(cmd)->delayed_cmd_list);
+ spin_unlock(&SE_DEV(cmd)->delayed_cmd_lock);
+
+ DEBUG_STA("Added CDB: 0x%02x Task Attr: 0x%02x to"
+ " delayed CMD list, se_ordered_id: %u\n",
+ T_TASK(cmd)->t_task_cdb[0], cmd->sam_task_attr,
+ cmd->se_ordered_id);
+ /*
+ * Return zero to let transport_execute_tasks() know
+ * not to add the delayed tasks to the execution list.
+ */
+ return 0;
+ }
+ /*
+ * Otherwise, no ORDERED task attributes exist..
+ */
+ return 1;
+}
+
+/*
+ * Called from fabric module context in transport_generic_new_cmd() and
+ * transport_generic_process_write()
+ */
+static int transport_execute_tasks(struct se_cmd *cmd)
+{
+ int add_tasks;
+
+ if (!(cmd->se_cmd_flags & SCF_SE_DISABLE_ONLINE_CHECK)) {
+ if (se_dev_check_online(cmd->se_orig_obj_ptr) != 0) {
+ cmd->transport_error_status =
+ PYX_TRANSPORT_LU_COMM_FAILURE;
+ transport_generic_request_failure(cmd, NULL, 0, 1);
+ return 0;
+ }
+ }
+ /*
+ * Call transport_cmd_check_stop() to see if a fabric exception
+ * has occured that prevents execution.
+ */
+ if (!(transport_cmd_check_stop(cmd, 0, TRANSPORT_PROCESSING))) {
+ /*
+ * Check for SAM Task Attribute emulation and HEAD_OF_QUEUE
+ * attribute for the tasks of the received struct se_cmd CDB
+ */
+ add_tasks = transport_execute_task_attr(cmd);
+ if (add_tasks == 0)
+ goto execute_tasks;
+ /*
+ * This calls transport_add_tasks_from_cmd() to handle
+ * HEAD_OF_QUEUE ordering for SAM Task Attribute emulation
+ * (if enabled) in __transport_add_task_to_execute_queue() and
+ * transport_add_task_check_sam_attr().
+ */
+ transport_add_tasks_from_cmd(cmd);
+ }
+ /*
+ * Kick the execution queue for the cmd associated struct se_device
+ * storage object.
+ */
+execute_tasks:
+ __transport_execute_tasks(SE_DEV(cmd));
+ return 0;
+}
+
+/*
+ * Called to check struct se_device tcq depth window, and once open pull struct se_task
+ * from struct se_device->execute_task_list and
+ *
+ * Called from transport_processing_thread()
+ */
+static int __transport_execute_tasks(struct se_device *dev)
+{
+ int error;
+ struct se_cmd *cmd = NULL;
+ struct se_task *task;
+ unsigned long flags;
+
+ /*
+ * Check if there is enough room in the device and HBA queue to send
+ * struct se_transport_task's to the selected transport.
+ */
+check_depth:
+ spin_lock_irqsave(&SE_HBA(dev)->hba_queue_lock, flags);
+ if (!(atomic_read(&dev->depth_left)) ||
+ !(atomic_read(&SE_HBA(dev)->left_queue_depth))) {
+ spin_unlock_irqrestore(&SE_HBA(dev)->hba_queue_lock, flags);
+ return transport_tcq_window_closed(dev);
+ }
+ dev->dev_tcq_window_closed = 0;
+
+ spin_lock(&dev->execute_task_lock);
+ task = transport_get_task_from_execute_queue(dev);
+ spin_unlock(&dev->execute_task_lock);
+
+ if (!task) {
+ spin_unlock_irqrestore(&SE_HBA(dev)->hba_queue_lock, flags);
+ return 0;
+ }
+
+ atomic_dec(&dev->depth_left);
+ atomic_dec(&SE_HBA(dev)->left_queue_depth);
+ spin_unlock_irqrestore(&SE_HBA(dev)->hba_queue_lock, flags);
+
+ cmd = TASK_CMD(task);
+
+ spin_lock_irqsave(&T_TASK(cmd)->t_state_lock, flags);
+ atomic_set(&task->task_active, 1);
+ atomic_set(&task->task_sent, 1);
+ atomic_inc(&T_TASK(cmd)->t_task_cdbs_sent);
+
+ if (atomic_read(&T_TASK(cmd)->t_task_cdbs_sent) ==
+ T_TASK(cmd)->t_task_cdbs)
+ atomic_set(&cmd->transport_sent, 1);
+
+ transport_start_task_timer(task);
+ spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags);
+ /*
+ * The struct se_cmd->transport_emulate_cdb() function pointer is used
+ * to grab REPORT_LUNS CDBs before they hit the
+ * struct se_subsystem_api->do_task() caller below.
+ */
+ if (cmd->transport_emulate_cdb) {
+ error = cmd->transport_emulate_cdb(cmd);
+ if (error != 0) {
+ cmd->transport_error_status = error;
+ atomic_set(&task->task_active, 0);
+ atomic_set(&cmd->transport_sent, 0);
+ transport_stop_tasks_for_cmd(cmd);
+ transport_generic_request_failure(cmd, dev, 0, 1);
+ goto check_depth;
+ }
+ /*
+ * Handle the successful completion for transport_emulate_cdb()
+ * for synchronous operation, following SCF_EMULATE_CDB_ASYNC
+ * Otherwise the caller is expected to complete the task with
+ * proper status.
+ */
+ if (!(cmd->se_cmd_flags & SCF_EMULATE_CDB_ASYNC)) {
+ cmd->scsi_status = SAM_STAT_GOOD;
+ task->task_scsi_status = GOOD;
+ transport_complete_task(task, 1);
+ }
+ } else {
+ /*
+ * Currently for all virtual TCM plugins including IBLOCK, FILEIO and
+ * RAMDISK we use the internal transport_emulate_control_cdb() logic
+ * with struct se_subsystem_api callers for the primary SPC-3 TYPE_DISK
+ * LUN emulation code.
+ *
+ * For TCM/pSCSI and all other SCF_SCSI_DATA_SG_IO_CDB I/O tasks we
+ * call ->do_task() directly and let the underlying TCM subsystem plugin
+ * code handle the CDB emulation.
+ */
+ if ((TRANSPORT(dev)->transport_type != TRANSPORT_PLUGIN_PHBA_PDEV) &&
+ (!(TASK_CMD(task)->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB)))
+ error = transport_emulate_control_cdb(task);
+ else
+ error = TRANSPORT(dev)->do_task(task);
+
+ if (error != 0) {
+ cmd->transport_error_status = error;
+ atomic_set(&task->task_active, 0);
+ atomic_set(&cmd->transport_sent, 0);
+ transport_stop_tasks_for_cmd(cmd);
+ transport_generic_request_failure(cmd, dev, 0, 1);
+ }
+ }
+
+ goto check_depth;
+
+ return 0;
+}
+
+void transport_new_cmd_failure(struct se_cmd *se_cmd)
+{
+ unsigned long flags;
+ /*
+ * Any unsolicited data will get dumped for failed command inside of
+ * the fabric plugin
+ */
+ spin_lock_irqsave(&T_TASK(se_cmd)->t_state_lock, flags);
+ se_cmd->se_cmd_flags |= SCF_SE_CMD_FAILED;
+ se_cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION;
+ spin_unlock_irqrestore(&T_TASK(se_cmd)->t_state_lock, flags);
+
+ CMD_TFO(se_cmd)->new_cmd_failure(se_cmd);
+}
+
+static void transport_nop_wait_for_tasks(struct se_cmd *, int, int);
+
+static inline u32 transport_get_sectors_6(
+ unsigned char *cdb,
+ struct se_cmd *cmd,
+ int *ret)
+{
+ struct se_device *dev = SE_LUN(cmd)->lun_se_dev;
+
+ /*
+ * Assume TYPE_DISK for non struct se_device objects.
+ * Use 8-bit sector value.
+ */
+ if (!dev)
+ goto type_disk;
+
+ /*
+ * Use 24-bit allocation length for TYPE_TAPE.
+ */
+ if (TRANSPORT(dev)->get_device_type(dev) == TYPE_TAPE)
+ return (u32)(cdb[2] << 16) + (cdb[3] << 8) + cdb[4];
+
+ /*
+ * Everything else assume TYPE_DISK Sector CDB location.
+ * Use 8-bit sector value.
+ */
+type_disk:
+ return (u32)cdb[4];
+}
+
+static inline u32 transport_get_sectors_10(
+ unsigned char *cdb,
+ struct se_cmd *cmd,
+ int *ret)
+{
+ struct se_device *dev = SE_LUN(cmd)->lun_se_dev;
+
+ /*
+ * Assume TYPE_DISK for non struct se_device objects.
+ * Use 16-bit sector value.
+ */
+ if (!dev)
+ goto type_disk;
+
+ /*
+ * XXX_10 is not defined in SSC, throw an exception
+ */
+ if (TRANSPORT(dev)->get_device_type(dev) == TYPE_TAPE) {
+ *ret = -1;
+ return 0;
+ }
+
+ /*
+ * Everything else assume TYPE_DISK Sector CDB location.
+ * Use 16-bit sector value.
+ */
+type_disk:
+ return (u32)(cdb[7] << 8) + cdb[8];
+}
+
+static inline u32 transport_get_sectors_12(
+ unsigned char *cdb,
+ struct se_cmd *cmd,
+ int *ret)
+{
+ struct se_device *dev = SE_LUN(cmd)->lun_se_dev;
+
+ /*
+ * Assume TYPE_DISK for non struct se_device objects.
+ * Use 32-bit sector value.
+ */
+ if (!dev)
+ goto type_disk;
+
+ /*
+ * XXX_12 is not defined in SSC, throw an exception
+ */
+ if (TRANSPORT(dev)->get_device_type(dev) == TYPE_TAPE) {
+ *ret = -1;
+ return 0;
+ }
+
+ /*
+ * Everything else assume TYPE_DISK Sector CDB location.
+ * Use 32-bit sector value.
+ */
+type_disk:
+ return (u32)(cdb[6] << 24) + (cdb[7] << 16) + (cdb[8] << 8) + cdb[9];
+}
+
+static inline u32 transport_get_sectors_16(
+ unsigned char *cdb,
+ struct se_cmd *cmd,
+ int *ret)
+{
+ struct se_device *dev = SE_LUN(cmd)->lun_se_dev;
+
+ /*
+ * Assume TYPE_DISK for non struct se_device objects.
+ * Use 32-bit sector value.
+ */
+ if (!dev)
+ goto type_disk;
+
+ /*
+ * Use 24-bit allocation length for TYPE_TAPE.
+ */
+ if (TRANSPORT(dev)->get_device_type(dev) == TYPE_TAPE)
+ return (u32)(cdb[12] << 16) + (cdb[13] << 8) + cdb[14];
+
+type_disk:
+ return (u32)(cdb[10] << 24) + (cdb[11] << 16) +
+ (cdb[12] << 8) + cdb[13];
+}
+
+/*
+ * Used for VARIABLE_LENGTH_CDB WRITE_32 and READ_32 variants
+ */
+static inline u32 transport_get_sectors_32(
+ unsigned char *cdb,
+ struct se_cmd *cmd,
+ int *ret)
+{
+ /*
+ * Assume TYPE_DISK for non struct se_device objects.
+ * Use 32-bit sector value.
+ */
+ return (u32)(cdb[28] << 24) + (cdb[29] << 16) +
+ (cdb[30] << 8) + cdb[31];
+
+}
+
+static inline u32 transport_get_size(
+ u32 sectors,
+ unsigned char *cdb,
+ struct se_cmd *cmd)
+{
+ struct se_device *dev = SE_DEV(cmd);
+
+ if (TRANSPORT(dev)->get_device_type(dev) == TYPE_TAPE) {
+ if (cdb[1] & 1) { /* sectors */
+ return DEV_ATTRIB(dev)->block_size * sectors;
+ } else /* bytes */
+ return sectors;
+ }
+#if 0
+ printk(KERN_INFO "Returning block_size: %u, sectors: %u == %u for"
+ " %s object\n", DEV_ATTRIB(dev)->block_size, sectors,
+ DEV_ATTRIB(dev)->block_size * sectors,
+ TRANSPORT(dev)->name);
+#endif
+ return DEV_ATTRIB(dev)->block_size * sectors;
+}
+
+unsigned char transport_asciihex_to_binaryhex(unsigned char val[2])
+{
+ unsigned char result = 0;
+ /*
+ * MSB
+ */
+ if ((val[0] >= 'a') && (val[0] <= 'f'))
+ result = ((val[0] - 'a' + 10) & 0xf) << 4;
+ else
+ if ((val[0] >= 'A') && (val[0] <= 'F'))
+ result = ((val[0] - 'A' + 10) & 0xf) << 4;
+ else /* digit */
+ result = ((val[0] - '0') & 0xf) << 4;
+ /*
+ * LSB
+ */
+ if ((val[1] >= 'a') && (val[1] <= 'f'))
+ result |= ((val[1] - 'a' + 10) & 0xf);
+ else
+ if ((val[1] >= 'A') && (val[1] <= 'F'))
+ result |= ((val[1] - 'A' + 10) & 0xf);
+ else /* digit */
+ result |= ((val[1] - '0') & 0xf);
+
+ return result;
+}
+EXPORT_SYMBOL(transport_asciihex_to_binaryhex);
+
+static void transport_xor_callback(struct se_cmd *cmd)
+{
+ unsigned char *buf, *addr;
+ struct se_mem *se_mem;
+ unsigned int offset;
+ int i;
+ /*
+ * From sbc3r22.pdf section 5.48 XDWRITEREAD (10) command
+ *
+ * 1) read the specified logical block(s);
+ * 2) transfer logical blocks from the data-out buffer;
+ * 3) XOR the logical blocks transferred from the data-out buffer with
+ * the logical blocks read, storing the resulting XOR data in a buffer;
+ * 4) if the DISABLE WRITE bit is set to zero, then write the logical
+ * blocks transferred from the data-out buffer; and
+ * 5) transfer the resulting XOR data to the data-in buffer.
+ */
+ buf = kmalloc(cmd->data_length, GFP_KERNEL);
+ if (!(buf)) {
+ printk(KERN_ERR "Unable to allocate xor_callback buf\n");
+ return;
+ }
+ /*
+ * Copy the scatterlist WRITE buffer located at T_TASK(cmd)->t_mem_list
+ * into the locally allocated *buf
+ */
+ transport_memcpy_se_mem_read_contig(cmd, buf, T_TASK(cmd)->t_mem_list);
+ /*
+ * Now perform the XOR against the BIDI read memory located at
+ * T_TASK(cmd)->t_mem_bidi_list
+ */
+
+ offset = 0;
+ list_for_each_entry(se_mem, T_TASK(cmd)->t_mem_bidi_list, se_list) {
+ addr = (unsigned char *)kmap_atomic(se_mem->se_page, KM_USER0);
+ if (!(addr))
+ goto out;
+
+ for (i = 0; i < se_mem->se_len; i++)
+ *(addr + se_mem->se_off + i) ^= *(buf + offset + i);
+
+ offset += se_mem->se_len;
+ kunmap_atomic(addr, KM_USER0);
+ }
+out:
+ kfree(buf);
+}
+
+/*
+ * Used to obtain Sense Data from underlying Linux/SCSI struct scsi_cmnd
+ */
+static int transport_get_sense_data(struct se_cmd *cmd)
+{
+ unsigned char *buffer = cmd->sense_buffer, *sense_buffer = NULL;
+ struct se_device *dev;
+ struct se_task *task = NULL, *task_tmp;
+ unsigned long flags;
+ u32 offset = 0;
+
+ if (!SE_LUN(cmd)) {
+ printk(KERN_ERR "SE_LUN(cmd) is NULL\n");
+ return -1;
+ }
+ spin_lock_irqsave(&T_TASK(cmd)->t_state_lock, flags);
+ if (cmd->se_cmd_flags & SCF_SENT_CHECK_CONDITION) {
+ spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags);
+ return 0;
+ }
+
+ list_for_each_entry_safe(task, task_tmp,
+ &T_TASK(cmd)->t_task_list, t_list) {
+
+ if (!task->task_sense)
+ continue;
+
+ dev = task->se_dev;
+ if (!(dev))
+ continue;
+
+ if (!TRANSPORT(dev)->get_sense_buffer) {
+ printk(KERN_ERR "TRANSPORT(dev)->get_sense_buffer"
+ " is NULL\n");
+ continue;
+ }
+
+ sense_buffer = TRANSPORT(dev)->get_sense_buffer(task);
+ if (!(sense_buffer)) {
+ printk(KERN_ERR "ITT[0x%08x]_TASK[%d]: Unable to locate"
+ " sense buffer for task with sense\n",
+ CMD_TFO(cmd)->get_task_tag(cmd), task->task_no);
+ continue;
+ }
+ spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags);
+
+ offset = CMD_TFO(cmd)->set_fabric_sense_len(cmd,
+ TRANSPORT_SENSE_BUFFER);
+
+ memcpy((void *)&buffer[offset], (void *)sense_buffer,
+ TRANSPORT_SENSE_BUFFER);
+ cmd->scsi_status = task->task_scsi_status;
+ /* Automatically padded */
+ cmd->scsi_sense_length =
+ (TRANSPORT_SENSE_BUFFER + offset);
+
+ printk(KERN_INFO "HBA_[%u]_PLUG[%s]: Set SAM STATUS: 0x%02x"
+ " and sense\n",
+ dev->se_hba->hba_id, TRANSPORT(dev)->name,
+ cmd->scsi_status);
+ return 0;
+ }
+ spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags);
+
+ return -1;
+}
+
+static int transport_allocate_resources(struct se_cmd *cmd)
+{
+ u32 length = cmd->data_length;
+
+ if ((cmd->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB) ||
+ (cmd->se_cmd_flags & SCF_SCSI_CONTROL_SG_IO_CDB))
+ return transport_generic_get_mem(cmd, length, PAGE_SIZE);
+ else if (cmd->se_cmd_flags & SCF_SCSI_CONTROL_NONSG_IO_CDB)
+ return transport_generic_allocate_buf(cmd, length);
+ else
+ return 0;
+}
+
+static int
+transport_handle_reservation_conflict(struct se_cmd *cmd)
+{
+ cmd->transport_wait_for_tasks = &transport_nop_wait_for_tasks;
+ cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION;
+ cmd->se_cmd_flags |= SCF_SCSI_RESERVATION_CONFLICT;
+ cmd->scsi_status = SAM_STAT_RESERVATION_CONFLICT;
+ /*
+ * For UA Interlock Code 11b, a RESERVATION CONFLICT will
+ * establish a UNIT ATTENTION with PREVIOUS RESERVATION
+ * CONFLICT STATUS.
+ *
+ * See spc4r17, section 7.4.6 Control Mode Page, Table 349
+ */
+ if (SE_SESS(cmd) &&
+ DEV_ATTRIB(cmd->se_dev)->emulate_ua_intlck_ctrl == 2)
+ core_scsi3_ua_allocate(SE_SESS(cmd)->se_node_acl,
+ cmd->orig_fe_lun, 0x2C,
+ ASCQ_2CH_PREVIOUS_RESERVATION_CONFLICT_STATUS);
+ return -2;
+}
+
+/* transport_generic_cmd_sequencer():
+ *
+ * Generic Command Sequencer that should work for most DAS transport
+ * drivers.
+ *
+ * Called from transport_generic_allocate_tasks() in the $FABRIC_MOD
+ * RX Thread.
+ *
+ * FIXME: Need to support other SCSI OPCODES where as well.
+ */
+static int transport_generic_cmd_sequencer(
+ struct se_cmd *cmd,
+ unsigned char *cdb)
+{
+ struct se_device *dev = SE_DEV(cmd);
+ struct se_subsystem_dev *su_dev = dev->se_sub_dev;
+ int ret = 0, sector_ret = 0, passthrough;
+ u32 sectors = 0, size = 0, pr_reg_type = 0;
+ u16 service_action;
+ u8 alua_ascq = 0;
+ /*
+ * Check for an existing UNIT ATTENTION condition
+ */
+ if (core_scsi3_ua_check(cmd, cdb) < 0) {
+ cmd->transport_wait_for_tasks =
+ &transport_nop_wait_for_tasks;
+ cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION;
+ cmd->scsi_sense_reason = TCM_CHECK_CONDITION_UNIT_ATTENTION;
+ return -2;
+ }
+ /*
+ * Check status of Asymmetric Logical Unit Assignment port
+ */
+ ret = T10_ALUA(su_dev)->alua_state_check(cmd, cdb, &alua_ascq);
+ if (ret != 0) {
+ cmd->transport_wait_for_tasks = &transport_nop_wait_for_tasks;
+ /*
+ * Set SCSI additional sense code (ASC) to 'LUN Not Accessable';
+ * The ALUA additional sense code qualifier (ASCQ) is determined
+ * by the ALUA primary or secondary access state..
+ */
+ if (ret > 0) {
+#if 0
+ printk(KERN_INFO "[%s]: ALUA TG Port not available,"
+ " SenseKey: NOT_READY, ASC/ASCQ: 0x04/0x%02x\n",
+ CMD_TFO(cmd)->get_fabric_name(), alua_ascq);
+#endif
+ transport_set_sense_codes(cmd, 0x04, alua_ascq);
+ cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION;
+ cmd->scsi_sense_reason = TCM_CHECK_CONDITION_NOT_READY;
+ return -2;
+ }
+ goto out_invalid_cdb_field;
+ }
+ /*
+ * Check status for SPC-3 Persistent Reservations
+ */
+ if (T10_PR_OPS(su_dev)->t10_reservation_check(cmd, &pr_reg_type) != 0) {
+ if (T10_PR_OPS(su_dev)->t10_seq_non_holder(
+ cmd, cdb, pr_reg_type) != 0)
+ return transport_handle_reservation_conflict(cmd);
+ /*
+ * This means the CDB is allowed for the SCSI Initiator port
+ * when said port is *NOT* holding the legacy SPC-2 or
+ * SPC-3 Persistent Reservation.
+ */
+ }
+
+ switch (cdb[0]) {
+ case READ_6:
+ sectors = transport_get_sectors_6(cdb, cmd, &sector_ret);
+ if (sector_ret)
+ goto out_unsupported_cdb;
+ size = transport_get_size(sectors, cdb, cmd);
+ cmd->transport_split_cdb = &split_cdb_XX_6;
+ T_TASK(cmd)->t_task_lba = transport_lba_21(cdb);
+ cmd->se_cmd_flags |= SCF_SCSI_DATA_SG_IO_CDB;
+ break;
+ case READ_10:
+ sectors = transport_get_sectors_10(cdb, cmd, &sector_ret);
+ if (sector_ret)
+ goto out_unsupported_cdb;
+ size = transport_get_size(sectors, cdb, cmd);
+ cmd->transport_split_cdb = &split_cdb_XX_10;
+ T_TASK(cmd)->t_task_lba = transport_lba_32(cdb);
+ cmd->se_cmd_flags |= SCF_SCSI_DATA_SG_IO_CDB;
+ break;
+ case READ_12:
+ sectors = transport_get_sectors_12(cdb, cmd, &sector_ret);
+ if (sector_ret)
+ goto out_unsupported_cdb;
+ size = transport_get_size(sectors, cdb, cmd);
+ cmd->transport_split_cdb = &split_cdb_XX_12;
+ T_TASK(cmd)->t_task_lba = transport_lba_32(cdb);
+ cmd->se_cmd_flags |= SCF_SCSI_DATA_SG_IO_CDB;
+ break;
+ case READ_16:
+ sectors = transport_get_sectors_16(cdb, cmd, &sector_ret);
+ if (sector_ret)
+ goto out_unsupported_cdb;
+ size = transport_get_size(sectors, cdb, cmd);
+ cmd->transport_split_cdb = &split_cdb_XX_16;
+ T_TASK(cmd)->t_task_lba = transport_lba_64(cdb);
+ cmd->se_cmd_flags |= SCF_SCSI_DATA_SG_IO_CDB;
+ break;
+ case WRITE_6:
+ sectors = transport_get_sectors_6(cdb, cmd, &sector_ret);
+ if (sector_ret)
+ goto out_unsupported_cdb;
+ size = transport_get_size(sectors, cdb, cmd);
+ cmd->transport_split_cdb = &split_cdb_XX_6;
+ T_TASK(cmd)->t_task_lba = transport_lba_21(cdb);
+ cmd->se_cmd_flags |= SCF_SCSI_DATA_SG_IO_CDB;
+ break;
+ case WRITE_10:
+ sectors = transport_get_sectors_10(cdb, cmd, &sector_ret);
+ if (sector_ret)
+ goto out_unsupported_cdb;
+ size = transport_get_size(sectors, cdb, cmd);
+ cmd->transport_split_cdb = &split_cdb_XX_10;
+ T_TASK(cmd)->t_task_lba = transport_lba_32(cdb);
+ T_TASK(cmd)->t_tasks_fua = (cdb[1] & 0x8);
+ cmd->se_cmd_flags |= SCF_SCSI_DATA_SG_IO_CDB;
+ break;
+ case WRITE_12:
+ sectors = transport_get_sectors_12(cdb, cmd, &sector_ret);
+ if (sector_ret)
+ goto out_unsupported_cdb;
+ size = transport_get_size(sectors, cdb, cmd);
+ cmd->transport_split_cdb = &split_cdb_XX_12;
+ T_TASK(cmd)->t_task_lba = transport_lba_32(cdb);
+ T_TASK(cmd)->t_tasks_fua = (cdb[1] & 0x8);
+ cmd->se_cmd_flags |= SCF_SCSI_DATA_SG_IO_CDB;
+ break;
+ case WRITE_16:
+ sectors = transport_get_sectors_16(cdb, cmd, &sector_ret);
+ if (sector_ret)
+ goto out_unsupported_cdb;
+ size = transport_get_size(sectors, cdb, cmd);
+ cmd->transport_split_cdb = &split_cdb_XX_16;
+ T_TASK(cmd)->t_task_lba = transport_lba_64(cdb);
+ T_TASK(cmd)->t_tasks_fua = (cdb[1] & 0x8);
+ cmd->se_cmd_flags |= SCF_SCSI_DATA_SG_IO_CDB;
+ break;
+ case XDWRITEREAD_10:
+ if ((cmd->data_direction != DMA_TO_DEVICE) ||
+ !(T_TASK(cmd)->t_tasks_bidi))
+ goto out_invalid_cdb_field;
+ sectors = transport_get_sectors_10(cdb, cmd, &sector_ret);
+ if (sector_ret)
+ goto out_unsupported_cdb;
+ size = transport_get_size(sectors, cdb, cmd);
+ cmd->transport_split_cdb = &split_cdb_XX_10;
+ T_TASK(cmd)->t_task_lba = transport_lba_32(cdb);
+ cmd->se_cmd_flags |= SCF_SCSI_DATA_SG_IO_CDB;
+ passthrough = (TRANSPORT(dev)->transport_type ==
+ TRANSPORT_PLUGIN_PHBA_PDEV);
+ /*
+ * Skip the remaining assignments for TCM/PSCSI passthrough
+ */
+ if (passthrough)
+ break;
+ /*
+ * Setup BIDI XOR callback to be run during transport_generic_complete_ok()
+ */
+ cmd->transport_complete_callback = &transport_xor_callback;
+ T_TASK(cmd)->t_tasks_fua = (cdb[1] & 0x8);
+ break;
+ case VARIABLE_LENGTH_CMD:
+ service_action = get_unaligned_be16(&cdb[8]);
+ /*
+ * Determine if this is TCM/PSCSI device and we should disable
+ * internal emulation for this CDB.
+ */
+ passthrough = (TRANSPORT(dev)->transport_type ==
+ TRANSPORT_PLUGIN_PHBA_PDEV);
+
+ switch (service_action) {
+ case XDWRITEREAD_32:
+ sectors = transport_get_sectors_32(cdb, cmd, &sector_ret);
+ if (sector_ret)
+ goto out_unsupported_cdb;
+ size = transport_get_size(sectors, cdb, cmd);
+ /*
+ * Use WRITE_32 and READ_32 opcodes for the emulated
+ * XDWRITE_READ_32 logic.
+ */
+ cmd->transport_split_cdb = &split_cdb_XX_32;
+ T_TASK(cmd)->t_task_lba = transport_lba_64_ext(cdb);
+ cmd->se_cmd_flags |= SCF_SCSI_DATA_SG_IO_CDB;
+
+ /*
+ * Skip the remaining assignments for TCM/PSCSI passthrough
+ */
+ if (passthrough)
+ break;
+
+ /*
+ * Setup BIDI XOR callback to be run during
+ * transport_generic_complete_ok()
+ */
+ cmd->transport_complete_callback = &transport_xor_callback;
+ T_TASK(cmd)->t_tasks_fua = (cdb[10] & 0x8);
+ break;
+ case WRITE_SAME_32:
+ sectors = transport_get_sectors_32(cdb, cmd, &sector_ret);
+ if (sector_ret)
+ goto out_unsupported_cdb;
+ size = transport_get_size(sectors, cdb, cmd);
+ T_TASK(cmd)->t_task_lba = get_unaligned_be64(&cdb[12]);
+ cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
+
+ /*
+ * Skip the remaining assignments for TCM/PSCSI passthrough
+ */
+ if (passthrough)
+ break;
+
+ if ((cdb[10] & 0x04) || (cdb[10] & 0x02)) {
+ printk(KERN_ERR "WRITE_SAME PBDATA and LBDATA"
+ " bits not supported for Block Discard"
+ " Emulation\n");
+ goto out_invalid_cdb_field;
+ }
+ /*
+ * Currently for the emulated case we only accept
+ * tpws with the UNMAP=1 bit set.
+ */
+ if (!(cdb[10] & 0x08)) {
+ printk(KERN_ERR "WRITE_SAME w/o UNMAP bit not"
+ " supported for Block Discard Emulation\n");
+ goto out_invalid_cdb_field;
+ }
+ break;
+ default:
+ printk(KERN_ERR "VARIABLE_LENGTH_CMD service action"
+ " 0x%04x not supported\n", service_action);
+ goto out_unsupported_cdb;
+ }
+ break;
+ case 0xa3:
+ if (TRANSPORT(dev)->get_device_type(dev) != TYPE_ROM) {
+ /* MAINTENANCE_IN from SCC-2 */
+ /*
+ * Check for emulated MI_REPORT_TARGET_PGS.
+ */
+ if (cdb[1] == MI_REPORT_TARGET_PGS) {
+ cmd->transport_emulate_cdb =
+ (T10_ALUA(su_dev)->alua_type ==
+ SPC3_ALUA_EMULATED) ?
+ &core_emulate_report_target_port_groups :
+ NULL;
+ }
+ size = (cdb[6] << 24) | (cdb[7] << 16) |
+ (cdb[8] << 8) | cdb[9];
+ } else {
+ /* GPCMD_SEND_KEY from multi media commands */
+ size = (cdb[8] << 8) + cdb[9];
+ }
+ cmd->se_cmd_flags |= SCF_SCSI_CONTROL_NONSG_IO_CDB;
+ break;
+ case MODE_SELECT:
+ size = cdb[4];
+ cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
+ break;
+ case MODE_SELECT_10:
+ size = (cdb[7] << 8) + cdb[8];
+ cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
+ break;
+ case MODE_SENSE:
+ size = cdb[4];
+ cmd->se_cmd_flags |= SCF_SCSI_CONTROL_NONSG_IO_CDB;
+ break;
+ case MODE_SENSE_10:
+ case GPCMD_READ_BUFFER_CAPACITY:
+ case GPCMD_SEND_OPC:
+ case LOG_SELECT:
+ case LOG_SENSE:
+ size = (cdb[7] << 8) + cdb[8];
+ cmd->se_cmd_flags |= SCF_SCSI_CONTROL_NONSG_IO_CDB;
+ break;
+ case READ_BLOCK_LIMITS:
+ size = READ_BLOCK_LEN;
+ cmd->se_cmd_flags |= SCF_SCSI_CONTROL_NONSG_IO_CDB;
+ break;
+ case GPCMD_GET_CONFIGURATION:
+ case GPCMD_READ_FORMAT_CAPACITIES:
+ case GPCMD_READ_DISC_INFO:
+ case GPCMD_READ_TRACK_RZONE_INFO:
+ size = (cdb[7] << 8) + cdb[8];
+ cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
+ break;
+ case PERSISTENT_RESERVE_IN:
+ case PERSISTENT_RESERVE_OUT:
+ cmd->transport_emulate_cdb =
+ (T10_RES(su_dev)->res_type ==
+ SPC3_PERSISTENT_RESERVATIONS) ?
+ &core_scsi3_emulate_pr : NULL;
+ size = (cdb[7] << 8) + cdb[8];
+ cmd->se_cmd_flags |= SCF_SCSI_CONTROL_NONSG_IO_CDB;
+ break;
+ case GPCMD_MECHANISM_STATUS:
+ case GPCMD_READ_DVD_STRUCTURE:
+ size = (cdb[8] << 8) + cdb[9];
+ cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
+ break;
+ case READ_POSITION:
+ size = READ_POSITION_LEN;
+ cmd->se_cmd_flags |= SCF_SCSI_CONTROL_NONSG_IO_CDB;
+ break;
+ case 0xa4:
+ if (TRANSPORT(dev)->get_device_type(dev) != TYPE_ROM) {
+ /* MAINTENANCE_OUT from SCC-2
+ *
+ * Check for emulated MO_SET_TARGET_PGS.
+ */
+ if (cdb[1] == MO_SET_TARGET_PGS) {
+ cmd->transport_emulate_cdb =
+ (T10_ALUA(su_dev)->alua_type ==
+ SPC3_ALUA_EMULATED) ?
+ &core_emulate_set_target_port_groups :
+ NULL;
+ }
+
+ size = (cdb[6] << 24) | (cdb[7] << 16) |
+ (cdb[8] << 8) | cdb[9];
+ } else {
+ /* GPCMD_REPORT_KEY from multi media commands */
+ size = (cdb[8] << 8) + cdb[9];
+ }
+ cmd->se_cmd_flags |= SCF_SCSI_CONTROL_NONSG_IO_CDB;
+ break;
+ case INQUIRY:
+ size = (cdb[3] << 8) + cdb[4];
+ /*
+ * Do implict HEAD_OF_QUEUE processing for INQUIRY.
+ * See spc4r17 section 5.3
+ */
+ if (SE_DEV(cmd)->dev_task_attr_type == SAM_TASK_ATTR_EMULATED)
+ cmd->sam_task_attr = TASK_ATTR_HOQ;
+ cmd->se_cmd_flags |= SCF_SCSI_CONTROL_NONSG_IO_CDB;
+ break;
+ case READ_BUFFER:
+ size = (cdb[6] << 16) + (cdb[7] << 8) + cdb[8];
+ cmd->se_cmd_flags |= SCF_SCSI_CONTROL_NONSG_IO_CDB;
+ break;
+ case READ_CAPACITY:
+ size = READ_CAP_LEN;
+ cmd->se_cmd_flags |= SCF_SCSI_CONTROL_NONSG_IO_CDB;
+ break;
+ case READ_MEDIA_SERIAL_NUMBER:
+ case SECURITY_PROTOCOL_IN:
+ case SECURITY_PROTOCOL_OUT:
+ size = (cdb[6] << 24) | (cdb[7] << 16) | (cdb[8] << 8) | cdb[9];
+ cmd->se_cmd_flags |= SCF_SCSI_CONTROL_NONSG_IO_CDB;
+ break;
+ case SERVICE_ACTION_IN:
+ case ACCESS_CONTROL_IN:
+ case ACCESS_CONTROL_OUT:
+ case EXTENDED_COPY:
+ case READ_ATTRIBUTE:
+ case RECEIVE_COPY_RESULTS:
+ case WRITE_ATTRIBUTE:
+ size = (cdb[10] << 24) | (cdb[11] << 16) |
+ (cdb[12] << 8) | cdb[13];
+ cmd->se_cmd_flags |= SCF_SCSI_CONTROL_NONSG_IO_CDB;
+ break;
+ case RECEIVE_DIAGNOSTIC:
+ case SEND_DIAGNOSTIC:
+ size = (cdb[3] << 8) | cdb[4];
+ cmd->se_cmd_flags |= SCF_SCSI_CONTROL_NONSG_IO_CDB;
+ break;
+/* #warning FIXME: Figure out correct GPCMD_READ_CD blocksize. */
+#if 0
+ case GPCMD_READ_CD:
+ sectors = (cdb[6] << 16) + (cdb[7] << 8) + cdb[8];
+ size = (2336 * sectors);
+ cmd->se_cmd_flags |= SCF_SCSI_CONTROL_NONSG_IO_CDB;
+ break;
+#endif
+ case READ_TOC:
+ size = cdb[8];
+ cmd->se_cmd_flags |= SCF_SCSI_CONTROL_NONSG_IO_CDB;
+ break;
+ case REQUEST_SENSE:
+ size = cdb[4];
+ cmd->se_cmd_flags |= SCF_SCSI_CONTROL_NONSG_IO_CDB;
+ break;
+ case READ_ELEMENT_STATUS:
+ size = 65536 * cdb[7] + 256 * cdb[8] + cdb[9];
+ cmd->se_cmd_flags |= SCF_SCSI_CONTROL_NONSG_IO_CDB;
+ break;
+ case WRITE_BUFFER:
+ size = (cdb[6] << 16) + (cdb[7] << 8) + cdb[8];
+ cmd->se_cmd_flags |= SCF_SCSI_CONTROL_NONSG_IO_CDB;
+ break;
+ case RESERVE:
+ case RESERVE_10:
+ /*
+ * The SPC-2 RESERVE does not contain a size in the SCSI CDB.
+ * Assume the passthrough or $FABRIC_MOD will tell us about it.
+ */
+ if (cdb[0] == RESERVE_10)
+ size = (cdb[7] << 8) | cdb[8];
+ else
+ size = cmd->data_length;
+
+ /*
+ * Setup the legacy emulated handler for SPC-2 and
+ * >= SPC-3 compatible reservation handling (CRH=1)
+ * Otherwise, we assume the underlying SCSI logic is
+ * is running in SPC_PASSTHROUGH, and wants reservations
+ * emulation disabled.
+ */
+ cmd->transport_emulate_cdb =
+ (T10_RES(su_dev)->res_type !=
+ SPC_PASSTHROUGH) ?
+ &core_scsi2_emulate_crh : NULL;
+ cmd->se_cmd_flags |= SCF_SCSI_NON_DATA_CDB;
+ break;
+ case RELEASE:
+ case RELEASE_10:
+ /*
+ * The SPC-2 RELEASE does not contain a size in the SCSI CDB.
+ * Assume the passthrough or $FABRIC_MOD will tell us about it.
+ */
+ if (cdb[0] == RELEASE_10)
+ size = (cdb[7] << 8) | cdb[8];
+ else
+ size = cmd->data_length;
+
+ cmd->transport_emulate_cdb =
+ (T10_RES(su_dev)->res_type !=
+ SPC_PASSTHROUGH) ?
+ &core_scsi2_emulate_crh : NULL;
+ cmd->se_cmd_flags |= SCF_SCSI_NON_DATA_CDB;
+ break;
+ case SYNCHRONIZE_CACHE:
+ case 0x91: /* SYNCHRONIZE_CACHE_16: */
+ /*
+ * Extract LBA and range to be flushed for emulated SYNCHRONIZE_CACHE
+ */
+ if (cdb[0] == SYNCHRONIZE_CACHE) {
+ sectors = transport_get_sectors_10(cdb, cmd, &sector_ret);
+ T_TASK(cmd)->t_task_lba = transport_lba_32(cdb);
+ } else {
+ sectors = transport_get_sectors_16(cdb, cmd, &sector_ret);
+ T_TASK(cmd)->t_task_lba = transport_lba_64(cdb);
+ }
+ if (sector_ret)
+ goto out_unsupported_cdb;
+
+ size = transport_get_size(sectors, cdb, cmd);
+ cmd->se_cmd_flags |= SCF_SCSI_NON_DATA_CDB;
+
+ /*
+ * For TCM/pSCSI passthrough, skip cmd->transport_emulate_cdb()
+ */
+ if (TRANSPORT(dev)->transport_type == TRANSPORT_PLUGIN_PHBA_PDEV)
+ break;
+ /*
+ * Set SCF_EMULATE_CDB_ASYNC to ensure asynchronous operation
+ * for SYNCHRONIZE_CACHE* Immed=1 case in __transport_execute_tasks()
+ */
+ cmd->se_cmd_flags |= SCF_EMULATE_CDB_ASYNC;
+ /*
+ * Check to ensure that LBA + Range does not exceed past end of
+ * device.
+ */
+ if (transport_get_sectors(cmd) < 0)
+ goto out_invalid_cdb_field;
+ break;
+ case UNMAP:
+ size = get_unaligned_be16(&cdb[7]);
+ passthrough = (TRANSPORT(dev)->transport_type ==
+ TRANSPORT_PLUGIN_PHBA_PDEV);
+ /*
+ * Determine if the received UNMAP used to for direct passthrough
+ * into Linux/SCSI with struct request via TCM/pSCSI or we are
+ * signaling the use of internal transport_generic_unmap() emulation
+ * for UNMAP -> Linux/BLOCK disbard with TCM/IBLOCK and TCM/FILEIO
+ * subsystem plugin backstores.
+ */
+ if (!(passthrough))
+ cmd->se_cmd_flags |= SCF_EMULATE_SYNC_UNMAP;
+
+ cmd->se_cmd_flags |= SCF_SCSI_CONTROL_NONSG_IO_CDB;
+ break;
+ case WRITE_SAME_16:
+ sectors = transport_get_sectors_16(cdb, cmd, &sector_ret);
+ if (sector_ret)
+ goto out_unsupported_cdb;
+ size = transport_get_size(sectors, cdb, cmd);
+ T_TASK(cmd)->t_task_lba = get_unaligned_be16(&cdb[2]);
+ passthrough = (TRANSPORT(dev)->transport_type ==
+ TRANSPORT_PLUGIN_PHBA_PDEV);
+ /*
+ * Determine if the received WRITE_SAME_16 is used to for direct
+ * passthrough into Linux/SCSI with struct request via TCM/pSCSI
+ * or we are signaling the use of internal WRITE_SAME + UNMAP=1
+ * emulation for -> Linux/BLOCK disbard with TCM/IBLOCK and
+ * TCM/FILEIO subsystem plugin backstores.
+ */
+ if (!(passthrough)) {
+ if ((cdb[1] & 0x04) || (cdb[1] & 0x02)) {
+ printk(KERN_ERR "WRITE_SAME PBDATA and LBDATA"
+ " bits not supported for Block Discard"
+ " Emulation\n");
+ goto out_invalid_cdb_field;
+ }
+ /*
+ * Currently for the emulated case we only accept
+ * tpws with the UNMAP=1 bit set.
+ */
+ if (!(cdb[1] & 0x08)) {
+ printk(KERN_ERR "WRITE_SAME w/o UNMAP bit not "
+ " supported for Block Discard Emulation\n");
+ goto out_invalid_cdb_field;
+ }
+ }
+ cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
+ break;
+ case ALLOW_MEDIUM_REMOVAL:
+ case GPCMD_CLOSE_TRACK:
+ case ERASE:
+ case INITIALIZE_ELEMENT_STATUS:
+ case GPCMD_LOAD_UNLOAD:
+ case REZERO_UNIT:
+ case SEEK_10:
+ case GPCMD_SET_SPEED:
+ case SPACE:
+ case START_STOP:
+ case TEST_UNIT_READY:
+ case VERIFY:
+ case WRITE_FILEMARKS:
+ case MOVE_MEDIUM:
+ cmd->se_cmd_flags |= SCF_SCSI_NON_DATA_CDB;
+ break;
+ case REPORT_LUNS:
+ cmd->transport_emulate_cdb =
+ &transport_core_report_lun_response;
+ size = (cdb[6] << 24) | (cdb[7] << 16) | (cdb[8] << 8) | cdb[9];
+ /*
+ * Do implict HEAD_OF_QUEUE processing for REPORT_LUNS
+ * See spc4r17 section 5.3
+ */
+ if (SE_DEV(cmd)->dev_task_attr_type == SAM_TASK_ATTR_EMULATED)
+ cmd->sam_task_attr = TASK_ATTR_HOQ;
+ cmd->se_cmd_flags |= SCF_SCSI_CONTROL_NONSG_IO_CDB;
+ break;
+ default:
+ printk(KERN_WARNING "TARGET_CORE[%s]: Unsupported SCSI Opcode"
+ " 0x%02x, sending CHECK_CONDITION.\n",
+ CMD_TFO(cmd)->get_fabric_name(), cdb[0]);
+ cmd->transport_wait_for_tasks = &transport_nop_wait_for_tasks;
+ goto out_unsupported_cdb;
+ }
+
+ if (size != cmd->data_length) {
+ printk(KERN_WARNING "TARGET_CORE[%s]: Expected Transfer Length:"
+ " %u does not match SCSI CDB Length: %u for SAM Opcode:"
+ " 0x%02x\n", CMD_TFO(cmd)->get_fabric_name(),
+ cmd->data_length, size, cdb[0]);
+
+ cmd->cmd_spdtl = size;
+
+ if (cmd->data_direction == DMA_TO_DEVICE) {
+ printk(KERN_ERR "Rejecting underflow/overflow"
+ " WRITE data\n");
+ goto out_invalid_cdb_field;
+ }
+ /*
+ * Reject READ_* or WRITE_* with overflow/underflow for
+ * type SCF_SCSI_DATA_SG_IO_CDB.
+ */
+ if (!(ret) && (DEV_ATTRIB(dev)->block_size != 512)) {
+ printk(KERN_ERR "Failing OVERFLOW/UNDERFLOW for LBA op"
+ " CDB on non 512-byte sector setup subsystem"
+ " plugin: %s\n", TRANSPORT(dev)->name);
+ /* Returns CHECK_CONDITION + INVALID_CDB_FIELD */
+ goto out_invalid_cdb_field;
+ }
+
+ if (size > cmd->data_length) {
+ cmd->se_cmd_flags |= SCF_OVERFLOW_BIT;
+ cmd->residual_count = (size - cmd->data_length);
+ } else {
+ cmd->se_cmd_flags |= SCF_UNDERFLOW_BIT;
+ cmd->residual_count = (cmd->data_length - size);
+ }
+ cmd->data_length = size;
+ }
+
+ transport_set_supported_SAM_opcode(cmd);
+ return ret;
+
+out_unsupported_cdb:
+ cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION;
+ cmd->scsi_sense_reason = TCM_UNSUPPORTED_SCSI_OPCODE;
+ return -2;
+out_invalid_cdb_field:
+ cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION;
+ cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD;
+ return -2;
+}
+
+static inline void transport_release_tasks(struct se_cmd *);
+
+/*
+ * This function will copy a contiguous *src buffer into a destination
+ * struct scatterlist array.
+ */
+static void transport_memcpy_write_contig(
+ struct se_cmd *cmd,
+ struct scatterlist *sg_d,
+ unsigned char *src)
+{
+ u32 i = 0, length = 0, total_length = cmd->data_length;
+ void *dst;
+
+ while (total_length) {
+ length = sg_d[i].length;
+
+ if (length > total_length)
+ length = total_length;
+
+ dst = sg_virt(&sg_d[i]);
+
+ memcpy(dst, src, length);
+
+ if (!(total_length -= length))
+ return;
+
+ src += length;
+ i++;
+ }
+}
+
+/*
+ * This function will copy a struct scatterlist array *sg_s into a destination
+ * contiguous *dst buffer.
+ */
+static void transport_memcpy_read_contig(
+ struct se_cmd *cmd,
+ unsigned char *dst,
+ struct scatterlist *sg_s)
+{
+ u32 i = 0, length = 0, total_length = cmd->data_length;
+ void *src;
+
+ while (total_length) {
+ length = sg_s[i].length;
+
+ if (length > total_length)
+ length = total_length;
+
+ src = sg_virt(&sg_s[i]);
+
+ memcpy(dst, src, length);
+
+ if (!(total_length -= length))
+ return;
+
+ dst += length;
+ i++;
+ }
+}
+
+static void transport_memcpy_se_mem_read_contig(
+ struct se_cmd *cmd,
+ unsigned char *dst,
+ struct list_head *se_mem_list)
+{
+ struct se_mem *se_mem;
+ void *src;
+ u32 length = 0, total_length = cmd->data_length;
+
+ list_for_each_entry(se_mem, se_mem_list, se_list) {
+ length = se_mem->se_len;
+
+ if (length > total_length)
+ length = total_length;
+
+ src = page_address(se_mem->se_page) + se_mem->se_off;
+
+ memcpy(dst, src, length);
+
+ if (!(total_length -= length))
+ return;
+
+ dst += length;
+ }
+}
+
+/*
+ * Called from transport_generic_complete_ok() and
+ * transport_generic_request_failure() to determine which dormant/delayed
+ * and ordered cmds need to have their tasks added to the execution queue.
+ */
+static void transport_complete_task_attr(struct se_cmd *cmd)
+{
+ struct se_device *dev = SE_DEV(cmd);
+ struct se_cmd *cmd_p, *cmd_tmp;
+ int new_active_tasks = 0;
+
+ if (cmd->sam_task_attr == TASK_ATTR_SIMPLE) {
+ atomic_dec(&dev->simple_cmds);
+ smp_mb__after_atomic_dec();
+ dev->dev_cur_ordered_id++;
+ DEBUG_STA("Incremented dev->dev_cur_ordered_id: %u for"
+ " SIMPLE: %u\n", dev->dev_cur_ordered_id,
+ cmd->se_ordered_id);
+ } else if (cmd->sam_task_attr == TASK_ATTR_HOQ) {
+ atomic_dec(&dev->dev_hoq_count);
+ smp_mb__after_atomic_dec();
+ dev->dev_cur_ordered_id++;
+ DEBUG_STA("Incremented dev_cur_ordered_id: %u for"
+ " HEAD_OF_QUEUE: %u\n", dev->dev_cur_ordered_id,
+ cmd->se_ordered_id);
+ } else if (cmd->sam_task_attr == TASK_ATTR_ORDERED) {
+ spin_lock(&dev->ordered_cmd_lock);
+ list_del(&cmd->se_ordered_list);
+ atomic_dec(&dev->dev_ordered_sync);
+ smp_mb__after_atomic_dec();
+ spin_unlock(&dev->ordered_cmd_lock);
+
+ dev->dev_cur_ordered_id++;
+ DEBUG_STA("Incremented dev_cur_ordered_id: %u for ORDERED:"
+ " %u\n", dev->dev_cur_ordered_id, cmd->se_ordered_id);
+ }
+ /*
+ * Process all commands up to the last received
+ * ORDERED task attribute which requires another blocking
+ * boundary
+ */
+ spin_lock(&dev->delayed_cmd_lock);
+ list_for_each_entry_safe(cmd_p, cmd_tmp,
+ &dev->delayed_cmd_list, se_delayed_list) {
+
+ list_del(&cmd_p->se_delayed_list);
+ spin_unlock(&dev->delayed_cmd_lock);
+
+ DEBUG_STA("Calling add_tasks() for"
+ " cmd_p: 0x%02x Task Attr: 0x%02x"
+ " Dormant -> Active, se_ordered_id: %u\n",
+ T_TASK(cmd_p)->t_task_cdb[0],
+ cmd_p->sam_task_attr, cmd_p->se_ordered_id);
+
+ transport_add_tasks_from_cmd(cmd_p);
+ new_active_tasks++;
+
+ spin_lock(&dev->delayed_cmd_lock);
+ if (cmd_p->sam_task_attr == TASK_ATTR_ORDERED)
+ break;
+ }
+ spin_unlock(&dev->delayed_cmd_lock);
+ /*
+ * If new tasks have become active, wake up the transport thread
+ * to do the processing of the Active tasks.
+ */
+ if (new_active_tasks != 0)
+ wake_up_interruptible(&dev->dev_queue_obj->thread_wq);
+}
+
+static void transport_generic_complete_ok(struct se_cmd *cmd)
+{
+ int reason = 0;
+ /*
+ * Check if we need to move delayed/dormant tasks from cmds on the
+ * delayed execution list after a HEAD_OF_QUEUE or ORDERED Task
+ * Attribute.
+ */
+ if (SE_DEV(cmd)->dev_task_attr_type == SAM_TASK_ATTR_EMULATED)
+ transport_complete_task_attr(cmd);
+ /*
+ * Check if we need to retrieve a sense buffer from
+ * the struct se_cmd in question.
+ */
+ if (cmd->se_cmd_flags & SCF_TRANSPORT_TASK_SENSE) {
+ if (transport_get_sense_data(cmd) < 0)
+ reason = TCM_NON_EXISTENT_LUN;
+
+ /*
+ * Only set when an struct se_task->task_scsi_status returned
+ * a non GOOD status.
+ */
+ if (cmd->scsi_status) {
+ transport_send_check_condition_and_sense(
+ cmd, reason, 1);
+ transport_lun_remove_cmd(cmd);
+ transport_cmd_check_stop_to_fabric(cmd);
+ return;
+ }
+ }
+ /*
+ * Check for a callback, used by amoungst other things
+ * XDWRITE_READ_10 emulation.
+ */
+ if (cmd->transport_complete_callback)
+ cmd->transport_complete_callback(cmd);
+
+ switch (cmd->data_direction) {
+ case DMA_FROM_DEVICE:
+ spin_lock(&cmd->se_lun->lun_sep_lock);
+ if (SE_LUN(cmd)->lun_sep) {
+ SE_LUN(cmd)->lun_sep->sep_stats.tx_data_octets +=
+ cmd->data_length;
+ }
+ spin_unlock(&cmd->se_lun->lun_sep_lock);
+ /*
+ * If enabled by TCM fabirc module pre-registered SGL
+ * memory, perform the memcpy() from the TCM internal
+ * contigious buffer back to the original SGL.
+ */
+ if (cmd->se_cmd_flags & SCF_PASSTHROUGH_CONTIG_TO_SG)
+ transport_memcpy_write_contig(cmd,
+ T_TASK(cmd)->t_task_pt_sgl,
+ T_TASK(cmd)->t_task_buf);
+
+ CMD_TFO(cmd)->queue_data_in(cmd);
+ break;
+ case DMA_TO_DEVICE:
+ spin_lock(&cmd->se_lun->lun_sep_lock);
+ if (SE_LUN(cmd)->lun_sep) {
+ SE_LUN(cmd)->lun_sep->sep_stats.rx_data_octets +=
+ cmd->data_length;
+ }
+ spin_unlock(&cmd->se_lun->lun_sep_lock);
+ /*
+ * Check if we need to send READ payload for BIDI-COMMAND
+ */
+ if (T_TASK(cmd)->t_mem_bidi_list != NULL) {
+ spin_lock(&cmd->se_lun->lun_sep_lock);
+ if (SE_LUN(cmd)->lun_sep) {
+ SE_LUN(cmd)->lun_sep->sep_stats.tx_data_octets +=
+ cmd->data_length;
+ }
+ spin_unlock(&cmd->se_lun->lun_sep_lock);
+ CMD_TFO(cmd)->queue_data_in(cmd);
+ break;
+ }
+ /* Fall through for DMA_TO_DEVICE */
+ case DMA_NONE:
+ CMD_TFO(cmd)->queue_status(cmd);
+ break;
+ default:
+ break;
+ }
+
+ transport_lun_remove_cmd(cmd);
+ transport_cmd_check_stop_to_fabric(cmd);
+}
+
+static void transport_free_dev_tasks(struct se_cmd *cmd)
+{
+ struct se_task *task, *task_tmp;
+ unsigned long flags;
+
+ spin_lock_irqsave(&T_TASK(cmd)->t_state_lock, flags);
+ list_for_each_entry_safe(task, task_tmp,
+ &T_TASK(cmd)->t_task_list, t_list) {
+ if (atomic_read(&task->task_active))
+ continue;
+
+ kfree(task->task_sg_bidi);
+ kfree(task->task_sg);
+
+ list_del(&task->t_list);
+
+ spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags);
+ if (task->se_dev)
+ TRANSPORT(task->se_dev)->free_task(task);
+ else
+ printk(KERN_ERR "task[%u] - task->se_dev is NULL\n",
+ task->task_no);
+ spin_lock_irqsave(&T_TASK(cmd)->t_state_lock, flags);
+ }
+ spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags);
+}
+
+static inline void transport_free_pages(struct se_cmd *cmd)
+{
+ struct se_mem *se_mem, *se_mem_tmp;
+ int free_page = 1;
+
+ if (cmd->se_cmd_flags & SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC)
+ free_page = 0;
+ if (cmd->se_dev->transport->do_se_mem_map)
+ free_page = 0;
+
+ if (T_TASK(cmd)->t_task_buf) {
+ kfree(T_TASK(cmd)->t_task_buf);
+ T_TASK(cmd)->t_task_buf = NULL;
+ return;
+ }
+
+ /*
+ * Caller will handle releasing of struct se_mem.
+ */
+ if (cmd->se_cmd_flags & SCF_CMD_PASSTHROUGH_NOALLOC)
+ return;
+
+ if (!(T_TASK(cmd)->t_tasks_se_num))
+ return;
+
+ list_for_each_entry_safe(se_mem, se_mem_tmp,
+ T_TASK(cmd)->t_mem_list, se_list) {
+ /*
+ * We only release call __free_page(struct se_mem->se_page) when
+ * SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC is NOT in use,
+ */
+ if (free_page)
+ __free_page(se_mem->se_page);
+
+ list_del(&se_mem->se_list);
+ kmem_cache_free(se_mem_cache, se_mem);
+ }
+
+ if (T_TASK(cmd)->t_mem_bidi_list && T_TASK(cmd)->t_tasks_se_bidi_num) {
+ list_for_each_entry_safe(se_mem, se_mem_tmp,
+ T_TASK(cmd)->t_mem_bidi_list, se_list) {
+ /*
+ * We only release call __free_page(struct se_mem->se_page) when
+ * SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC is NOT in use,
+ */
+ if (free_page)
+ __free_page(se_mem->se_page);
+
+ list_del(&se_mem->se_list);
+ kmem_cache_free(se_mem_cache, se_mem);
+ }
+ }
+
+ kfree(T_TASK(cmd)->t_mem_bidi_list);
+ T_TASK(cmd)->t_mem_bidi_list = NULL;
+ kfree(T_TASK(cmd)->t_mem_list);
+ T_TASK(cmd)->t_mem_list = NULL;
+ T_TASK(cmd)->t_tasks_se_num = 0;
+}
+
+static inline void transport_release_tasks(struct se_cmd *cmd)
+{
+ transport_free_dev_tasks(cmd);
+}
+
+static inline int transport_dec_and_check(struct se_cmd *cmd)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&T_TASK(cmd)->t_state_lock, flags);
+ if (atomic_read(&T_TASK(cmd)->t_fe_count)) {
+ if (!(atomic_dec_and_test(&T_TASK(cmd)->t_fe_count))) {
+ spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock,
+ flags);
+ return 1;
+ }
+ }
+
+ if (atomic_read(&T_TASK(cmd)->t_se_count)) {
+ if (!(atomic_dec_and_test(&T_TASK(cmd)->t_se_count))) {
+ spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock,
+ flags);
+ return 1;
+ }
+ }
+ spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags);
+
+ return 0;
+}
+
+static void transport_release_fe_cmd(struct se_cmd *cmd)
+{
+ unsigned long flags;
+
+ if (transport_dec_and_check(cmd))
+ return;
+
+ spin_lock_irqsave(&T_TASK(cmd)->t_state_lock, flags);
+ if (!(atomic_read(&T_TASK(cmd)->transport_dev_active))) {
+ spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags);
+ goto free_pages;
+ }
+ atomic_set(&T_TASK(cmd)->transport_dev_active, 0);
+ transport_all_task_dev_remove_state(cmd);
+ spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags);
+
+ transport_release_tasks(cmd);
+free_pages:
+ transport_free_pages(cmd);
+ transport_free_se_cmd(cmd);
+ CMD_TFO(cmd)->release_cmd_direct(cmd);
+}
+
+static int transport_generic_remove(
+ struct se_cmd *cmd,
+ int release_to_pool,
+ int session_reinstatement)
+{
+ unsigned long flags;
+
+ if (!(T_TASK(cmd)))
+ goto release_cmd;
+
+ if (transport_dec_and_check(cmd)) {
+ if (session_reinstatement) {
+ spin_lock_irqsave(&T_TASK(cmd)->t_state_lock, flags);
+ transport_all_task_dev_remove_state(cmd);
+ spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock,
+ flags);
+ }
+ return 1;
+ }
+
+ spin_lock_irqsave(&T_TASK(cmd)->t_state_lock, flags);
+ if (!(atomic_read(&T_TASK(cmd)->transport_dev_active))) {
+ spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags);
+ goto free_pages;
+ }
+ atomic_set(&T_TASK(cmd)->transport_dev_active, 0);
+ transport_all_task_dev_remove_state(cmd);
+ spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags);
+
+ transport_release_tasks(cmd);
+free_pages:
+ transport_free_pages(cmd);
+
+release_cmd:
+ if (release_to_pool) {
+ transport_release_cmd_to_pool(cmd);
+ } else {
+ transport_free_se_cmd(cmd);
+ CMD_TFO(cmd)->release_cmd_direct(cmd);
+ }
+
+ return 0;
+}
+
+/*
+ * transport_generic_map_mem_to_cmd - Perform SGL -> struct se_mem map
+ * @cmd: Associated se_cmd descriptor
+ * @mem: SGL style memory for TCM WRITE / READ
+ * @sg_mem_num: Number of SGL elements
+ * @mem_bidi_in: SGL style memory for TCM BIDI READ
+ * @sg_mem_bidi_num: Number of BIDI READ SGL elements
+ *
+ * Return: nonzero return cmd was rejected for -ENOMEM or inproper usage
+ * of parameters.
+ */
+int transport_generic_map_mem_to_cmd(
+ struct se_cmd *cmd,
+ struct scatterlist *mem,
+ u32 sg_mem_num,
+ struct scatterlist *mem_bidi_in,
+ u32 sg_mem_bidi_num)
+{
+ u32 se_mem_cnt_out = 0;
+ int ret;
+
+ if (!(mem) || !(sg_mem_num))
+ return 0;
+ /*
+ * Passed *mem will contain a list_head containing preformatted
+ * struct se_mem elements...
+ */
+ if (!(cmd->se_cmd_flags & SCF_PASSTHROUGH_SG_TO_MEM)) {
+ if ((mem_bidi_in) || (sg_mem_bidi_num)) {
+ printk(KERN_ERR "SCF_CMD_PASSTHROUGH_NOALLOC not supported"
+ " with BIDI-COMMAND\n");
+ return -ENOSYS;
+ }
+
+ T_TASK(cmd)->t_mem_list = (struct list_head *)mem;
+ T_TASK(cmd)->t_tasks_se_num = sg_mem_num;
+ cmd->se_cmd_flags |= SCF_CMD_PASSTHROUGH_NOALLOC;
+ return 0;
+ }
+ /*
+ * Otherwise, assume the caller is passing a struct scatterlist
+ * array from include/linux/scatterlist.h
+ */
+ if ((cmd->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB) ||
+ (cmd->se_cmd_flags & SCF_SCSI_CONTROL_SG_IO_CDB)) {
+ /*
+ * For CDB using TCM struct se_mem linked list scatterlist memory
+ * processed into a TCM struct se_subsystem_dev, we do the mapping
+ * from the passed physical memory to struct se_mem->se_page here.
+ */
+ T_TASK(cmd)->t_mem_list = transport_init_se_mem_list();
+ if (!(T_TASK(cmd)->t_mem_list))
+ return -ENOMEM;
+
+ ret = transport_map_sg_to_mem(cmd,
+ T_TASK(cmd)->t_mem_list, mem, &se_mem_cnt_out);
+ if (ret < 0)
+ return -ENOMEM;
+
+ T_TASK(cmd)->t_tasks_se_num = se_mem_cnt_out;
+ /*
+ * Setup BIDI READ list of struct se_mem elements
+ */
+ if ((mem_bidi_in) && (sg_mem_bidi_num)) {
+ T_TASK(cmd)->t_mem_bidi_list = transport_init_se_mem_list();
+ if (!(T_TASK(cmd)->t_mem_bidi_list)) {
+ kfree(T_TASK(cmd)->t_mem_list);
+ return -ENOMEM;
+ }
+ se_mem_cnt_out = 0;
+
+ ret = transport_map_sg_to_mem(cmd,
+ T_TASK(cmd)->t_mem_bidi_list, mem_bidi_in,
+ &se_mem_cnt_out);
+ if (ret < 0) {
+ kfree(T_TASK(cmd)->t_mem_list);
+ return -ENOMEM;
+ }
+
+ T_TASK(cmd)->t_tasks_se_bidi_num = se_mem_cnt_out;
+ }
+ cmd->se_cmd_flags |= SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC;
+
+ } else if (cmd->se_cmd_flags & SCF_SCSI_CONTROL_NONSG_IO_CDB) {
+ if (mem_bidi_in || sg_mem_bidi_num) {
+ printk(KERN_ERR "BIDI-Commands not supported using "
+ "SCF_SCSI_CONTROL_NONSG_IO_CDB\n");
+ return -ENOSYS;
+ }
+ /*
+ * For incoming CDBs using a contiguous buffer internall with TCM,
+ * save the passed struct scatterlist memory. After TCM storage object
+ * processing has completed for this struct se_cmd, TCM core will call
+ * transport_memcpy_[write,read]_contig() as necessary from
+ * transport_generic_complete_ok() and transport_write_pending() in order
+ * to copy the TCM buffer to/from the original passed *mem in SGL ->
+ * struct scatterlist format.
+ */
+ cmd->se_cmd_flags |= SCF_PASSTHROUGH_CONTIG_TO_SG;
+ T_TASK(cmd)->t_task_pt_sgl = mem;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(transport_generic_map_mem_to_cmd);
+
+
+static inline long long transport_dev_end_lba(struct se_device *dev)
+{
+ return dev->transport->get_blocks(dev) + 1;
+}
+
+static int transport_get_sectors(struct se_cmd *cmd)
+{
+ struct se_device *dev = SE_DEV(cmd);
+
+ T_TASK(cmd)->t_tasks_sectors =
+ (cmd->data_length / DEV_ATTRIB(dev)->block_size);
+ if (!(T_TASK(cmd)->t_tasks_sectors))
+ T_TASK(cmd)->t_tasks_sectors = 1;
+
+ if (TRANSPORT(dev)->get_device_type(dev) != TYPE_DISK)
+ return 0;
+
+ if ((T_TASK(cmd)->t_task_lba + T_TASK(cmd)->t_tasks_sectors) >
+ transport_dev_end_lba(dev)) {
+ printk(KERN_ERR "LBA: %llu Sectors: %u exceeds"
+ " transport_dev_end_lba(): %llu\n",
+ T_TASK(cmd)->t_task_lba, T_TASK(cmd)->t_tasks_sectors,
+ transport_dev_end_lba(dev));
+ cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION;
+ cmd->scsi_sense_reason = TCM_SECTOR_COUNT_TOO_MANY;
+ return PYX_TRANSPORT_REQ_TOO_MANY_SECTORS;
+ }
+
+ return 0;
+}
+
+static int transport_new_cmd_obj(struct se_cmd *cmd)
+{
+ struct se_device *dev = SE_DEV(cmd);
+ u32 task_cdbs = 0, rc;
+
+ if (!(cmd->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB)) {
+ task_cdbs++;
+ T_TASK(cmd)->t_task_cdbs++;
+ } else {
+ int set_counts = 1;
+
+ /*
+ * Setup any BIDI READ tasks and memory from
+ * T_TASK(cmd)->t_mem_bidi_list so the READ struct se_tasks
+ * are queued first for the non pSCSI passthrough case.
+ */
+ if ((T_TASK(cmd)->t_mem_bidi_list != NULL) &&
+ (TRANSPORT(dev)->transport_type != TRANSPORT_PLUGIN_PHBA_PDEV)) {
+ rc = transport_generic_get_cdb_count(cmd,
+ T_TASK(cmd)->t_task_lba,
+ T_TASK(cmd)->t_tasks_sectors,
+ DMA_FROM_DEVICE, T_TASK(cmd)->t_mem_bidi_list,
+ set_counts);
+ if (!(rc)) {
+ cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION;
+ cmd->scsi_sense_reason =
+ TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
+ return PYX_TRANSPORT_LU_COMM_FAILURE;
+ }
+ set_counts = 0;
+ }
+ /*
+ * Setup the tasks and memory from T_TASK(cmd)->t_mem_list
+ * Note for BIDI transfers this will contain the WRITE payload
+ */
+ task_cdbs = transport_generic_get_cdb_count(cmd,
+ T_TASK(cmd)->t_task_lba,
+ T_TASK(cmd)->t_tasks_sectors,
+ cmd->data_direction, T_TASK(cmd)->t_mem_list,
+ set_counts);
+ if (!(task_cdbs)) {
+ cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION;
+ cmd->scsi_sense_reason =
+ TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
+ return PYX_TRANSPORT_LU_COMM_FAILURE;
+ }
+ T_TASK(cmd)->t_task_cdbs += task_cdbs;
+
+#if 0
+ printk(KERN_INFO "data_length: %u, LBA: %llu t_tasks_sectors:"
+ " %u, t_task_cdbs: %u\n", obj_ptr, cmd->data_length,
+ T_TASK(cmd)->t_task_lba, T_TASK(cmd)->t_tasks_sectors,
+ T_TASK(cmd)->t_task_cdbs);
+#endif
+ }
+
+ atomic_set(&T_TASK(cmd)->t_task_cdbs_left, task_cdbs);
+ atomic_set(&T_TASK(cmd)->t_task_cdbs_ex_left, task_cdbs);
+ atomic_set(&T_TASK(cmd)->t_task_cdbs_timeout_left, task_cdbs);
+ return 0;
+}
+
+static struct list_head *transport_init_se_mem_list(void)
+{
+ struct list_head *se_mem_list;
+
+ se_mem_list = kzalloc(sizeof(struct list_head), GFP_KERNEL);
+ if (!(se_mem_list)) {
+ printk(KERN_ERR "Unable to allocate memory for se_mem_list\n");
+ return NULL;
+ }
+ INIT_LIST_HEAD(se_mem_list);
+
+ return se_mem_list;
+}
+
+static int
+transport_generic_get_mem(struct se_cmd *cmd, u32 length, u32 dma_size)
+{
+ unsigned char *buf;
+ struct se_mem *se_mem;
+
+ T_TASK(cmd)->t_mem_list = transport_init_se_mem_list();
+ if (!(T_TASK(cmd)->t_mem_list))
+ return -ENOMEM;
+
+ /*
+ * If the device uses memory mapping this is enough.
+ */
+ if (cmd->se_dev->transport->do_se_mem_map)
+ return 0;
+
+ /*
+ * Setup BIDI-COMMAND READ list of struct se_mem elements
+ */
+ if (T_TASK(cmd)->t_tasks_bidi) {
+ T_TASK(cmd)->t_mem_bidi_list = transport_init_se_mem_list();
+ if (!(T_TASK(cmd)->t_mem_bidi_list)) {
+ kfree(T_TASK(cmd)->t_mem_list);
+ return -ENOMEM;
+ }
+ }
+
+ while (length) {
+ se_mem = kmem_cache_zalloc(se_mem_cache, GFP_KERNEL);
+ if (!(se_mem)) {
+ printk(KERN_ERR "Unable to allocate struct se_mem\n");
+ goto out;
+ }
+ INIT_LIST_HEAD(&se_mem->se_list);
+ se_mem->se_len = (length > dma_size) ? dma_size : length;
+
+/* #warning FIXME Allocate contigous pages for struct se_mem elements */
+ se_mem->se_page = (struct page *) alloc_pages(GFP_KERNEL, 0);
+ if (!(se_mem->se_page)) {
+ printk(KERN_ERR "alloc_pages() failed\n");
+ goto out;
+ }
+
+ buf = kmap_atomic(se_mem->se_page, KM_IRQ0);
+ if (!(buf)) {
+ printk(KERN_ERR "kmap_atomic() failed\n");
+ goto out;
+ }
+ memset(buf, 0, se_mem->se_len);
+ kunmap_atomic(buf, KM_IRQ0);
+
+ list_add_tail(&se_mem->se_list, T_TASK(cmd)->t_mem_list);
+ T_TASK(cmd)->t_tasks_se_num++;
+
+ DEBUG_MEM("Allocated struct se_mem page(%p) Length(%u)"
+ " Offset(%u)\n", se_mem->se_page, se_mem->se_len,
+ se_mem->se_off);
+
+ length -= se_mem->se_len;
+ }
+
+ DEBUG_MEM("Allocated total struct se_mem elements(%u)\n",
+ T_TASK(cmd)->t_tasks_se_num);
+
+ return 0;
+out:
+ return -1;
+}
+
+extern u32 transport_calc_sg_num(
+ struct se_task *task,
+ struct se_mem *in_se_mem,
+ u32 task_offset)
+{
+ struct se_cmd *se_cmd = task->task_se_cmd;
+ struct se_device *se_dev = SE_DEV(se_cmd);
+ struct se_mem *se_mem = in_se_mem;
+ struct target_core_fabric_ops *tfo = CMD_TFO(se_cmd);
+ u32 sg_length, task_size = task->task_size, task_sg_num_padded;
+
+ while (task_size != 0) {
+ DEBUG_SC("se_mem->se_page(%p) se_mem->se_len(%u)"
+ " se_mem->se_off(%u) task_offset(%u)\n",
+ se_mem->se_page, se_mem->se_len,
+ se_mem->se_off, task_offset);
+
+ if (task_offset == 0) {
+ if (task_size >= se_mem->se_len) {
+ sg_length = se_mem->se_len;
+
+ if (!(list_is_last(&se_mem->se_list,
+ T_TASK(se_cmd)->t_mem_list)))
+ se_mem = list_entry(se_mem->se_list.next,
+ struct se_mem, se_list);
+ } else {
+ sg_length = task_size;
+ task_size -= sg_length;
+ goto next;
+ }
+
+ DEBUG_SC("sg_length(%u) task_size(%u)\n",
+ sg_length, task_size);
+ } else {
+ if ((se_mem->se_len - task_offset) > task_size) {
+ sg_length = task_size;
+ task_size -= sg_length;
+ goto next;
+ } else {
+ sg_length = (se_mem->se_len - task_offset);
+
+ if (!(list_is_last(&se_mem->se_list,
+ T_TASK(se_cmd)->t_mem_list)))
+ se_mem = list_entry(se_mem->se_list.next,
+ struct se_mem, se_list);
+ }
+
+ DEBUG_SC("sg_length(%u) task_size(%u)\n",
+ sg_length, task_size);
+
+ task_offset = 0;
+ }
+ task_size -= sg_length;
+next:
+ DEBUG_SC("task[%u] - Reducing task_size to(%u)\n",
+ task->task_no, task_size);
+
+ task->task_sg_num++;
+ }
+ /*
+ * Check if the fabric module driver is requesting that all
+ * struct se_task->task_sg[] be chained together.. If so,
+ * then allocate an extra padding SG entry for linking and
+ * marking the end of the chained SGL.
+ */
+ if (tfo->task_sg_chaining) {
+ task_sg_num_padded = (task->task_sg_num + 1);
+ task->task_padded_sg = 1;
+ } else
+ task_sg_num_padded = task->task_sg_num;
+
+ task->task_sg = kzalloc(task_sg_num_padded *
+ sizeof(struct scatterlist), GFP_KERNEL);
+ if (!(task->task_sg)) {
+ printk(KERN_ERR "Unable to allocate memory for"
+ " task->task_sg\n");
+ return 0;
+ }
+ sg_init_table(&task->task_sg[0], task_sg_num_padded);
+ /*
+ * Setup task->task_sg_bidi for SCSI READ payload for
+ * TCM/pSCSI passthrough if present for BIDI-COMMAND
+ */
+ if ((T_TASK(se_cmd)->t_mem_bidi_list != NULL) &&
+ (TRANSPORT(se_dev)->transport_type == TRANSPORT_PLUGIN_PHBA_PDEV)) {
+ task->task_sg_bidi = kzalloc(task_sg_num_padded *
+ sizeof(struct scatterlist), GFP_KERNEL);
+ if (!(task->task_sg_bidi)) {
+ printk(KERN_ERR "Unable to allocate memory for"
+ " task->task_sg_bidi\n");
+ return 0;
+ }
+ sg_init_table(&task->task_sg_bidi[0], task_sg_num_padded);
+ }
+ /*
+ * For the chaining case, setup the proper end of SGL for the
+ * initial submission struct task into struct se_subsystem_api.
+ * This will be cleared later by transport_do_task_sg_chain()
+ */
+ if (task->task_padded_sg) {
+ sg_mark_end(&task->task_sg[task->task_sg_num - 1]);
+ /*
+ * Added the 'if' check before marking end of bi-directional
+ * scatterlist (which gets created only in case of request
+ * (RD + WR).
+ */
+ if (task->task_sg_bidi)
+ sg_mark_end(&task->task_sg_bidi[task->task_sg_num - 1]);
+ }
+
+ DEBUG_SC("Successfully allocated task->task_sg_num(%u),"
+ " task_sg_num_padded(%u)\n", task->task_sg_num,
+ task_sg_num_padded);
+
+ return task->task_sg_num;
+}
+
+static inline int transport_set_tasks_sectors_disk(
+ struct se_task *task,
+ struct se_device *dev,
+ unsigned long long lba,
+ u32 sectors,
+ int *max_sectors_set)
+{
+ if ((lba + sectors) > transport_dev_end_lba(dev)) {
+ task->task_sectors = ((transport_dev_end_lba(dev) - lba) + 1);
+
+ if (task->task_sectors > DEV_ATTRIB(dev)->max_sectors) {
+ task->task_sectors = DEV_ATTRIB(dev)->max_sectors;
+ *max_sectors_set = 1;
+ }
+ } else {
+ if (sectors > DEV_ATTRIB(dev)->max_sectors) {
+ task->task_sectors = DEV_ATTRIB(dev)->max_sectors;
+ *max_sectors_set = 1;
+ } else
+ task->task_sectors = sectors;
+ }
+
+ return 0;
+}
+
+static inline int transport_set_tasks_sectors_non_disk(
+ struct se_task *task,
+ struct se_device *dev,
+ unsigned long long lba,
+ u32 sectors,
+ int *max_sectors_set)
+{
+ if (sectors > DEV_ATTRIB(dev)->max_sectors) {
+ task->task_sectors = DEV_ATTRIB(dev)->max_sectors;
+ *max_sectors_set = 1;
+ } else
+ task->task_sectors = sectors;
+
+ return 0;
+}
+
+static inline int transport_set_tasks_sectors(
+ struct se_task *task,
+ struct se_device *dev,
+ unsigned long long lba,
+ u32 sectors,
+ int *max_sectors_set)
+{
+ return (TRANSPORT(dev)->get_device_type(dev) == TYPE_DISK) ?
+ transport_set_tasks_sectors_disk(task, dev, lba, sectors,
+ max_sectors_set) :
+ transport_set_tasks_sectors_non_disk(task, dev, lba, sectors,
+ max_sectors_set);
+}
+
+static int transport_map_sg_to_mem(
+ struct se_cmd *cmd,
+ struct list_head *se_mem_list,
+ void *in_mem,
+ u32 *se_mem_cnt)
+{
+ struct se_mem *se_mem;
+ struct scatterlist *sg;
+ u32 sg_count = 1, cmd_size = cmd->data_length;
+
+ if (!in_mem) {
+ printk(KERN_ERR "No source scatterlist\n");
+ return -1;
+ }
+ sg = (struct scatterlist *)in_mem;
+
+ while (cmd_size) {
+ se_mem = kmem_cache_zalloc(se_mem_cache, GFP_KERNEL);
+ if (!(se_mem)) {
+ printk(KERN_ERR "Unable to allocate struct se_mem\n");
+ return -1;
+ }
+ INIT_LIST_HEAD(&se_mem->se_list);
+ DEBUG_MEM("sg_to_mem: Starting loop with cmd_size: %u"
+ " sg_page: %p offset: %d length: %d\n", cmd_size,
+ sg_page(sg), sg->offset, sg->length);
+
+ se_mem->se_page = sg_page(sg);
+ se_mem->se_off = sg->offset;
+
+ if (cmd_size > sg->length) {
+ se_mem->se_len = sg->length;
+ sg = sg_next(sg);
+ sg_count++;
+ } else
+ se_mem->se_len = cmd_size;
+
+ cmd_size -= se_mem->se_len;
+
+ DEBUG_MEM("sg_to_mem: *se_mem_cnt: %u cmd_size: %u\n",
+ *se_mem_cnt, cmd_size);
+ DEBUG_MEM("sg_to_mem: Final se_page: %p se_off: %d se_len: %d\n",
+ se_mem->se_page, se_mem->se_off, se_mem->se_len);
+
+ list_add_tail(&se_mem->se_list, se_mem_list);
+ (*se_mem_cnt)++;
+ }
+
+ DEBUG_MEM("task[0] - Mapped(%u) struct scatterlist segments to(%u)"
+ " struct se_mem\n", sg_count, *se_mem_cnt);
+
+ if (sg_count != *se_mem_cnt)
+ BUG();
+
+ return 0;
+}
+
+/* transport_map_mem_to_sg():
+ *
+ *
+ */
+int transport_map_mem_to_sg(
+ struct se_task *task,
+ struct list_head *se_mem_list,
+ void *in_mem,
+ struct se_mem *in_se_mem,
+ struct se_mem **out_se_mem,
+ u32 *se_mem_cnt,
+ u32 *task_offset)
+{
+ struct se_cmd *se_cmd = task->task_se_cmd;
+ struct se_mem *se_mem = in_se_mem;
+ struct scatterlist *sg = (struct scatterlist *)in_mem;
+ u32 task_size = task->task_size, sg_no = 0;
+
+ if (!sg) {
+ printk(KERN_ERR "Unable to locate valid struct"
+ " scatterlist pointer\n");
+ return -1;
+ }
+
+ while (task_size != 0) {
+ /*
+ * Setup the contigious array of scatterlists for
+ * this struct se_task.
+ */
+ sg_assign_page(sg, se_mem->se_page);
+
+ if (*task_offset == 0) {
+ sg->offset = se_mem->se_off;
+
+ if (task_size >= se_mem->se_len) {
+ sg->length = se_mem->se_len;
+
+ if (!(list_is_last(&se_mem->se_list,
+ T_TASK(se_cmd)->t_mem_list))) {
+ se_mem = list_entry(se_mem->se_list.next,
+ struct se_mem, se_list);
+ (*se_mem_cnt)++;
+ }
+ } else {
+ sg->length = task_size;
+ /*
+ * Determine if we need to calculate an offset
+ * into the struct se_mem on the next go around..
+ */
+ task_size -= sg->length;
+ if (!(task_size))
+ *task_offset = sg->length;
+
+ goto next;
+ }
+
+ } else {
+ sg->offset = (*task_offset + se_mem->se_off);
+
+ if ((se_mem->se_len - *task_offset) > task_size) {
+ sg->length = task_size;
+ /*
+ * Determine if we need to calculate an offset
+ * into the struct se_mem on the next go around..
+ */
+ task_size -= sg->length;
+ if (!(task_size))
+ *task_offset += sg->length;
+
+ goto next;
+ } else {
+ sg->length = (se_mem->se_len - *task_offset);
+
+ if (!(list_is_last(&se_mem->se_list,
+ T_TASK(se_cmd)->t_mem_list))) {
+ se_mem = list_entry(se_mem->se_list.next,
+ struct se_mem, se_list);
+ (*se_mem_cnt)++;
+ }
+ }
+
+ *task_offset = 0;
+ }
+ task_size -= sg->length;
+next:
+ DEBUG_MEM("task[%u] mem_to_sg - sg[%u](%p)(%u)(%u) - Reducing"
+ " task_size to(%u), task_offset: %u\n", task->task_no, sg_no,
+ sg_page(sg), sg->length, sg->offset, task_size, *task_offset);
+
+ sg_no++;
+ if (!(task_size))
+ break;
+
+ sg = sg_next(sg);
+
+ if (task_size > se_cmd->data_length)
+ BUG();
+ }
+ *out_se_mem = se_mem;
+
+ DEBUG_MEM("task[%u] - Mapped(%u) struct se_mem segments to total(%u)"
+ " SGs\n", task->task_no, *se_mem_cnt, sg_no);
+
+ return 0;
+}
+
+/*
+ * This function can be used by HW target mode drivers to create a linked
+ * scatterlist from all contiguously allocated struct se_task->task_sg[].
+ * This is intended to be called during the completion path by TCM Core
+ * when struct target_core_fabric_ops->check_task_sg_chaining is enabled.
+ */
+void transport_do_task_sg_chain(struct se_cmd *cmd)
+{
+ struct scatterlist *sg_head = NULL, *sg_link = NULL, *sg_first = NULL;
+ struct scatterlist *sg_head_cur = NULL, *sg_link_cur = NULL;
+ struct scatterlist *sg, *sg_end = NULL, *sg_end_cur = NULL;
+ struct se_task *task;
+ struct target_core_fabric_ops *tfo = CMD_TFO(cmd);
+ u32 task_sg_num = 0, sg_count = 0;
+ int i;
+
+ if (tfo->task_sg_chaining == 0) {
+ printk(KERN_ERR "task_sg_chaining is diabled for fabric module:"
+ " %s\n", tfo->get_fabric_name());
+ dump_stack();
+ return;
+ }
+ /*
+ * Walk the struct se_task list and setup scatterlist chains
+ * for each contiguosly allocated struct se_task->task_sg[].
+ */
+ list_for_each_entry(task, &T_TASK(cmd)->t_task_list, t_list) {
+ if (!(task->task_sg) || !(task->task_padded_sg))
+ continue;
+
+ if (sg_head && sg_link) {
+ sg_head_cur = &task->task_sg[0];
+ sg_link_cur = &task->task_sg[task->task_sg_num];
+ /*
+ * Either add chain or mark end of scatterlist
+ */
+ if (!(list_is_last(&task->t_list,
+ &T_TASK(cmd)->t_task_list))) {
+ /*
+ * Clear existing SGL termination bit set in
+ * transport_calc_sg_num(), see sg_mark_end()
+ */
+ sg_end_cur = &task->task_sg[task->task_sg_num - 1];
+ sg_end_cur->page_link &= ~0x02;
+
+ sg_chain(sg_head, task_sg_num, sg_head_cur);
+ sg_count += (task->task_sg_num + 1);
+ } else
+ sg_count += task->task_sg_num;
+
+ sg_head = sg_head_cur;
+ sg_link = sg_link_cur;
+ task_sg_num = task->task_sg_num;
+ continue;
+ }
+ sg_head = sg_first = &task->task_sg[0];
+ sg_link = &task->task_sg[task->task_sg_num];
+ task_sg_num = task->task_sg_num;
+ /*
+ * Check for single task..
+ */
+ if (!(list_is_last(&task->t_list, &T_TASK(cmd)->t_task_list))) {
+ /*
+ * Clear existing SGL termination bit set in
+ * transport_calc_sg_num(), see sg_mark_end()
+ */
+ sg_end = &task->task_sg[task->task_sg_num - 1];
+ sg_end->page_link &= ~0x02;
+ sg_count += (task->task_sg_num + 1);
+ } else
+ sg_count += task->task_sg_num;
+ }
+ /*
+ * Setup the starting pointer and total t_tasks_sg_linked_no including
+ * padding SGs for linking and to mark the end.
+ */
+ T_TASK(cmd)->t_tasks_sg_chained = sg_first;
+ T_TASK(cmd)->t_tasks_sg_chained_no = sg_count;
+
+ DEBUG_CMD_M("Setup T_TASK(cmd)->t_tasks_sg_chained: %p and"
+ " t_tasks_sg_chained_no: %u\n", T_TASK(cmd)->t_tasks_sg_chained,
+ T_TASK(cmd)->t_tasks_sg_chained_no);
+
+ for_each_sg(T_TASK(cmd)->t_tasks_sg_chained, sg,
+ T_TASK(cmd)->t_tasks_sg_chained_no, i) {
+
+ DEBUG_CMD_M("SG: %p page: %p length: %d offset: %d\n",
+ sg, sg_page(sg), sg->length, sg->offset);
+ if (sg_is_chain(sg))
+ DEBUG_CMD_M("SG: %p sg_is_chain=1\n", sg);
+ if (sg_is_last(sg))
+ DEBUG_CMD_M("SG: %p sg_is_last=1\n", sg);
+ }
+
+}
+EXPORT_SYMBOL(transport_do_task_sg_chain);
+
+static int transport_do_se_mem_map(
+ struct se_device *dev,
+ struct se_task *task,
+ struct list_head *se_mem_list,
+ void *in_mem,
+ struct se_mem *in_se_mem,
+ struct se_mem **out_se_mem,
+ u32 *se_mem_cnt,
+ u32 *task_offset_in)
+{
+ u32 task_offset = *task_offset_in;
+ int ret = 0;
+ /*
+ * se_subsystem_api_t->do_se_mem_map is used when internal allocation
+ * has been done by the transport plugin.
+ */
+ if (TRANSPORT(dev)->do_se_mem_map) {
+ ret = TRANSPORT(dev)->do_se_mem_map(task, se_mem_list,
+ in_mem, in_se_mem, out_se_mem, se_mem_cnt,
+ task_offset_in);
+ if (ret == 0)
+ T_TASK(task->task_se_cmd)->t_tasks_se_num += *se_mem_cnt;
+
+ return ret;
+ }
+ /*
+ * This is the normal path for all normal non BIDI and BIDI-COMMAND
+ * WRITE payloads.. If we need to do BIDI READ passthrough for
+ * TCM/pSCSI the first call to transport_do_se_mem_map ->
+ * transport_calc_sg_num() -> transport_map_mem_to_sg() will do the
+ * allocation for task->task_sg_bidi, and the subsequent call to
+ * transport_do_se_mem_map() from transport_generic_get_cdb_count()
+ */
+ if (!(task->task_sg_bidi)) {
+ /*
+ * Assume default that transport plugin speaks preallocated
+ * scatterlists.
+ */
+ if (!(transport_calc_sg_num(task, in_se_mem, task_offset)))
+ return -1;
+ /*
+ * struct se_task->task_sg now contains the struct scatterlist array.
+ */
+ return transport_map_mem_to_sg(task, se_mem_list, task->task_sg,
+ in_se_mem, out_se_mem, se_mem_cnt,
+ task_offset_in);
+ }
+ /*
+ * Handle the se_mem_list -> struct task->task_sg_bidi
+ * memory map for the extra BIDI READ payload
+ */
+ return transport_map_mem_to_sg(task, se_mem_list, task->task_sg_bidi,
+ in_se_mem, out_se_mem, se_mem_cnt,
+ task_offset_in);
+}
+
+static u32 transport_generic_get_cdb_count(
+ struct se_cmd *cmd,
+ unsigned long long lba,
+ u32 sectors,
+ enum dma_data_direction data_direction,
+ struct list_head *mem_list,
+ int set_counts)
+{
+ unsigned char *cdb = NULL;
+ struct se_task *task;
+ struct se_mem *se_mem = NULL, *se_mem_lout = NULL;
+ struct se_mem *se_mem_bidi = NULL, *se_mem_bidi_lout = NULL;
+ struct se_device *dev = SE_DEV(cmd);
+ int max_sectors_set = 0, ret;
+ u32 task_offset_in = 0, se_mem_cnt = 0, se_mem_bidi_cnt = 0, task_cdbs = 0;
+
+ if (!mem_list) {
+ printk(KERN_ERR "mem_list is NULL in transport_generic_get"
+ "_cdb_count()\n");
+ return 0;
+ }
+ /*
+ * While using RAMDISK_DR backstores is the only case where
+ * mem_list will ever be empty at this point.
+ */
+ if (!(list_empty(mem_list)))
+ se_mem = list_entry(mem_list->next, struct se_mem, se_list);
+ /*
+ * Check for extra se_mem_bidi mapping for BIDI-COMMANDs to
+ * struct se_task->task_sg_bidi for TCM/pSCSI passthrough operation
+ */
+ if ((T_TASK(cmd)->t_mem_bidi_list != NULL) &&
+ !(list_empty(T_TASK(cmd)->t_mem_bidi_list)) &&
+ (TRANSPORT(dev)->transport_type == TRANSPORT_PLUGIN_PHBA_PDEV))
+ se_mem_bidi = list_entry(T_TASK(cmd)->t_mem_bidi_list->next,
+ struct se_mem, se_list);
+
+ while (sectors) {
+ DEBUG_VOL("ITT[0x%08x] LBA(%llu) SectorsLeft(%u) EOBJ(%llu)\n",
+ CMD_TFO(cmd)->get_task_tag(cmd), lba, sectors,
+ transport_dev_end_lba(dev));
+
+ task = transport_generic_get_task(cmd, data_direction);
+ if (!(task))
+ goto out;
+
+ transport_set_tasks_sectors(task, dev, lba, sectors,
+ &max_sectors_set);
+
+ task->task_lba = lba;
+ lba += task->task_sectors;
+ sectors -= task->task_sectors;
+ task->task_size = (task->task_sectors *
+ DEV_ATTRIB(dev)->block_size);
+
+ cdb = TRANSPORT(dev)->get_cdb(task);
+ if ((cdb)) {
+ memcpy(cdb, T_TASK(cmd)->t_task_cdb,
+ scsi_command_size(T_TASK(cmd)->t_task_cdb));
+ cmd->transport_split_cdb(task->task_lba,
+ &task->task_sectors, cdb);
+ }
+
+ /*
+ * Perform the SE OBJ plugin and/or Transport plugin specific
+ * mapping for T_TASK(cmd)->t_mem_list. And setup the
+ * task->task_sg and if necessary task->task_sg_bidi
+ */
+ ret = transport_do_se_mem_map(dev, task, mem_list,
+ NULL, se_mem, &se_mem_lout, &se_mem_cnt,
+ &task_offset_in);
+ if (ret < 0)
+ goto out;
+
+ se_mem = se_mem_lout;
+ /*
+ * Setup the T_TASK(cmd)->t_mem_bidi_list -> task->task_sg_bidi
+ * mapping for SCSI READ for BIDI-COMMAND passthrough with TCM/pSCSI
+ *
+ * Note that the first call to transport_do_se_mem_map() above will
+ * allocate struct se_task->task_sg_bidi in transport_do_se_mem_map()
+ * -> transport_calc_sg_num(), and the second here will do the
+ * mapping for SCSI READ for BIDI-COMMAND passthrough with TCM/pSCSI.
+ */
+ if (task->task_sg_bidi != NULL) {
+ ret = transport_do_se_mem_map(dev, task,
+ T_TASK(cmd)->t_mem_bidi_list, NULL,
+ se_mem_bidi, &se_mem_bidi_lout, &se_mem_bidi_cnt,
+ &task_offset_in);
+ if (ret < 0)
+ goto out;
+
+ se_mem_bidi = se_mem_bidi_lout;
+ }
+ task_cdbs++;
+
+ DEBUG_VOL("Incremented task_cdbs(%u) task->task_sg_num(%u)\n",
+ task_cdbs, task->task_sg_num);
+
+ if (max_sectors_set) {
+ max_sectors_set = 0;
+ continue;
+ }
+
+ if (!sectors)
+ break;
+ }
+
+ if (set_counts) {
+ atomic_inc(&T_TASK(cmd)->t_fe_count);
+ atomic_inc(&T_TASK(cmd)->t_se_count);
+ }
+
+ DEBUG_VOL("ITT[0x%08x] total %s cdbs(%u)\n",
+ CMD_TFO(cmd)->get_task_tag(cmd), (data_direction == DMA_TO_DEVICE)
+ ? "DMA_TO_DEVICE" : "DMA_FROM_DEVICE", task_cdbs);
+
+ return task_cdbs;
+out:
+ return 0;
+}
+
+static int
+transport_map_control_cmd_to_task(struct se_cmd *cmd)
+{
+ struct se_device *dev = SE_DEV(cmd);
+ unsigned char *cdb;
+ struct se_task *task;
+ int ret;
+
+ task = transport_generic_get_task(cmd, cmd->data_direction);
+ if (!task)
+ return PYX_TRANSPORT_OUT_OF_MEMORY_RESOURCES;
+
+ cdb = TRANSPORT(dev)->get_cdb(task);
+ if (cdb)
+ memcpy(cdb, cmd->t_task->t_task_cdb,
+ scsi_command_size(cmd->t_task->t_task_cdb));
+
+ task->task_size = cmd->data_length;
+ task->task_sg_num =
+ (cmd->se_cmd_flags & SCF_SCSI_CONTROL_SG_IO_CDB) ? 1 : 0;
+
+ atomic_inc(&cmd->t_task->t_fe_count);
+ atomic_inc(&cmd->t_task->t_se_count);
+
+ if (cmd->se_cmd_flags & SCF_SCSI_CONTROL_SG_IO_CDB) {
+ struct se_mem *se_mem = NULL, *se_mem_lout = NULL;
+ u32 se_mem_cnt = 0, task_offset = 0;
+
+ BUG_ON(list_empty(cmd->t_task->t_mem_list));
+
+ ret = transport_do_se_mem_map(dev, task,
+ cmd->t_task->t_mem_list, NULL, se_mem,
+ &se_mem_lout, &se_mem_cnt, &task_offset);
+ if (ret < 0)
+ return PYX_TRANSPORT_OUT_OF_MEMORY_RESOURCES;
+
+ if (dev->transport->map_task_SG)
+ return dev->transport->map_task_SG(task);
+ return 0;
+ } else if (cmd->se_cmd_flags & SCF_SCSI_CONTROL_NONSG_IO_CDB) {
+ if (dev->transport->map_task_non_SG)
+ return dev->transport->map_task_non_SG(task);
+ return 0;
+ } else if (cmd->se_cmd_flags & SCF_SCSI_NON_DATA_CDB) {
+ if (dev->transport->cdb_none)
+ return dev->transport->cdb_none(task);
+ return 0;
+ } else {
+ BUG();
+ return PYX_TRANSPORT_OUT_OF_MEMORY_RESOURCES;
+ }
+}
+
+/* transport_generic_new_cmd(): Called from transport_processing_thread()
+ *
+ * Allocate storage transport resources from a set of values predefined
+ * by transport_generic_cmd_sequencer() from the iSCSI Target RX process.
+ * Any non zero return here is treated as an "out of resource' op here.
+ */
+ /*
+ * Generate struct se_task(s) and/or their payloads for this CDB.
+ */
+static int transport_generic_new_cmd(struct se_cmd *cmd)
+{
+ struct se_portal_group *se_tpg;
+ struct se_task *task;
+ struct se_device *dev = SE_DEV(cmd);
+ int ret = 0;
+
+ /*
+ * Determine is the TCM fabric module has already allocated physical
+ * memory, and is directly calling transport_generic_map_mem_to_cmd()
+ * to setup beforehand the linked list of physical memory at
+ * T_TASK(cmd)->t_mem_list of struct se_mem->se_page
+ */
+ if (!(cmd->se_cmd_flags & SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC)) {
+ ret = transport_allocate_resources(cmd);
+ if (ret < 0)
+ return ret;
+ }
+
+ ret = transport_get_sectors(cmd);
+ if (ret < 0)
+ return ret;
+
+ ret = transport_new_cmd_obj(cmd);
+ if (ret < 0)
+ return ret;
+
+ /*
+ * Determine if the calling TCM fabric module is talking to
+ * Linux/NET via kernel sockets and needs to allocate a
+ * struct iovec array to complete the struct se_cmd
+ */
+ se_tpg = SE_LUN(cmd)->lun_sep->sep_tpg;
+ if (TPG_TFO(se_tpg)->alloc_cmd_iovecs != NULL) {
+ ret = TPG_TFO(se_tpg)->alloc_cmd_iovecs(cmd);
+ if (ret < 0)
+ return PYX_TRANSPORT_OUT_OF_MEMORY_RESOURCES;
+ }
+
+ if (cmd->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB) {
+ list_for_each_entry(task, &T_TASK(cmd)->t_task_list, t_list) {
+ if (atomic_read(&task->task_sent))
+ continue;
+ if (!dev->transport->map_task_SG)
+ continue;
+
+ ret = dev->transport->map_task_SG(task);
+ if (ret < 0)
+ return ret;
+ }
+ } else {
+ ret = transport_map_control_cmd_to_task(cmd);
+ if (ret < 0)
+ return ret;
+ }
+
+ /*
+ * For WRITEs, let the iSCSI Target RX Thread know its buffer is ready..
+ * This WRITE struct se_cmd (and all of its associated struct se_task's)
+ * will be added to the struct se_device execution queue after its WRITE
+ * data has arrived. (ie: It gets handled by the transport processing
+ * thread a second time)
+ */
+ if (cmd->data_direction == DMA_TO_DEVICE) {
+ transport_add_tasks_to_state_queue(cmd);
+ return transport_generic_write_pending(cmd);
+ }
+ /*
+ * Everything else but a WRITE, add the struct se_cmd's struct se_task's
+ * to the execution queue.
+ */
+ transport_execute_tasks(cmd);
+ return 0;
+}
+
+/* transport_generic_process_write():
+ *
+ *
+ */
+void transport_generic_process_write(struct se_cmd *cmd)
+{
+#if 0
+ /*
+ * Copy SCSI Presented DTL sector(s) from received buffers allocated to
+ * original EDTL
+ */
+ if (cmd->se_cmd_flags & SCF_UNDERFLOW_BIT) {
+ if (!T_TASK(cmd)->t_tasks_se_num) {
+ unsigned char *dst, *buf =
+ (unsigned char *)T_TASK(cmd)->t_task_buf;
+
+ dst = kzalloc(cmd->cmd_spdtl), GFP_KERNEL);
+ if (!(dst)) {
+ printk(KERN_ERR "Unable to allocate memory for"
+ " WRITE underflow\n");
+ transport_generic_request_failure(cmd, NULL,
+ PYX_TRANSPORT_REQ_TOO_MANY_SECTORS, 1);
+ return;
+ }
+ memcpy(dst, buf, cmd->cmd_spdtl);
+
+ kfree(T_TASK(cmd)->t_task_buf);
+ T_TASK(cmd)->t_task_buf = dst;
+ } else {
+ struct scatterlist *sg =
+ (struct scatterlist *sg)T_TASK(cmd)->t_task_buf;
+ struct scatterlist *orig_sg;
+
+ orig_sg = kzalloc(sizeof(struct scatterlist) *
+ T_TASK(cmd)->t_tasks_se_num,
+ GFP_KERNEL))) {
+ if (!(orig_sg)) {
+ printk(KERN_ERR "Unable to allocate memory"
+ " for WRITE underflow\n");
+ transport_generic_request_failure(cmd, NULL,
+ PYX_TRANSPORT_REQ_TOO_MANY_SECTORS, 1);
+ return;
+ }
+
+ memcpy(orig_sg, T_TASK(cmd)->t_task_buf,
+ sizeof(struct scatterlist) *
+ T_TASK(cmd)->t_tasks_se_num);
+
+ cmd->data_length = cmd->cmd_spdtl;
+ /*
+ * FIXME, clear out original struct se_task and state
+ * information.
+ */
+ if (transport_generic_new_cmd(cmd) < 0) {
+ transport_generic_request_failure(cmd, NULL,
+ PYX_TRANSPORT_REQ_TOO_MANY_SECTORS, 1);
+ kfree(orig_sg);
+ return;
+ }
+
+ transport_memcpy_write_sg(cmd, orig_sg);
+ }
+ }
+#endif
+ transport_execute_tasks(cmd);
+}
+EXPORT_SYMBOL(transport_generic_process_write);
+
+/* transport_generic_write_pending():
+ *
+ *
+ */
+static int transport_generic_write_pending(struct se_cmd *cmd)
+{
+ unsigned long flags;
+ int ret;
+
+ spin_lock_irqsave(&T_TASK(cmd)->t_state_lock, flags);
+ cmd->t_state = TRANSPORT_WRITE_PENDING;
+ spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags);
+ /*
+ * For the TCM control CDBs using a contiguous buffer, do the memcpy
+ * from the passed Linux/SCSI struct scatterlist located at
+ * T_TASK(se_cmd)->t_task_pt_buf to the contiguous buffer at
+ * T_TASK(se_cmd)->t_task_buf.
+ */
+ if (cmd->se_cmd_flags & SCF_PASSTHROUGH_CONTIG_TO_SG)
+ transport_memcpy_read_contig(cmd,
+ T_TASK(cmd)->t_task_buf,
+ T_TASK(cmd)->t_task_pt_sgl);
+ /*
+ * Clear the se_cmd for WRITE_PENDING status in order to set
+ * T_TASK(cmd)->t_transport_active=0 so that transport_generic_handle_data
+ * can be called from HW target mode interrupt code. This is safe
+ * to be called with transport_off=1 before the CMD_TFO(cmd)->write_pending
+ * because the se_cmd->se_lun pointer is not being cleared.
+ */
+ transport_cmd_check_stop(cmd, 1, 0);
+
+ /*
+ * Call the fabric write_pending function here to let the
+ * frontend know that WRITE buffers are ready.
+ */
+ ret = CMD_TFO(cmd)->write_pending(cmd);
+ if (ret < 0)
+ return ret;
+
+ return PYX_TRANSPORT_WRITE_PENDING;
+}
+
+/* transport_release_cmd_to_pool():
+ *
+ *
+ */
+void transport_release_cmd_to_pool(struct se_cmd *cmd)
+{
+ BUG_ON(!T_TASK(cmd));
+ BUG_ON(!CMD_TFO(cmd));
+
+ transport_free_se_cmd(cmd);
+ CMD_TFO(cmd)->release_cmd_to_pool(cmd);
+}
+EXPORT_SYMBOL(transport_release_cmd_to_pool);
+
+/* transport_generic_free_cmd():
+ *
+ * Called from processing frontend to release storage engine resources
+ */
+void transport_generic_free_cmd(
+ struct se_cmd *cmd,
+ int wait_for_tasks,
+ int release_to_pool,
+ int session_reinstatement)
+{
+ if (!(cmd->se_cmd_flags & SCF_SE_LUN_CMD) || !T_TASK(cmd))
+ transport_release_cmd_to_pool(cmd);
+ else {
+ core_dec_lacl_count(cmd->se_sess->se_node_acl, cmd);
+
+ if (SE_LUN(cmd)) {
+#if 0
+ printk(KERN_INFO "cmd: %p ITT: 0x%08x contains"
+ " SE_LUN(cmd)\n", cmd,
+ CMD_TFO(cmd)->get_task_tag(cmd));
+#endif
+ transport_lun_remove_cmd(cmd);
+ }
+
+ if (wait_for_tasks && cmd->transport_wait_for_tasks)
+ cmd->transport_wait_for_tasks(cmd, 0, 0);
+
+ transport_generic_remove(cmd, release_to_pool,
+ session_reinstatement);
+ }
+}
+EXPORT_SYMBOL(transport_generic_free_cmd);
+
+static void transport_nop_wait_for_tasks(
+ struct se_cmd *cmd,
+ int remove_cmd,
+ int session_reinstatement)
+{
+ return;
+}
+
+/* transport_lun_wait_for_tasks():
+ *
+ * Called from ConfigFS context to stop the passed struct se_cmd to allow
+ * an struct se_lun to be successfully shutdown.
+ */
+static int transport_lun_wait_for_tasks(struct se_cmd *cmd, struct se_lun *lun)
+{
+ unsigned long flags;
+ int ret;
+ /*
+ * If the frontend has already requested this struct se_cmd to
+ * be stopped, we can safely ignore this struct se_cmd.
+ */
+ spin_lock_irqsave(&T_TASK(cmd)->t_state_lock, flags);
+ if (atomic_read(&T_TASK(cmd)->t_transport_stop)) {
+ atomic_set(&T_TASK(cmd)->transport_lun_stop, 0);
+ DEBUG_TRANSPORT_S("ConfigFS ITT[0x%08x] - t_transport_stop =="
+ " TRUE, skipping\n", CMD_TFO(cmd)->get_task_tag(cmd));
+ spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags);
+ transport_cmd_check_stop(cmd, 1, 0);
+ return -1;
+ }
+ atomic_set(&T_TASK(cmd)->transport_lun_fe_stop, 1);
+ spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags);
+
+ wake_up_interruptible(&SE_DEV(cmd)->dev_queue_obj->thread_wq);
+
+ ret = transport_stop_tasks_for_cmd(cmd);
+
+ DEBUG_TRANSPORT_S("ConfigFS: cmd: %p t_task_cdbs: %d stop tasks ret:"
+ " %d\n", cmd, T_TASK(cmd)->t_task_cdbs, ret);
+ if (!ret) {
+ DEBUG_TRANSPORT_S("ConfigFS: ITT[0x%08x] - stopping cmd....\n",
+ CMD_TFO(cmd)->get_task_tag(cmd));
+ wait_for_completion(&T_TASK(cmd)->transport_lun_stop_comp);
+ DEBUG_TRANSPORT_S("ConfigFS: ITT[0x%08x] - stopped cmd....\n",
+ CMD_TFO(cmd)->get_task_tag(cmd));
+ }
+ transport_remove_cmd_from_queue(cmd, SE_DEV(cmd)->dev_queue_obj);
+
+ return 0;
+}
+
+/* #define DEBUG_CLEAR_LUN */
+#ifdef DEBUG_CLEAR_LUN
+#define DEBUG_CLEAR_L(x...) printk(KERN_INFO x)
+#else
+#define DEBUG_CLEAR_L(x...)
+#endif
+
+static void __transport_clear_lun_from_sessions(struct se_lun *lun)
+{
+ struct se_cmd *cmd = NULL;
+ unsigned long lun_flags, cmd_flags;
+ /*
+ * Do exception processing and return CHECK_CONDITION status to the
+ * Initiator Port.
+ */
+ spin_lock_irqsave(&lun->lun_cmd_lock, lun_flags);
+ while (!list_empty_careful(&lun->lun_cmd_list)) {
+ cmd = list_entry(lun->lun_cmd_list.next,
+ struct se_cmd, se_lun_list);
+ list_del(&cmd->se_lun_list);
+
+ if (!(T_TASK(cmd))) {
+ printk(KERN_ERR "ITT: 0x%08x, T_TASK(cmd) = NULL"
+ "[i,t]_state: %u/%u\n",
+ CMD_TFO(cmd)->get_task_tag(cmd),
+ CMD_TFO(cmd)->get_cmd_state(cmd), cmd->t_state);
+ BUG();
+ }
+ atomic_set(&T_TASK(cmd)->transport_lun_active, 0);
+ /*
+ * This will notify iscsi_target_transport.c:
+ * transport_cmd_check_stop() that a LUN shutdown is in
+ * progress for the iscsi_cmd_t.
+ */
+ spin_lock(&T_TASK(cmd)->t_state_lock);
+ DEBUG_CLEAR_L("SE_LUN[%d] - Setting T_TASK(cmd)->transport"
+ "_lun_stop for ITT: 0x%08x\n",
+ SE_LUN(cmd)->unpacked_lun,
+ CMD_TFO(cmd)->get_task_tag(cmd));
+ atomic_set(&T_TASK(cmd)->transport_lun_stop, 1);
+ spin_unlock(&T_TASK(cmd)->t_state_lock);
+
+ spin_unlock_irqrestore(&lun->lun_cmd_lock, lun_flags);
+
+ if (!(SE_LUN(cmd))) {
+ printk(KERN_ERR "ITT: 0x%08x, [i,t]_state: %u/%u\n",
+ CMD_TFO(cmd)->get_task_tag(cmd),
+ CMD_TFO(cmd)->get_cmd_state(cmd), cmd->t_state);
+ BUG();
+ }
+ /*
+ * If the Storage engine still owns the iscsi_cmd_t, determine
+ * and/or stop its context.
+ */
+ DEBUG_CLEAR_L("SE_LUN[%d] - ITT: 0x%08x before transport"
+ "_lun_wait_for_tasks()\n", SE_LUN(cmd)->unpacked_lun,
+ CMD_TFO(cmd)->get_task_tag(cmd));
+
+ if (transport_lun_wait_for_tasks(cmd, SE_LUN(cmd)) < 0) {
+ spin_lock_irqsave(&lun->lun_cmd_lock, lun_flags);
+ continue;
+ }
+
+ DEBUG_CLEAR_L("SE_LUN[%d] - ITT: 0x%08x after transport_lun"
+ "_wait_for_tasks(): SUCCESS\n",
+ SE_LUN(cmd)->unpacked_lun,
+ CMD_TFO(cmd)->get_task_tag(cmd));
+
+ spin_lock_irqsave(&T_TASK(cmd)->t_state_lock, cmd_flags);
+ if (!(atomic_read(&T_TASK(cmd)->transport_dev_active))) {
+ spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, cmd_flags);
+ goto check_cond;
+ }
+ atomic_set(&T_TASK(cmd)->transport_dev_active, 0);
+ transport_all_task_dev_remove_state(cmd);
+ spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, cmd_flags);
+
+ transport_free_dev_tasks(cmd);
+ /*
+ * The Storage engine stopped this struct se_cmd before it was
+ * send to the fabric frontend for delivery back to the
+ * Initiator Node. Return this SCSI CDB back with an
+ * CHECK_CONDITION status.
+ */
+check_cond:
+ transport_send_check_condition_and_sense(cmd,
+ TCM_NON_EXISTENT_LUN, 0);
+ /*
+ * If the fabric frontend is waiting for this iscsi_cmd_t to
+ * be released, notify the waiting thread now that LU has
+ * finished accessing it.
+ */
+ spin_lock_irqsave(&T_TASK(cmd)->t_state_lock, cmd_flags);
+ if (atomic_read(&T_TASK(cmd)->transport_lun_fe_stop)) {
+ DEBUG_CLEAR_L("SE_LUN[%d] - Detected FE stop for"
+ " struct se_cmd: %p ITT: 0x%08x\n",
+ lun->unpacked_lun,
+ cmd, CMD_TFO(cmd)->get_task_tag(cmd));
+
+ spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock,
+ cmd_flags);
+ transport_cmd_check_stop(cmd, 1, 0);
+ complete(&T_TASK(cmd)->transport_lun_fe_stop_comp);
+ spin_lock_irqsave(&lun->lun_cmd_lock, lun_flags);
+ continue;
+ }
+ DEBUG_CLEAR_L("SE_LUN[%d] - ITT: 0x%08x finished processing\n",
+ lun->unpacked_lun, CMD_TFO(cmd)->get_task_tag(cmd));
+
+ spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, cmd_flags);
+ spin_lock_irqsave(&lun->lun_cmd_lock, lun_flags);
+ }
+ spin_unlock_irqrestore(&lun->lun_cmd_lock, lun_flags);
+}
+
+static int transport_clear_lun_thread(void *p)
+{
+ struct se_lun *lun = (struct se_lun *)p;
+
+ __transport_clear_lun_from_sessions(lun);
+ complete(&lun->lun_shutdown_comp);
+
+ return 0;
+}
+
+int transport_clear_lun_from_sessions(struct se_lun *lun)
+{
+ struct task_struct *kt;
+
+ kt = kthread_run(transport_clear_lun_thread, (void *)lun,
+ "tcm_cl_%u", lun->unpacked_lun);
+ if (IS_ERR(kt)) {
+ printk(KERN_ERR "Unable to start clear_lun thread\n");
+ return -1;
+ }
+ wait_for_completion(&lun->lun_shutdown_comp);
+
+ return 0;
+}
+
+/* transport_generic_wait_for_tasks():
+ *
+ * Called from frontend or passthrough context to wait for storage engine
+ * to pause and/or release frontend generated struct se_cmd.
+ */
+static void transport_generic_wait_for_tasks(
+ struct se_cmd *cmd,
+ int remove_cmd,
+ int session_reinstatement)
+{
+ unsigned long flags;
+
+ if (!(cmd->se_cmd_flags & SCF_SE_LUN_CMD) && !(cmd->se_tmr_req))
+ return;
+
+ spin_lock_irqsave(&T_TASK(cmd)->t_state_lock, flags);
+ /*
+ * If we are already stopped due to an external event (ie: LUN shutdown)
+ * sleep until the connection can have the passed struct se_cmd back.
+ * The T_TASK(cmd)->transport_lun_stopped_sem will be upped by
+ * transport_clear_lun_from_sessions() once the ConfigFS context caller
+ * has completed its operation on the struct se_cmd.
+ */
+ if (atomic_read(&T_TASK(cmd)->transport_lun_stop)) {
+
+ DEBUG_TRANSPORT_S("wait_for_tasks: Stopping"
+ " wait_for_completion(&T_TASK(cmd)transport_lun_fe"
+ "_stop_comp); for ITT: 0x%08x\n",
+ CMD_TFO(cmd)->get_task_tag(cmd));
+ /*
+ * There is a special case for WRITES where a FE exception +
+ * LUN shutdown means ConfigFS context is still sleeping on
+ * transport_lun_stop_comp in transport_lun_wait_for_tasks().
+ * We go ahead and up transport_lun_stop_comp just to be sure
+ * here.
+ */
+ spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags);
+ complete(&T_TASK(cmd)->transport_lun_stop_comp);
+ wait_for_completion(&T_TASK(cmd)->transport_lun_fe_stop_comp);
+ spin_lock_irqsave(&T_TASK(cmd)->t_state_lock, flags);
+
+ transport_all_task_dev_remove_state(cmd);
+ /*
+ * At this point, the frontend who was the originator of this
+ * struct se_cmd, now owns the structure and can be released through
+ * normal means below.
+ */
+ DEBUG_TRANSPORT_S("wait_for_tasks: Stopped"
+ " wait_for_completion(&T_TASK(cmd)transport_lun_fe_"
+ "stop_comp); for ITT: 0x%08x\n",
+ CMD_TFO(cmd)->get_task_tag(cmd));
+
+ atomic_set(&T_TASK(cmd)->transport_lun_stop, 0);
+ }
+ if (!atomic_read(&T_TASK(cmd)->t_transport_active))
+ goto remove;
+
+ atomic_set(&T_TASK(cmd)->t_transport_stop, 1);
+
+ DEBUG_TRANSPORT_S("wait_for_tasks: Stopping %p ITT: 0x%08x"
+ " i_state: %d, t_state/def_t_state: %d/%d, t_transport_stop"
+ " = TRUE\n", cmd, CMD_TFO(cmd)->get_task_tag(cmd),
+ CMD_TFO(cmd)->get_cmd_state(cmd), cmd->t_state,
+ cmd->deferred_t_state);
+
+ spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags);
+
+ wake_up_interruptible(&SE_DEV(cmd)->dev_queue_obj->thread_wq);
+
+ wait_for_completion(&T_TASK(cmd)->t_transport_stop_comp);
+
+ spin_lock_irqsave(&T_TASK(cmd)->t_state_lock, flags);
+ atomic_set(&T_TASK(cmd)->t_transport_active, 0);
+ atomic_set(&T_TASK(cmd)->t_transport_stop, 0);
+
+ DEBUG_TRANSPORT_S("wait_for_tasks: Stopped wait_for_compltion("
+ "&T_TASK(cmd)->t_transport_stop_comp) for ITT: 0x%08x\n",
+ CMD_TFO(cmd)->get_task_tag(cmd));
+remove:
+ spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags);
+ if (!remove_cmd)
+ return;
+
+ transport_generic_free_cmd(cmd, 0, 0, session_reinstatement);
+}
+
+static int transport_get_sense_codes(
+ struct se_cmd *cmd,
+ u8 *asc,
+ u8 *ascq)
+{
+ *asc = cmd->scsi_asc;
+ *ascq = cmd->scsi_ascq;
+
+ return 0;
+}
+
+static int transport_set_sense_codes(
+ struct se_cmd *cmd,
+ u8 asc,
+ u8 ascq)
+{
+ cmd->scsi_asc = asc;
+ cmd->scsi_ascq = ascq;
+
+ return 0;
+}
+
+int transport_send_check_condition_and_sense(
+ struct se_cmd *cmd,
+ u8 reason,
+ int from_transport)
+{
+ unsigned char *buffer = cmd->sense_buffer;
+ unsigned long flags;
+ int offset;
+ u8 asc = 0, ascq = 0;
+
+ spin_lock_irqsave(&T_TASK(cmd)->t_state_lock, flags);
+ if (cmd->se_cmd_flags & SCF_SENT_CHECK_CONDITION) {
+ spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags);
+ return 0;
+ }
+ cmd->se_cmd_flags |= SCF_SENT_CHECK_CONDITION;
+ spin_unlock_irqrestore(&T_TASK(cmd)->t_state_lock, flags);
+
+ if (!reason && from_transport)
+ goto after_reason;
+
+ if (!from_transport)
+ cmd->se_cmd_flags |= SCF_EMULATED_TASK_SENSE;
+ /*
+ * Data Segment and SenseLength of the fabric response PDU.
+ *
+ * TRANSPORT_SENSE_BUFFER is now set to SCSI_SENSE_BUFFERSIZE
+ * from include/scsi/scsi_cmnd.h
+ */
+ offset = CMD_TFO(cmd)->set_fabric_sense_len(cmd,
+ TRANSPORT_SENSE_BUFFER);
+ /*
+ * Actual SENSE DATA, see SPC-3 7.23.2 SPC_SENSE_KEY_OFFSET uses
+ * SENSE KEY values from include/scsi/scsi.h
+ */
+ switch (reason) {
+ case TCM_NON_EXISTENT_LUN:
+ case TCM_UNSUPPORTED_SCSI_OPCODE:
+ case TCM_SECTOR_COUNT_TOO_MANY:
+ /* CURRENT ERROR */
+ buffer[offset] = 0x70;
+ /* ILLEGAL REQUEST */
+ buffer[offset+SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST;
+ /* INVALID COMMAND OPERATION CODE */
+ buffer[offset+SPC_ASC_KEY_OFFSET] = 0x20;
+ break;
+ case TCM_UNKNOWN_MODE_PAGE:
+ /* CURRENT ERROR */
+ buffer[offset] = 0x70;
+ /* ILLEGAL REQUEST */
+ buffer[offset+SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST;
+ /* INVALID FIELD IN CDB */
+ buffer[offset+SPC_ASC_KEY_OFFSET] = 0x24;
+ break;
+ case TCM_CHECK_CONDITION_ABORT_CMD:
+ /* CURRENT ERROR */
+ buffer[offset] = 0x70;
+ /* ABORTED COMMAND */
+ buffer[offset+SPC_SENSE_KEY_OFFSET] = ABORTED_COMMAND;
+ /* BUS DEVICE RESET FUNCTION OCCURRED */
+ buffer[offset+SPC_ASC_KEY_OFFSET] = 0x29;
+ buffer[offset+SPC_ASCQ_KEY_OFFSET] = 0x03;
+ break;
+ case TCM_INCORRECT_AMOUNT_OF_DATA:
+ /* CURRENT ERROR */
+ buffer[offset] = 0x70;
+ /* ABORTED COMMAND */
+ buffer[offset+SPC_SENSE_KEY_OFFSET] = ABORTED_COMMAND;
+ /* WRITE ERROR */
+ buffer[offset+SPC_ASC_KEY_OFFSET] = 0x0c;
+ /* NOT ENOUGH UNSOLICITED DATA */
+ buffer[offset+SPC_ASCQ_KEY_OFFSET] = 0x0d;
+ break;
+ case TCM_INVALID_CDB_FIELD:
+ /* CURRENT ERROR */
+ buffer[offset] = 0x70;
+ /* ABORTED COMMAND */
+ buffer[offset+SPC_SENSE_KEY_OFFSET] = ABORTED_COMMAND;
+ /* INVALID FIELD IN CDB */
+ buffer[offset+SPC_ASC_KEY_OFFSET] = 0x24;
+ break;
+ case TCM_INVALID_PARAMETER_LIST:
+ /* CURRENT ERROR */
+ buffer[offset] = 0x70;
+ /* ABORTED COMMAND */
+ buffer[offset+SPC_SENSE_KEY_OFFSET] = ABORTED_COMMAND;
+ /* INVALID FIELD IN PARAMETER LIST */
+ buffer[offset+SPC_ASC_KEY_OFFSET] = 0x26;
+ break;
+ case TCM_UNEXPECTED_UNSOLICITED_DATA:
+ /* CURRENT ERROR */
+ buffer[offset] = 0x70;
+ /* ABORTED COMMAND */
+ buffer[offset+SPC_SENSE_KEY_OFFSET] = ABORTED_COMMAND;
+ /* WRITE ERROR */
+ buffer[offset+SPC_ASC_KEY_OFFSET] = 0x0c;
+ /* UNEXPECTED_UNSOLICITED_DATA */
+ buffer[offset+SPC_ASCQ_KEY_OFFSET] = 0x0c;
+ break;
+ case TCM_SERVICE_CRC_ERROR:
+ /* CURRENT ERROR */
+ buffer[offset] = 0x70;
+ /* ABORTED COMMAND */
+ buffer[offset+SPC_SENSE_KEY_OFFSET] = ABORTED_COMMAND;
+ /* PROTOCOL SERVICE CRC ERROR */
+ buffer[offset+SPC_ASC_KEY_OFFSET] = 0x47;
+ /* N/A */
+ buffer[offset+SPC_ASCQ_KEY_OFFSET] = 0x05;
+ break;
+ case TCM_SNACK_REJECTED:
+ /* CURRENT ERROR */
+ buffer[offset] = 0x70;
+ /* ABORTED COMMAND */
+ buffer[offset+SPC_SENSE_KEY_OFFSET] = ABORTED_COMMAND;
+ /* READ ERROR */
+ buffer[offset+SPC_ASC_KEY_OFFSET] = 0x11;
+ /* FAILED RETRANSMISSION REQUEST */
+ buffer[offset+SPC_ASCQ_KEY_OFFSET] = 0x13;
+ break;
+ case TCM_WRITE_PROTECTED:
+ /* CURRENT ERROR */
+ buffer[offset] = 0x70;
+ /* DATA PROTECT */
+ buffer[offset+SPC_SENSE_KEY_OFFSET] = DATA_PROTECT;
+ /* WRITE PROTECTED */
+ buffer[offset+SPC_ASC_KEY_OFFSET] = 0x27;
+ break;
+ case TCM_CHECK_CONDITION_UNIT_ATTENTION:
+ /* CURRENT ERROR */
+ buffer[offset] = 0x70;
+ /* UNIT ATTENTION */
+ buffer[offset+SPC_SENSE_KEY_OFFSET] = UNIT_ATTENTION;
+ core_scsi3_ua_for_check_condition(cmd, &asc, &ascq);
+ buffer[offset+SPC_ASC_KEY_OFFSET] = asc;
+ buffer[offset+SPC_ASCQ_KEY_OFFSET] = ascq;
+ break;
+ case TCM_CHECK_CONDITION_NOT_READY:
+ /* CURRENT ERROR */
+ buffer[offset] = 0x70;
+ /* Not Ready */
+ buffer[offset+SPC_SENSE_KEY_OFFSET] = NOT_READY;
+ transport_get_sense_codes(cmd, &asc, &ascq);
+ buffer[offset+SPC_ASC_KEY_OFFSET] = asc;
+ buffer[offset+SPC_ASCQ_KEY_OFFSET] = ascq;
+ break;
+ case TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE:
+ default:
+ /* CURRENT ERROR */
+ buffer[offset] = 0x70;
+ /* ILLEGAL REQUEST */
+ buffer[offset+SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST;
+ /* LOGICAL UNIT COMMUNICATION FAILURE */
+ buffer[offset+SPC_ASC_KEY_OFFSET] = 0x80;
+ break;
+ }
+ /*
+ * This code uses linux/include/scsi/scsi.h SAM status codes!
+ */
+ cmd->scsi_status = SAM_STAT_CHECK_CONDITION;
+ /*
+ * Automatically padded, this value is encoded in the fabric's
+ * data_length response PDU containing the SCSI defined sense data.
+ */
+ cmd->scsi_sense_length = TRANSPORT_SENSE_BUFFER + offset;
+
+after_reason:
+ CMD_TFO(cmd)->queue_status(cmd);
+ return 0;
+}
+EXPORT_SYMBOL(transport_send_check_condition_and_sense);
+
+int transport_check_aborted_status(struct se_cmd *cmd, int send_status)
+{
+ int ret = 0;
+
+ if (atomic_read(&T_TASK(cmd)->t_transport_aborted) != 0) {
+ if (!(send_status) ||
+ (cmd->se_cmd_flags & SCF_SENT_DELAYED_TAS))
+ return 1;
+#if 0
+ printk(KERN_INFO "Sending delayed SAM_STAT_TASK_ABORTED"
+ " status for CDB: 0x%02x ITT: 0x%08x\n",
+ T_TASK(cmd)->t_task_cdb[0],
+ CMD_TFO(cmd)->get_task_tag(cmd));
+#endif
+ cmd->se_cmd_flags |= SCF_SENT_DELAYED_TAS;
+ CMD_TFO(cmd)->queue_status(cmd);
+ ret = 1;
+ }
+ return ret;
+}
+EXPORT_SYMBOL(transport_check_aborted_status);
+
+void transport_send_task_abort(struct se_cmd *cmd)
+{
+ /*
+ * If there are still expected incoming fabric WRITEs, we wait
+ * until until they have completed before sending a TASK_ABORTED
+ * response. This response with TASK_ABORTED status will be
+ * queued back to fabric module by transport_check_aborted_status().
+ */
+ if (cmd->data_direction == DMA_TO_DEVICE) {
+ if (CMD_TFO(cmd)->write_pending_status(cmd) != 0) {
+ atomic_inc(&T_TASK(cmd)->t_transport_aborted);
+ smp_mb__after_atomic_inc();
+ cmd->scsi_status = SAM_STAT_TASK_ABORTED;
+ transport_new_cmd_failure(cmd);
+ return;
+ }
+ }
+ cmd->scsi_status = SAM_STAT_TASK_ABORTED;
+#if 0
+ printk(KERN_INFO "Setting SAM_STAT_TASK_ABORTED status for CDB: 0x%02x,"
+ " ITT: 0x%08x\n", T_TASK(cmd)->t_task_cdb[0],
+ CMD_TFO(cmd)->get_task_tag(cmd));
+#endif
+ CMD_TFO(cmd)->queue_status(cmd);
+}
+
+/* transport_generic_do_tmr():
+ *
+ *
+ */
+int transport_generic_do_tmr(struct se_cmd *cmd)
+{
+ struct se_cmd *ref_cmd;
+ struct se_device *dev = SE_DEV(cmd);
+ struct se_tmr_req *tmr = cmd->se_tmr_req;
+ int ret;
+
+ switch (tmr->function) {
+ case ABORT_TASK:
+ ref_cmd = tmr->ref_cmd;
+ tmr->response = TMR_FUNCTION_REJECTED;
+ break;
+ case ABORT_TASK_SET:
+ case CLEAR_ACA:
+ case CLEAR_TASK_SET:
+ tmr->response = TMR_TASK_MGMT_FUNCTION_NOT_SUPPORTED;
+ break;
+ case LUN_RESET:
+ ret = core_tmr_lun_reset(dev, tmr, NULL, NULL);
+ tmr->response = (!ret) ? TMR_FUNCTION_COMPLETE :
+ TMR_FUNCTION_REJECTED;
+ break;
+#if 0
+ case TARGET_WARM_RESET:
+ transport_generic_host_reset(dev->se_hba);
+ tmr->response = TMR_FUNCTION_REJECTED;
+ break;
+ case TARGET_COLD_RESET:
+ transport_generic_host_reset(dev->se_hba);
+ transport_generic_cold_reset(dev->se_hba);
+ tmr->response = TMR_FUNCTION_REJECTED;
+ break;
+#endif
+ default:
+ printk(KERN_ERR "Uknown TMR function: 0x%02x.\n",
+ tmr->function);
+ tmr->response = TMR_FUNCTION_REJECTED;
+ break;
+ }
+
+ cmd->t_state = TRANSPORT_ISTATE_PROCESSING;
+ CMD_TFO(cmd)->queue_tm_rsp(cmd);
+
+ transport_cmd_check_stop(cmd, 2, 0);
+ return 0;
+}
+
+/*
+ * Called with spin_lock_irq(&dev->execute_task_lock); held
+ *
+ */
+static struct se_task *
+transport_get_task_from_state_list(struct se_device *dev)
+{
+ struct se_task *task;
+
+ if (list_empty(&dev->state_task_list))
+ return NULL;
+
+ list_for_each_entry(task, &dev->state_task_list, t_state_list)
+ break;
+
+ list_del(&task->t_state_list);
+ atomic_set(&task->task_state_active, 0);
+
+ return task;
+}
+
+static void transport_processing_shutdown(struct se_device *dev)
+{
+ struct se_cmd *cmd;
+ struct se_queue_req *qr;
+ struct se_task *task;
+ u8 state;
+ unsigned long flags;
+ /*
+ * Empty the struct se_device's struct se_task state list.
+ */
+ spin_lock_irqsave(&dev->execute_task_lock, flags);
+ while ((task = transport_get_task_from_state_list(dev))) {
+ if (!(TASK_CMD(task))) {
+ printk(KERN_ERR "TASK_CMD(task) is NULL!\n");
+ continue;
+ }
+ cmd = TASK_CMD(task);
+
+ if (!T_TASK(cmd)) {
+ printk(KERN_ERR "T_TASK(cmd) is NULL for task: %p cmd:"
+ " %p ITT: 0x%08x\n", task, cmd,
+ CMD_TFO(cmd)->get_task_tag(cmd));
+ continue;
+ }
+ spin_unlock_irqrestore(&dev->execute_task_lock, flags);
+
+ spin_lock_irqsave(&T_TASK(cmd)->t_state_lock, flags);
+
+ DEBUG_DO("PT: cmd: %p task: %p ITT/CmdSN: 0x%08x/0x%08x,"
+ " i_state/def_i_state: %d/%d, t_state/def_t_state:"
+ " %d/%d cdb: 0x%02x\n", cmd, task,
+ CMD_TFO(cmd)->get_task_tag(cmd), cmd->cmd_sn,
+ CMD_TFO(cmd)->get_cmd_state(cmd), cmd->deferred_i_state,
+ cmd->t_state, cmd->deferred_t_state,
+ T_TASK(cmd)->t_task_cdb[0]);
+ DEBUG_DO("PT: ITT[0x%08x] - t_task_cdbs: %d t_task_cdbs_left:"
+ " %d t_task_cdbs_sent: %d -- t_transport_active: %d"
+ " t_transport_stop: %d t_transport_sent: %d\n",
+ CMD_TFO(cmd)->get_task_tag(cmd),
+ T_TASK(cmd)->t_task_cdbs,
+ atomic_read(&T_TASK(cmd)->t_task_cdbs_left),
+ atomic_read(&T_TASK(cmd)->t_task_cdbs_sent),
+ atomic_read(&T_TASK(cmd)->t_transport_active),
+ atomic_read(&T_TASK(cmd)->t_transport_stop),
+ atomic_read(&T_TASK(cmd)->t_transport_sent));
+
+ if (atomic_read(&task->task_active)) {
+ atomic_set(&task->task_stop, 1);
+ spin_unlock_irqrestore(
+ &T_TASK(cmd)->t_state_lock, flags);
+
+ DEBUG_DO("Waiting for task: %p to shutdown for dev:"
+ " %p\n", task, dev);
+ wait_for_completion(&task->task_stop_comp);
+ DEBUG_DO("Completed task: %p shutdown for dev: %p\n",
+ task, dev);
+
+ spin_lock_irqsave(&T_TASK(cmd)->t_state_lock, flags);
+ atomic_dec(&T_TASK(cmd)->t_task_cdbs_left);
+
+ atomic_set(&task->task_active, 0);
+ atomic_set(&task->task_stop, 0);
+ }
+ __transport_stop_task_timer(task, &flags);
+
+ if (!(atomic_dec_and_test(&T_TASK(cmd)->t_task_cdbs_ex_left))) {
+ spin_unlock_irqrestore(
+ &T_TASK(cmd)->t_state_lock, flags);
+
+ DEBUG_DO("Skipping task: %p, dev: %p for"
+ " t_task_cdbs_ex_left: %d\n", task, dev,
+ atomic_read(&T_TASK(cmd)->t_task_cdbs_ex_left));
+
+ spin_lock_irqsave(&dev->execute_task_lock, flags);
+ continue;
+ }
+
+ if (atomic_read(&T_TASK(cmd)->t_transport_active)) {
+ DEBUG_DO("got t_transport_active = 1 for task: %p, dev:"
+ " %p\n", task, dev);
+
+ if (atomic_read(&T_TASK(cmd)->t_fe_count)) {
+ spin_unlock_irqrestore(
+ &T_TASK(cmd)->t_state_lock, flags);
+ transport_send_check_condition_and_sense(
+ cmd, TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE,
+ 0);
+ transport_remove_cmd_from_queue(cmd,
+ SE_DEV(cmd)->dev_queue_obj);
+
+ transport_lun_remove_cmd(cmd);
+ transport_cmd_check_stop(cmd, 1, 0);
+ } else {
+ spin_unlock_irqrestore(
+ &T_TASK(cmd)->t_state_lock, flags);
+
+ transport_remove_cmd_from_queue(cmd,
+ SE_DEV(cmd)->dev_queue_obj);
+
+ transport_lun_remove_cmd(cmd);
+
+ if (transport_cmd_check_stop(cmd, 1, 0))
+ transport_generic_remove(cmd, 0, 0);
+ }
+
+ spin_lock_irqsave(&dev->execute_task_lock, flags);
+ continue;
+ }
+ DEBUG_DO("Got t_transport_active = 0 for task: %p, dev: %p\n",
+ task, dev);
+
+ if (atomic_read(&T_TASK(cmd)->t_fe_count)) {
+ spin_unlock_irqrestore(
+ &T_TASK(cmd)->t_state_lock, flags);
+ transport_send_check_condition_and_sense(cmd,
+ TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE, 0);
+ transport_remove_cmd_from_queue(cmd,
+ SE_DEV(cmd)->dev_queue_obj);
+
+ transport_lun_remove_cmd(cmd);
+ transport_cmd_check_stop(cmd, 1, 0);
+ } else {
+ spin_unlock_irqrestore(
+ &T_TASK(cmd)->t_state_lock, flags);
+
+ transport_remove_cmd_from_queue(cmd,
+ SE_DEV(cmd)->dev_queue_obj);
+ transport_lun_remove_cmd(cmd);
+
+ if (transport_cmd_check_stop(cmd, 1, 0))
+ transport_generic_remove(cmd, 0, 0);
+ }
+
+ spin_lock_irqsave(&dev->execute_task_lock, flags);
+ }
+ spin_unlock_irqrestore(&dev->execute_task_lock, flags);
+ /*
+ * Empty the struct se_device's struct se_cmd list.
+ */
+ spin_lock_irqsave(&dev->dev_queue_obj->cmd_queue_lock, flags);
+ while ((qr = __transport_get_qr_from_queue(dev->dev_queue_obj))) {
+ spin_unlock_irqrestore(
+ &dev->dev_queue_obj->cmd_queue_lock, flags);
+ cmd = (struct se_cmd *)qr->cmd;
+ state = qr->state;
+ kfree(qr);
+
+ DEBUG_DO("From Device Queue: cmd: %p t_state: %d\n",
+ cmd, state);
+
+ if (atomic_read(&T_TASK(cmd)->t_fe_count)) {
+ transport_send_check_condition_and_sense(cmd,
+ TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE, 0);
+
+ transport_lun_remove_cmd(cmd);
+ transport_cmd_check_stop(cmd, 1, 0);
+ } else {
+ transport_lun_remove_cmd(cmd);
+ if (transport_cmd_check_stop(cmd, 1, 0))
+ transport_generic_remove(cmd, 0, 0);
+ }
+ spin_lock_irqsave(&dev->dev_queue_obj->cmd_queue_lock, flags);
+ }
+ spin_unlock_irqrestore(&dev->dev_queue_obj->cmd_queue_lock, flags);
+}
+
+/* transport_processing_thread():
+ *
+ *
+ */
+static int transport_processing_thread(void *param)
+{
+ int ret, t_state;
+ struct se_cmd *cmd;
+ struct se_device *dev = (struct se_device *) param;
+ struct se_queue_req *qr;
+
+ set_user_nice(current, -20);
+
+ while (!kthread_should_stop()) {
+ ret = wait_event_interruptible(dev->dev_queue_obj->thread_wq,
+ atomic_read(&dev->dev_queue_obj->queue_cnt) ||
+ kthread_should_stop());
+ if (ret < 0)
+ goto out;
+
+ spin_lock_irq(&dev->dev_status_lock);
+ if (dev->dev_status & TRANSPORT_DEVICE_SHUTDOWN) {
+ spin_unlock_irq(&dev->dev_status_lock);
+ transport_processing_shutdown(dev);
+ continue;
+ }
+ spin_unlock_irq(&dev->dev_status_lock);
+
+get_cmd:
+ __transport_execute_tasks(dev);
+
+ qr = transport_get_qr_from_queue(dev->dev_queue_obj);
+ if (!(qr))
+ continue;
+
+ cmd = (struct se_cmd *)qr->cmd;
+ t_state = qr->state;
+ kfree(qr);
+
+ switch (t_state) {
+ case TRANSPORT_NEW_CMD_MAP:
+ if (!(CMD_TFO(cmd)->new_cmd_map)) {
+ printk(KERN_ERR "CMD_TFO(cmd)->new_cmd_map is"
+ " NULL for TRANSPORT_NEW_CMD_MAP\n");
+ BUG();
+ }
+ ret = CMD_TFO(cmd)->new_cmd_map(cmd);
+ if (ret < 0) {
+ cmd->transport_error_status = ret;
+ transport_generic_request_failure(cmd, NULL,
+ 0, (cmd->data_direction !=
+ DMA_TO_DEVICE));
+ break;
+ }
+ /* Fall through */
+ case TRANSPORT_NEW_CMD:
+ ret = transport_generic_new_cmd(cmd);
+ if (ret < 0) {
+ cmd->transport_error_status = ret;
+ transport_generic_request_failure(cmd, NULL,
+ 0, (cmd->data_direction !=
+ DMA_TO_DEVICE));
+ }
+ break;
+ case TRANSPORT_PROCESS_WRITE:
+ transport_generic_process_write(cmd);
+ break;
+ case TRANSPORT_COMPLETE_OK:
+ transport_stop_all_task_timers(cmd);
+ transport_generic_complete_ok(cmd);
+ break;
+ case TRANSPORT_REMOVE:
+ transport_generic_remove(cmd, 1, 0);
+ break;
+ case TRANSPORT_PROCESS_TMR:
+ transport_generic_do_tmr(cmd);
+ break;
+ case TRANSPORT_COMPLETE_FAILURE:
+ transport_generic_request_failure(cmd, NULL, 1, 1);
+ break;
+ case TRANSPORT_COMPLETE_TIMEOUT:
+ transport_stop_all_task_timers(cmd);
+ transport_generic_request_timeout(cmd);
+ break;
+ default:
+ printk(KERN_ERR "Unknown t_state: %d deferred_t_state:"
+ " %d for ITT: 0x%08x i_state: %d on SE LUN:"
+ " %u\n", t_state, cmd->deferred_t_state,
+ CMD_TFO(cmd)->get_task_tag(cmd),
+ CMD_TFO(cmd)->get_cmd_state(cmd),
+ SE_LUN(cmd)->unpacked_lun);
+ BUG();
+ }
+
+ goto get_cmd;
+ }
+
+out:
+ transport_release_all_cmds(dev);
+ dev->process_thread = NULL;
+ return 0;
+}
diff --git a/drivers/target/target_core_ua.c b/drivers/target/target_core_ua.c
new file mode 100644
index 0000000..a2ef346
--- /dev/null
+++ b/drivers/target/target_core_ua.c
@@ -0,0 +1,332 @@
+/*******************************************************************************
+ * Filename: target_core_ua.c
+ *
+ * This file contains logic for SPC-3 Unit Attention emulation
+ *
+ * Copyright (c) 2009,2010 Rising Tide Systems
+ * Copyright (c) 2009,2010 Linux-iSCSI.org
+ *
+ * Nicholas A. Bellinger <nab@kernel.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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ ******************************************************************************/
+
+#include <linux/version.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+
+#include <target/target_core_base.h>
+#include <target/target_core_device.h>
+#include <target/target_core_transport.h>
+#include <target/target_core_fabric_ops.h>
+#include <target/target_core_configfs.h>
+
+#include "target_core_alua.h"
+#include "target_core_hba.h"
+#include "target_core_pr.h"
+#include "target_core_ua.h"
+
+int core_scsi3_ua_check(
+ struct se_cmd *cmd,
+ unsigned char *cdb)
+{
+ struct se_dev_entry *deve;
+ struct se_session *sess = cmd->se_sess;
+ struct se_node_acl *nacl;
+
+ if (!(sess))
+ return 0;
+
+ nacl = sess->se_node_acl;
+ if (!(nacl))
+ return 0;
+
+ deve = &nacl->device_list[cmd->orig_fe_lun];
+ if (!(atomic_read(&deve->ua_count)))
+ return 0;
+ /*
+ * From sam4r14, section 5.14 Unit attention condition:
+ *
+ * a) if an INQUIRY command enters the enabled command state, the
+ * device server shall process the INQUIRY command and shall neither
+ * report nor clear any unit attention condition;
+ * b) if a REPORT LUNS command enters the enabled command state, the
+ * device server shall process the REPORT LUNS command and shall not
+ * report any unit attention condition;
+ * e) if a REQUEST SENSE command enters the enabled command state while
+ * a unit attention condition exists for the SCSI initiator port
+ * associated with the I_T nexus on which the REQUEST SENSE command
+ * was received, then the device server shall process the command
+ * and either:
+ */
+ switch (cdb[0]) {
+ case INQUIRY:
+ case REPORT_LUNS:
+ case REQUEST_SENSE:
+ return 0;
+ default:
+ return -1;
+ }
+
+ return -1;
+}
+
+int core_scsi3_ua_allocate(
+ struct se_node_acl *nacl,
+ u32 unpacked_lun,
+ u8 asc,
+ u8 ascq)
+{
+ struct se_dev_entry *deve;
+ struct se_ua *ua, *ua_p, *ua_tmp;
+ /*
+ * PASSTHROUGH OPS
+ */
+ if (!(nacl))
+ return -1;
+
+ ua = kmem_cache_zalloc(se_ua_cache, GFP_ATOMIC);
+ if (!(ua)) {
+ printk(KERN_ERR "Unable to allocate struct se_ua\n");
+ return -1;
+ }
+ INIT_LIST_HEAD(&ua->ua_dev_list);
+ INIT_LIST_HEAD(&ua->ua_nacl_list);
+
+ ua->ua_nacl = nacl;
+ ua->ua_asc = asc;
+ ua->ua_ascq = ascq;
+
+ spin_lock_irq(&nacl->device_list_lock);
+ deve = &nacl->device_list[unpacked_lun];
+
+ spin_lock(&deve->ua_lock);
+ list_for_each_entry_safe(ua_p, ua_tmp, &deve->ua_list, ua_nacl_list) {
+ /*
+ * Do not report the same UNIT ATTENTION twice..
+ */
+ if ((ua_p->ua_asc == asc) && (ua_p->ua_ascq == ascq)) {
+ spin_unlock(&deve->ua_lock);
+ spin_unlock_irq(&nacl->device_list_lock);
+ kmem_cache_free(se_ua_cache, ua);
+ return 0;
+ }
+ /*
+ * Attach the highest priority Unit Attention to
+ * the head of the list following sam4r14,
+ * Section 5.14 Unit Attention Condition:
+ *
+ * POWER ON, RESET, OR BUS DEVICE RESET OCCURRED highest
+ * POWER ON OCCURRED or
+ * DEVICE INTERNAL RESET
+ * SCSI BUS RESET OCCURRED or
+ * MICROCODE HAS BEEN CHANGED or
+ * protocol specific
+ * BUS DEVICE RESET FUNCTION OCCURRED
+ * I_T NEXUS LOSS OCCURRED
+ * COMMANDS CLEARED BY POWER LOSS NOTIFICATION
+ * all others Lowest
+ *
+ * Each of the ASCQ codes listed above are defined in
+ * the 29h ASC family, see spc4r17 Table D.1
+ */
+ if (ua_p->ua_asc == 0x29) {
+ if ((asc == 0x29) && (ascq > ua_p->ua_ascq))
+ list_add(&ua->ua_nacl_list,
+ &deve->ua_list);
+ else
+ list_add_tail(&ua->ua_nacl_list,
+ &deve->ua_list);
+ } else if (ua_p->ua_asc == 0x2a) {
+ /*
+ * Incoming Family 29h ASCQ codes will override
+ * Family 2AHh ASCQ codes for Unit Attention condition.
+ */
+ if ((asc == 0x29) || (ascq > ua_p->ua_asc))
+ list_add(&ua->ua_nacl_list,
+ &deve->ua_list);
+ else
+ list_add_tail(&ua->ua_nacl_list,
+ &deve->ua_list);
+ } else
+ list_add_tail(&ua->ua_nacl_list,
+ &deve->ua_list);
+ spin_unlock(&deve->ua_lock);
+ spin_unlock_irq(&nacl->device_list_lock);
+
+ atomic_inc(&deve->ua_count);
+ smp_mb__after_atomic_inc();
+ return 0;
+ }
+ list_add_tail(&ua->ua_nacl_list, &deve->ua_list);
+ spin_unlock(&deve->ua_lock);
+ spin_unlock_irq(&nacl->device_list_lock);
+
+ printk(KERN_INFO "[%s]: Allocated UNIT ATTENTION, mapped LUN: %u, ASC:"
+ " 0x%02x, ASCQ: 0x%02x\n",
+ TPG_TFO(nacl->se_tpg)->get_fabric_name(), unpacked_lun,
+ asc, ascq);
+
+ atomic_inc(&deve->ua_count);
+ smp_mb__after_atomic_inc();
+ return 0;
+}
+
+void core_scsi3_ua_release_all(
+ struct se_dev_entry *deve)
+{
+ struct se_ua *ua, *ua_p;
+
+ spin_lock(&deve->ua_lock);
+ list_for_each_entry_safe(ua, ua_p, &deve->ua_list, ua_nacl_list) {
+ list_del(&ua->ua_nacl_list);
+ kmem_cache_free(se_ua_cache, ua);
+
+ atomic_dec(&deve->ua_count);
+ smp_mb__after_atomic_dec();
+ }
+ spin_unlock(&deve->ua_lock);
+}
+
+void core_scsi3_ua_for_check_condition(
+ struct se_cmd *cmd,
+ u8 *asc,
+ u8 *ascq)
+{
+ struct se_device *dev = SE_DEV(cmd);
+ struct se_dev_entry *deve;
+ struct se_session *sess = cmd->se_sess;
+ struct se_node_acl *nacl;
+ struct se_ua *ua = NULL, *ua_p;
+ int head = 1;
+
+ if (!(sess))
+ return;
+
+ nacl = sess->se_node_acl;
+ if (!(nacl))
+ return;
+
+ spin_lock_irq(&nacl->device_list_lock);
+ deve = &nacl->device_list[cmd->orig_fe_lun];
+ if (!(atomic_read(&deve->ua_count))) {
+ spin_unlock_irq(&nacl->device_list_lock);
+ return;
+ }
+ /*
+ * The highest priority Unit Attentions are placed at the head of the
+ * struct se_dev_entry->ua_list, and will be returned in CHECK_CONDITION +
+ * sense data for the received CDB.
+ */
+ spin_lock(&deve->ua_lock);
+ list_for_each_entry_safe(ua, ua_p, &deve->ua_list, ua_nacl_list) {
+ /*
+ * For ua_intlck_ctrl code not equal to 00b, only report the
+ * highest priority UNIT_ATTENTION and ASC/ASCQ without
+ * clearing it.
+ */
+ if (DEV_ATTRIB(dev)->emulate_ua_intlck_ctrl != 0) {
+ *asc = ua->ua_asc;
+ *ascq = ua->ua_ascq;
+ break;
+ }
+ /*
+ * Otherwise for the default 00b, release the UNIT ATTENTION
+ * condition. Return the ASC/ASCQ of the higest priority UA
+ * (head of the list) in the outgoing CHECK_CONDITION + sense.
+ */
+ if (head) {
+ *asc = ua->ua_asc;
+ *ascq = ua->ua_ascq;
+ head = 0;
+ }
+ list_del(&ua->ua_nacl_list);
+ kmem_cache_free(se_ua_cache, ua);
+
+ atomic_dec(&deve->ua_count);
+ smp_mb__after_atomic_dec();
+ }
+ spin_unlock(&deve->ua_lock);
+ spin_unlock_irq(&nacl->device_list_lock);
+
+ printk(KERN_INFO "[%s]: %s UNIT ATTENTION condition with"
+ " INTLCK_CTRL: %d, mapped LUN: %u, got CDB: 0x%02x"
+ " reported ASC: 0x%02x, ASCQ: 0x%02x\n",
+ TPG_TFO(nacl->se_tpg)->get_fabric_name(),
+ (DEV_ATTRIB(dev)->emulate_ua_intlck_ctrl != 0) ? "Reporting" :
+ "Releasing", DEV_ATTRIB(dev)->emulate_ua_intlck_ctrl,
+ cmd->orig_fe_lun, T_TASK(cmd)->t_task_cdb[0], *asc, *ascq);
+}
+
+int core_scsi3_ua_clear_for_request_sense(
+ struct se_cmd *cmd,
+ u8 *asc,
+ u8 *ascq)
+{
+ struct se_dev_entry *deve;
+ struct se_session *sess = cmd->se_sess;
+ struct se_node_acl *nacl;
+ struct se_ua *ua = NULL, *ua_p;
+ int head = 1;
+
+ if (!(sess))
+ return -1;
+
+ nacl = sess->se_node_acl;
+ if (!(nacl))
+ return -1;
+
+ spin_lock_irq(&nacl->device_list_lock);
+ deve = &nacl->device_list[cmd->orig_fe_lun];
+ if (!(atomic_read(&deve->ua_count))) {
+ spin_unlock_irq(&nacl->device_list_lock);
+ return -1;
+ }
+ /*
+ * The highest priority Unit Attentions are placed at the head of the
+ * struct se_dev_entry->ua_list. The First (and hence highest priority)
+ * ASC/ASCQ will be returned in REQUEST_SENSE payload data for the
+ * matching struct se_lun.
+ *
+ * Once the returning ASC/ASCQ values are set, we go ahead and
+ * release all of the Unit Attention conditions for the assoicated
+ * struct se_lun.
+ */
+ spin_lock(&deve->ua_lock);
+ list_for_each_entry_safe(ua, ua_p, &deve->ua_list, ua_nacl_list) {
+ if (head) {
+ *asc = ua->ua_asc;
+ *ascq = ua->ua_ascq;
+ head = 0;
+ }
+ list_del(&ua->ua_nacl_list);
+ kmem_cache_free(se_ua_cache, ua);
+
+ atomic_dec(&deve->ua_count);
+ smp_mb__after_atomic_dec();
+ }
+ spin_unlock(&deve->ua_lock);
+ spin_unlock_irq(&nacl->device_list_lock);
+
+ printk(KERN_INFO "[%s]: Released UNIT ATTENTION condition, mapped"
+ " LUN: %u, got REQUEST_SENSE reported ASC: 0x%02x,"
+ " ASCQ: 0x%02x\n", TPG_TFO(nacl->se_tpg)->get_fabric_name(),
+ cmd->orig_fe_lun, *asc, *ascq);
+
+ return (head) ? -1 : 0;
+}
diff --git a/drivers/target/target_core_ua.h b/drivers/target/target_core_ua.h
new file mode 100644
index 0000000..6e6b034
--- /dev/null
+++ b/drivers/target/target_core_ua.h
@@ -0,0 +1,36 @@
+#ifndef TARGET_CORE_UA_H
+
+/*
+ * From spc4r17, Table D.1: ASC and ASCQ Assignement
+ */
+#define ASCQ_29H_POWER_ON_RESET_OR_BUS_DEVICE_RESET_OCCURED 0x00
+#define ASCQ_29H_POWER_ON_OCCURRED 0x01
+#define ASCQ_29H_SCSI_BUS_RESET_OCCURED 0x02
+#define ASCQ_29H_BUS_DEVICE_RESET_FUNCTION_OCCURRED 0x03
+#define ASCQ_29H_DEVICE_INTERNAL_RESET 0x04
+#define ASCQ_29H_TRANSCEIVER_MODE_CHANGED_TO_SINGLE_ENDED 0x05
+#define ASCQ_29H_TRANSCEIVER_MODE_CHANGED_TO_LVD 0x06
+#define ASCQ_29H_NEXUS_LOSS_OCCURRED 0x07
+
+#define ASCQ_2AH_PARAMETERS_CHANGED 0x00
+#define ASCQ_2AH_MODE_PARAMETERS_CHANGED 0x01
+#define ASCQ_2AH_LOG_PARAMETERS_CHANGED 0x02
+#define ASCQ_2AH_RESERVATIONS_PREEMPTED 0x03
+#define ASCQ_2AH_RESERVATIONS_RELEASED 0x04
+#define ASCQ_2AH_REGISTRATIONS_PREEMPTED 0x05
+#define ASCQ_2AH_ASYMMETRIC_ACCESS_STATE_CHANGED 0x06
+#define ASCQ_2AH_IMPLICT_ASYMMETRIC_ACCESS_STATE_TRANSITION_FAILED 0x07
+#define ASCQ_2AH_PRIORITY_CHANGED 0x08
+
+#define ASCQ_2CH_PREVIOUS_RESERVATION_CONFLICT_STATUS 0x09
+
+extern struct kmem_cache *se_ua_cache;
+
+extern int core_scsi3_ua_check(struct se_cmd *, unsigned char *);
+extern int core_scsi3_ua_allocate(struct se_node_acl *, u32, u8, u8);
+extern void core_scsi3_ua_release_all(struct se_dev_entry *);
+extern void core_scsi3_ua_for_check_condition(struct se_cmd *, u8 *, u8 *);
+extern int core_scsi3_ua_clear_for_request_sense(struct se_cmd *,
+ u8 *, u8 *);
+
+#endif /* TARGET_CORE_UA_H */
diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
index bf7c687..f7a5dba 100644
--- a/drivers/thermal/Kconfig
+++ b/drivers/thermal/Kconfig
@@ -4,6 +4,7 @@
menuconfig THERMAL
tristate "Generic Thermal sysfs driver"
+ depends on NET
help
Generic Thermal Sysfs driver offers a generic mechanism for
thermal management. Usually it's made up of one or more thermal
diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_sys.c
index 13c72c6..7d0e63c 100644
--- a/drivers/thermal/thermal_sys.c
+++ b/drivers/thermal/thermal_sys.c
@@ -32,6 +32,8 @@
#include <linux/thermal.h>
#include <linux/spinlock.h>
#include <linux/reboot.h>
+#include <net/netlink.h>
+#include <net/genetlink.h>
MODULE_AUTHOR("Zhang Rui");
MODULE_DESCRIPTION("Generic thermal management sysfs support");
@@ -58,6 +60,22 @@ static LIST_HEAD(thermal_tz_list);
static LIST_HEAD(thermal_cdev_list);
static DEFINE_MUTEX(thermal_list_lock);
+static unsigned int thermal_event_seqnum;
+
+static struct genl_family thermal_event_genl_family = {
+ .id = GENL_ID_GENERATE,
+ .name = THERMAL_GENL_FAMILY_NAME,
+ .version = THERMAL_GENL_VERSION,
+ .maxattr = THERMAL_GENL_ATTR_MAX,
+};
+
+static struct genl_multicast_group thermal_event_mcgrp = {
+ .name = THERMAL_GENL_MCAST_GROUP_NAME,
+};
+
+static int genetlink_init(void);
+static void genetlink_exit(void);
+
static int get_idr(struct idr *idr, struct mutex *lock, int *id)
{
int err;
@@ -823,11 +841,8 @@ static struct class thermal_class = {
* @devdata: device private data.
* @ops: standard thermal cooling devices callbacks.
*/
-struct thermal_cooling_device *thermal_cooling_device_register(char *type,
- void *devdata,
- struct
- thermal_cooling_device_ops
- *ops)
+struct thermal_cooling_device *thermal_cooling_device_register(
+ char *type, void *devdata, const struct thermal_cooling_device_ops *ops)
{
struct thermal_cooling_device *cdev;
struct thermal_zone_device *pos;
@@ -1048,13 +1063,9 @@ EXPORT_SYMBOL(thermal_zone_device_update);
* section 11.1.5.1 of the ACPI specification 3.0.
*/
struct thermal_zone_device *thermal_zone_device_register(char *type,
- int trips,
- void *devdata, struct
- thermal_zone_device_ops
- *ops, int tc1, int
- tc2,
- int passive_delay,
- int polling_delay)
+ int trips, void *devdata,
+ const struct thermal_zone_device_ops *ops,
+ int tc1, int tc2, int passive_delay, int polling_delay)
{
struct thermal_zone_device *tz;
struct thermal_cooling_device *pos;
@@ -1214,6 +1225,82 @@ void thermal_zone_device_unregister(struct thermal_zone_device *tz)
EXPORT_SYMBOL(thermal_zone_device_unregister);
+int generate_netlink_event(u32 orig, enum events event)
+{
+ struct sk_buff *skb;
+ struct nlattr *attr;
+ struct thermal_genl_event *thermal_event;
+ void *msg_header;
+ int size;
+ int result;
+
+ /* allocate memory */
+ size = nla_total_size(sizeof(struct thermal_genl_event)) + \
+ nla_total_size(0);
+
+ skb = genlmsg_new(size, GFP_ATOMIC);
+ if (!skb)
+ return -ENOMEM;
+
+ /* add the genetlink message header */
+ msg_header = genlmsg_put(skb, 0, thermal_event_seqnum++,
+ &thermal_event_genl_family, 0,
+ THERMAL_GENL_CMD_EVENT);
+ if (!msg_header) {
+ nlmsg_free(skb);
+ return -ENOMEM;
+ }
+
+ /* fill the data */
+ attr = nla_reserve(skb, THERMAL_GENL_ATTR_EVENT, \
+ sizeof(struct thermal_genl_event));
+
+ if (!attr) {
+ nlmsg_free(skb);
+ return -EINVAL;
+ }
+
+ thermal_event = nla_data(attr);
+ if (!thermal_event) {
+ nlmsg_free(skb);
+ return -EINVAL;
+ }
+
+ memset(thermal_event, 0, sizeof(struct thermal_genl_event));
+
+ thermal_event->orig = orig;
+ thermal_event->event = event;
+
+ /* send multicast genetlink message */
+ result = genlmsg_end(skb, msg_header);
+ if (result < 0) {
+ nlmsg_free(skb);
+ return result;
+ }
+
+ result = genlmsg_multicast(skb, 0, thermal_event_mcgrp.id, GFP_ATOMIC);
+ if (result)
+ printk(KERN_INFO "failed to send netlink event:%d", result);
+
+ return result;
+}
+EXPORT_SYMBOL(generate_netlink_event);
+
+static int genetlink_init(void)
+{
+ int result;
+
+ result = genl_register_family(&thermal_event_genl_family);
+ if (result)
+ return result;
+
+ result = genl_register_mc_group(&thermal_event_genl_family,
+ &thermal_event_mcgrp);
+ if (result)
+ genl_unregister_family(&thermal_event_genl_family);
+ return result;
+}
+
static int __init thermal_init(void)
{
int result = 0;
@@ -1225,9 +1312,15 @@ static int __init thermal_init(void)
mutex_destroy(&thermal_idr_lock);
mutex_destroy(&thermal_list_lock);
}
+ result = genetlink_init();
return result;
}
+static void genetlink_exit(void)
+{
+ genl_unregister_family(&thermal_event_genl_family);
+}
+
static void __exit thermal_exit(void)
{
class_unregister(&thermal_class);
@@ -1235,7 +1328,8 @@ static void __exit thermal_exit(void)
idr_destroy(&thermal_cdev_idr);
mutex_destroy(&thermal_idr_lock);
mutex_destroy(&thermal_list_lock);
+ genetlink_exit();
}
-subsys_initcall(thermal_init);
+fs_initcall(thermal_init);
module_exit(thermal_exit);
diff --git a/drivers/tty/Makefile b/drivers/tty/Makefile
index c43ef48..3962772 100644
--- a/drivers/tty/Makefile
+++ b/drivers/tty/Makefile
@@ -9,3 +9,5 @@ obj-$(CONFIG_N_GSM) += n_gsm.o
obj-$(CONFIG_R3964) += n_r3964.o
obj-y += vt/
+obj-$(CONFIG_HVC_DRIVER) += hvc/
+obj-y += serial/
diff --git a/drivers/tty/hvc/Makefile b/drivers/tty/hvc/Makefile
new file mode 100644
index 0000000..e6bed5f
--- /dev/null
+++ b/drivers/tty/hvc/Makefile
@@ -0,0 +1,13 @@
+obj-$(CONFIG_HVC_CONSOLE) += hvc_vio.o hvsi.o
+obj-$(CONFIG_HVC_ISERIES) += hvc_iseries.o
+obj-$(CONFIG_HVC_RTAS) += hvc_rtas.o
+obj-$(CONFIG_HVC_TILE) += hvc_tile.o
+obj-$(CONFIG_HVC_DCC) += hvc_dcc.o
+obj-$(CONFIG_HVC_BEAT) += hvc_beat.o
+obj-$(CONFIG_HVC_DRIVER) += hvc_console.o
+obj-$(CONFIG_HVC_IRQ) += hvc_irq.o
+obj-$(CONFIG_HVC_XEN) += hvc_xen.o
+obj-$(CONFIG_HVC_IUCV) += hvc_iucv.o
+obj-$(CONFIG_HVC_UDBG) += hvc_udbg.o
+obj-$(CONFIG_HVCS) += hvcs.o
+obj-$(CONFIG_VIRTIO_CONSOLE) += virtio_console.o
diff --git a/drivers/char/hvc_beat.c b/drivers/tty/hvc/hvc_beat.c
index 5fe4631..5fe4631 100644
--- a/drivers/char/hvc_beat.c
+++ b/drivers/tty/hvc/hvc_beat.c
diff --git a/drivers/char/hvc_console.c b/drivers/tty/hvc/hvc_console.c
index e9cba13..e9cba13 100644
--- a/drivers/char/hvc_console.c
+++ b/drivers/tty/hvc/hvc_console.c
diff --git a/drivers/char/hvc_console.h b/drivers/tty/hvc/hvc_console.h
index 54381eba..54381eba 100644
--- a/drivers/char/hvc_console.h
+++ b/drivers/tty/hvc/hvc_console.h
diff --git a/drivers/char/hvc_dcc.c b/drivers/tty/hvc/hvc_dcc.c
index 6470f63..6470f63 100644
--- a/drivers/char/hvc_dcc.c
+++ b/drivers/tty/hvc/hvc_dcc.c
diff --git a/drivers/char/hvc_irq.c b/drivers/tty/hvc/hvc_irq.c
index 2623e17..2623e17 100644
--- a/drivers/char/hvc_irq.c
+++ b/drivers/tty/hvc/hvc_irq.c
diff --git a/drivers/char/hvc_iseries.c b/drivers/tty/hvc/hvc_iseries.c
index 21c5495..21c5495 100644
--- a/drivers/char/hvc_iseries.c
+++ b/drivers/tty/hvc/hvc_iseries.c
diff --git a/drivers/char/hvc_iucv.c b/drivers/tty/hvc/hvc_iucv.c
index c3425bb..c3425bb 100644
--- a/drivers/char/hvc_iucv.c
+++ b/drivers/tty/hvc/hvc_iucv.c
diff --git a/drivers/char/hvc_rtas.c b/drivers/tty/hvc/hvc_rtas.c
index 61c4a61..61c4a61 100644
--- a/drivers/char/hvc_rtas.c
+++ b/drivers/tty/hvc/hvc_rtas.c
diff --git a/drivers/char/hvc_tile.c b/drivers/tty/hvc/hvc_tile.c
index 7a84a05..7a84a05 100644
--- a/drivers/char/hvc_tile.c
+++ b/drivers/tty/hvc/hvc_tile.c
diff --git a/drivers/char/hvc_udbg.c b/drivers/tty/hvc/hvc_udbg.c
index b0957e6..b0957e6 100644
--- a/drivers/char/hvc_udbg.c
+++ b/drivers/tty/hvc/hvc_udbg.c
diff --git a/drivers/char/hvc_vio.c b/drivers/tty/hvc/hvc_vio.c
index 5e2f52b..5e2f52b 100644
--- a/drivers/char/hvc_vio.c
+++ b/drivers/tty/hvc/hvc_vio.c
diff --git a/drivers/char/hvc_xen.c b/drivers/tty/hvc/hvc_xen.c
index 3740e32..3740e32 100644
--- a/drivers/char/hvc_xen.c
+++ b/drivers/tty/hvc/hvc_xen.c
diff --git a/drivers/char/hvcs.c b/drivers/tty/hvc/hvcs.c
index bedc6c1..bedc6c1 100644
--- a/drivers/char/hvcs.c
+++ b/drivers/tty/hvc/hvcs.c
diff --git a/drivers/char/hvsi.c b/drivers/tty/hvc/hvsi.c
index 67a75a5..67a75a5 100644
--- a/drivers/char/hvsi.c
+++ b/drivers/tty/hvc/hvsi.c
diff --git a/drivers/char/virtio_console.c b/drivers/tty/hvc/virtio_console.c
index 896a2ce..896a2ce 100644
--- a/drivers/char/virtio_console.c
+++ b/drivers/tty/hvc/virtio_console.c
diff --git a/drivers/serial/21285.c b/drivers/tty/serial/21285.c
index d89aa38..d89aa38 100644
--- a/drivers/serial/21285.c
+++ b/drivers/tty/serial/21285.c
diff --git a/drivers/serial/68328serial.c b/drivers/tty/serial/68328serial.c
index be0ebce..be0ebce 100644
--- a/drivers/serial/68328serial.c
+++ b/drivers/tty/serial/68328serial.c
diff --git a/drivers/serial/68328serial.h b/drivers/tty/serial/68328serial.h
index 664ceb0..664ceb0 100644
--- a/drivers/serial/68328serial.h
+++ b/drivers/tty/serial/68328serial.h
diff --git a/drivers/serial/68360serial.c b/drivers/tty/serial/68360serial.c
index 88b1335..88b1335 100644
--- a/drivers/serial/68360serial.c
+++ b/drivers/tty/serial/68360serial.c
diff --git a/drivers/serial/8250.c b/drivers/tty/serial/8250.c
index b25e6e4..b25e6e4 100644
--- a/drivers/serial/8250.c
+++ b/drivers/tty/serial/8250.c
diff --git a/drivers/serial/8250.h b/drivers/tty/serial/8250.h
index 6e19ea3..6e19ea3 100644
--- a/drivers/serial/8250.h
+++ b/drivers/tty/serial/8250.h
diff --git a/drivers/serial/8250_accent.c b/drivers/tty/serial/8250_accent.c
index 9c10262..9c10262 100644
--- a/drivers/serial/8250_accent.c
+++ b/drivers/tty/serial/8250_accent.c
diff --git a/drivers/serial/8250_acorn.c b/drivers/tty/serial/8250_acorn.c
index b0ce8c5..b0ce8c5 100644
--- a/drivers/serial/8250_acorn.c
+++ b/drivers/tty/serial/8250_acorn.c
diff --git a/drivers/serial/8250_boca.c b/drivers/tty/serial/8250_boca.c
index 3bfe0f7..3bfe0f7 100644
--- a/drivers/serial/8250_boca.c
+++ b/drivers/tty/serial/8250_boca.c
diff --git a/drivers/serial/8250_early.c b/drivers/tty/serial/8250_early.c
index eaafb98..eaafb98 100644
--- a/drivers/serial/8250_early.c
+++ b/drivers/tty/serial/8250_early.c
diff --git a/drivers/serial/8250_exar_st16c554.c b/drivers/tty/serial/8250_exar_st16c554.c
index 567143a..567143a 100644
--- a/drivers/serial/8250_exar_st16c554.c
+++ b/drivers/tty/serial/8250_exar_st16c554.c
diff --git a/drivers/serial/8250_fourport.c b/drivers/tty/serial/8250_fourport.c
index 6375d68..6375d68 100644
--- a/drivers/serial/8250_fourport.c
+++ b/drivers/tty/serial/8250_fourport.c
diff --git a/drivers/serial/8250_gsc.c b/drivers/tty/serial/8250_gsc.c
index d8c0ffb..d8c0ffb 100644
--- a/drivers/serial/8250_gsc.c
+++ b/drivers/tty/serial/8250_gsc.c
diff --git a/drivers/serial/8250_hp300.c b/drivers/tty/serial/8250_hp300.c
index c13438c..c13438c 100644
--- a/drivers/serial/8250_hp300.c
+++ b/drivers/tty/serial/8250_hp300.c
diff --git a/drivers/serial/8250_hub6.c b/drivers/tty/serial/8250_hub6.c
index 7609150..7609150 100644
--- a/drivers/serial/8250_hub6.c
+++ b/drivers/tty/serial/8250_hub6.c
diff --git a/drivers/serial/8250_mca.c b/drivers/tty/serial/8250_mca.c
index d10be94..d10be94 100644
--- a/drivers/serial/8250_mca.c
+++ b/drivers/tty/serial/8250_mca.c
diff --git a/drivers/serial/8250_pci.c b/drivers/tty/serial/8250_pci.c
index 8b8930f..8b8930f 100644
--- a/drivers/serial/8250_pci.c
+++ b/drivers/tty/serial/8250_pci.c
diff --git a/drivers/serial/8250_pnp.c b/drivers/tty/serial/8250_pnp.c
index 4822cb5..4822cb5 100644
--- a/drivers/serial/8250_pnp.c
+++ b/drivers/tty/serial/8250_pnp.c
diff --git a/drivers/serial/Kconfig b/drivers/tty/serial/Kconfig
index c1df767..b1682d7 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -81,7 +81,7 @@ config SERIAL_8250_GSC
default SERIAL_8250
config SERIAL_8250_PCI
- tristate "8250/16550 PCI device support" if EMBEDDED
+ tristate "8250/16550 PCI device support" if EXPERT
depends on SERIAL_8250 && PCI
default SERIAL_8250
help
@@ -90,7 +90,7 @@ config SERIAL_8250_PCI
Saves about 9K.
config SERIAL_8250_PNP
- tristate "8250/16550 PNP device support" if EMBEDDED
+ tristate "8250/16550 PNP device support" if EXPERT
depends on SERIAL_8250 && PNP
default SERIAL_8250
help
diff --git a/drivers/serial/Makefile b/drivers/tty/serial/Makefile
index 8ea92e9..8ea92e9 100644
--- a/drivers/serial/Makefile
+++ b/drivers/tty/serial/Makefile
diff --git a/drivers/serial/altera_jtaguart.c b/drivers/tty/serial/altera_jtaguart.c
index f9b49b5..f9b49b5 100644
--- a/drivers/serial/altera_jtaguart.c
+++ b/drivers/tty/serial/altera_jtaguart.c
diff --git a/drivers/serial/altera_uart.c b/drivers/tty/serial/altera_uart.c
index 7212162..7212162 100644
--- a/drivers/serial/altera_uart.c
+++ b/drivers/tty/serial/altera_uart.c
diff --git a/drivers/serial/amba-pl010.c b/drivers/tty/serial/amba-pl010.c
index 2904aa0..2904aa0 100644
--- a/drivers/serial/amba-pl010.c
+++ b/drivers/tty/serial/amba-pl010.c
diff --git a/drivers/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
index e76d7d0..e76d7d0 100644
--- a/drivers/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
diff --git a/drivers/serial/apbuart.c b/drivers/tty/serial/apbuart.c
index 095a5d5..095a5d5 100644
--- a/drivers/serial/apbuart.c
+++ b/drivers/tty/serial/apbuart.c
diff --git a/drivers/serial/apbuart.h b/drivers/tty/serial/apbuart.h
index 5faf87c..5faf87c 100644
--- a/drivers/serial/apbuart.h
+++ b/drivers/tty/serial/apbuart.h
diff --git a/drivers/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c
index 2a1d52f..2a1d52f 100644
--- a/drivers/serial/atmel_serial.c
+++ b/drivers/tty/serial/atmel_serial.c
diff --git a/drivers/serial/bcm63xx_uart.c b/drivers/tty/serial/bcm63xx_uart.c
index a1a0e55..a1a0e55 100644
--- a/drivers/serial/bcm63xx_uart.c
+++ b/drivers/tty/serial/bcm63xx_uart.c
diff --git a/drivers/serial/bfin_5xx.c b/drivers/tty/serial/bfin_5xx.c
index e381b89..e381b89 100644
--- a/drivers/serial/bfin_5xx.c
+++ b/drivers/tty/serial/bfin_5xx.c
diff --git a/drivers/serial/bfin_sport_uart.c b/drivers/tty/serial/bfin_sport_uart.c
index e95c524..e95c524 100644
--- a/drivers/serial/bfin_sport_uart.c
+++ b/drivers/tty/serial/bfin_sport_uart.c
diff --git a/drivers/serial/bfin_sport_uart.h b/drivers/tty/serial/bfin_sport_uart.h
index 6d06ce1..6d06ce1 100644
--- a/drivers/serial/bfin_sport_uart.h
+++ b/drivers/tty/serial/bfin_sport_uart.h
diff --git a/drivers/serial/clps711x.c b/drivers/tty/serial/clps711x.c
index b6acd19..b6acd19 100644
--- a/drivers/serial/clps711x.c
+++ b/drivers/tty/serial/clps711x.c
diff --git a/drivers/serial/cpm_uart/Makefile b/drivers/tty/serial/cpm_uart/Makefile
index e072724..e072724 100644
--- a/drivers/serial/cpm_uart/Makefile
+++ b/drivers/tty/serial/cpm_uart/Makefile
diff --git a/drivers/serial/cpm_uart/cpm_uart.h b/drivers/tty/serial/cpm_uart/cpm_uart.h
index b754dcf..b754dcf 100644
--- a/drivers/serial/cpm_uart/cpm_uart.h
+++ b/drivers/tty/serial/cpm_uart/cpm_uart.h
diff --git a/drivers/serial/cpm_uart/cpm_uart_core.c b/drivers/tty/serial/cpm_uart/cpm_uart_core.c
index 8692ff9..8692ff9 100644
--- a/drivers/serial/cpm_uart/cpm_uart_core.c
+++ b/drivers/tty/serial/cpm_uart/cpm_uart_core.c
diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm1.c b/drivers/tty/serial/cpm_uart/cpm_uart_cpm1.c
index 3fc1d66..3fc1d66 100644
--- a/drivers/serial/cpm_uart/cpm_uart_cpm1.c
+++ b/drivers/tty/serial/cpm_uart/cpm_uart_cpm1.c
diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm1.h b/drivers/tty/serial/cpm_uart/cpm_uart_cpm1.h
index 10eecd6..10eecd6 100644
--- a/drivers/serial/cpm_uart/cpm_uart_cpm1.h
+++ b/drivers/tty/serial/cpm_uart/cpm_uart_cpm1.h
diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm2.c b/drivers/tty/serial/cpm_uart/cpm_uart_cpm2.c
index 814ac00..814ac00 100644
--- a/drivers/serial/cpm_uart/cpm_uart_cpm2.c
+++ b/drivers/tty/serial/cpm_uart/cpm_uart_cpm2.c
diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm2.h b/drivers/tty/serial/cpm_uart/cpm_uart_cpm2.h
index 7194c63..7194c63 100644
--- a/drivers/serial/cpm_uart/cpm_uart_cpm2.h
+++ b/drivers/tty/serial/cpm_uart/cpm_uart_cpm2.h
diff --git a/drivers/serial/crisv10.c b/drivers/tty/serial/crisv10.c
index bcc31f2..bcc31f2 100644
--- a/drivers/serial/crisv10.c
+++ b/drivers/tty/serial/crisv10.c
diff --git a/drivers/serial/crisv10.h b/drivers/tty/serial/crisv10.h
index ea0beb46..ea0beb46 100644
--- a/drivers/serial/crisv10.h
+++ b/drivers/tty/serial/crisv10.h
diff --git a/drivers/serial/dz.c b/drivers/tty/serial/dz.c
index 57421d7..57421d7 100644
--- a/drivers/serial/dz.c
+++ b/drivers/tty/serial/dz.c
diff --git a/drivers/serial/dz.h b/drivers/tty/serial/dz.h
index faf169e..faf169e 100644
--- a/drivers/serial/dz.h
+++ b/drivers/tty/serial/dz.h
diff --git a/drivers/serial/icom.c b/drivers/tty/serial/icom.c
index 53a4682..53a4682 100644
--- a/drivers/serial/icom.c
+++ b/drivers/tty/serial/icom.c
diff --git a/drivers/serial/icom.h b/drivers/tty/serial/icom.h
index c8029e0..c8029e0 100644
--- a/drivers/serial/icom.h
+++ b/drivers/tty/serial/icom.h
diff --git a/drivers/serial/ifx6x60.c b/drivers/tty/serial/ifx6x60.c
index ab93763..ab93763 100644
--- a/drivers/serial/ifx6x60.c
+++ b/drivers/tty/serial/ifx6x60.c
diff --git a/drivers/serial/ifx6x60.h b/drivers/tty/serial/ifx6x60.h
index deb7b8d..deb7b8d 100644
--- a/drivers/serial/ifx6x60.h
+++ b/drivers/tty/serial/ifx6x60.h
diff --git a/drivers/serial/imx.c b/drivers/tty/serial/imx.c
index dfcf4b1..dfcf4b1 100644
--- a/drivers/serial/imx.c
+++ b/drivers/tty/serial/imx.c
diff --git a/drivers/serial/ioc3_serial.c b/drivers/tty/serial/ioc3_serial.c
index ee43efc..ee43efc 100644
--- a/drivers/serial/ioc3_serial.c
+++ b/drivers/tty/serial/ioc3_serial.c
diff --git a/drivers/serial/ioc4_serial.c b/drivers/tty/serial/ioc4_serial.c
index fcfe826..fcfe826 100644
--- a/drivers/serial/ioc4_serial.c
+++ b/drivers/tty/serial/ioc4_serial.c
diff --git a/drivers/serial/ip22zilog.c b/drivers/tty/serial/ip22zilog.c
index ebff4a1..ebff4a1 100644
--- a/drivers/serial/ip22zilog.c
+++ b/drivers/tty/serial/ip22zilog.c
diff --git a/drivers/serial/ip22zilog.h b/drivers/tty/serial/ip22zilog.h
index a59a9a8..a59a9a8 100644
--- a/drivers/serial/ip22zilog.h
+++ b/drivers/tty/serial/ip22zilog.h
diff --git a/drivers/serial/jsm/Makefile b/drivers/tty/serial/jsm/Makefile
index e46b6e0..e46b6e0 100644
--- a/drivers/serial/jsm/Makefile
+++ b/drivers/tty/serial/jsm/Makefile
diff --git a/drivers/serial/jsm/jsm.h b/drivers/tty/serial/jsm/jsm.h
index 38a509c..38a509c 100644
--- a/drivers/serial/jsm/jsm.h
+++ b/drivers/tty/serial/jsm/jsm.h
diff --git a/drivers/serial/jsm/jsm_driver.c b/drivers/tty/serial/jsm/jsm_driver.c
index 18f5484..18f5484 100644
--- a/drivers/serial/jsm/jsm_driver.c
+++ b/drivers/tty/serial/jsm/jsm_driver.c
diff --git a/drivers/serial/jsm/jsm_neo.c b/drivers/tty/serial/jsm/jsm_neo.c
index 7960d96..7960d96 100644
--- a/drivers/serial/jsm/jsm_neo.c
+++ b/drivers/tty/serial/jsm/jsm_neo.c
diff --git a/drivers/serial/jsm/jsm_tty.c b/drivers/tty/serial/jsm/jsm_tty.c
index 7a4a914..7a4a914 100644
--- a/drivers/serial/jsm/jsm_tty.c
+++ b/drivers/tty/serial/jsm/jsm_tty.c
diff --git a/drivers/serial/kgdboc.c b/drivers/tty/serial/kgdboc.c
index 25a8bc5..25a8bc5 100644
--- a/drivers/serial/kgdboc.c
+++ b/drivers/tty/serial/kgdboc.c
diff --git a/drivers/serial/m32r_sio.c b/drivers/tty/serial/m32r_sio.c
index bea5c21..bea5c21 100644
--- a/drivers/serial/m32r_sio.c
+++ b/drivers/tty/serial/m32r_sio.c
diff --git a/drivers/serial/m32r_sio.h b/drivers/tty/serial/m32r_sio.h
index e9b7e11..e9b7e11 100644
--- a/drivers/serial/m32r_sio.h
+++ b/drivers/tty/serial/m32r_sio.h
diff --git a/drivers/serial/m32r_sio_reg.h b/drivers/tty/serial/m32r_sio_reg.h
index 4671473..4671473 100644
--- a/drivers/serial/m32r_sio_reg.h
+++ b/drivers/tty/serial/m32r_sio_reg.h
diff --git a/drivers/serial/max3100.c b/drivers/tty/serial/max3100.c
index beb1afa2..beb1afa2 100644
--- a/drivers/serial/max3100.c
+++ b/drivers/tty/serial/max3100.c
diff --git a/drivers/serial/max3107-aava.c b/drivers/tty/serial/max3107-aava.c
index a1fe304..a1fe304 100644
--- a/drivers/serial/max3107-aava.c
+++ b/drivers/tty/serial/max3107-aava.c
diff --git a/drivers/serial/max3107.c b/drivers/tty/serial/max3107.c
index 910870e..910870e 100644
--- a/drivers/serial/max3107.c
+++ b/drivers/tty/serial/max3107.c
diff --git a/drivers/serial/max3107.h b/drivers/tty/serial/max3107.h
index 7ab63239..7ab63239 100644
--- a/drivers/serial/max3107.h
+++ b/drivers/tty/serial/max3107.h
diff --git a/drivers/serial/mcf.c b/drivers/tty/serial/mcf.c
index 3394b7c..3394b7c 100644
--- a/drivers/serial/mcf.c
+++ b/drivers/tty/serial/mcf.c
diff --git a/drivers/serial/mfd.c b/drivers/tty/serial/mfd.c
index d40010a..d40010a 100644
--- a/drivers/serial/mfd.c
+++ b/drivers/tty/serial/mfd.c
diff --git a/drivers/serial/mpc52xx_uart.c b/drivers/tty/serial/mpc52xx_uart.c
index 126ec7f..126ec7f 100644
--- a/drivers/serial/mpc52xx_uart.c
+++ b/drivers/tty/serial/mpc52xx_uart.c
diff --git a/drivers/serial/mpsc.c b/drivers/tty/serial/mpsc.c
index 6a9c660..6a9c660 100644
--- a/drivers/serial/mpsc.c
+++ b/drivers/tty/serial/mpsc.c
diff --git a/drivers/serial/mrst_max3110.c b/drivers/tty/serial/mrst_max3110.c
index b62857b..b62857b 100644
--- a/drivers/serial/mrst_max3110.c
+++ b/drivers/tty/serial/mrst_max3110.c
diff --git a/drivers/serial/mrst_max3110.h b/drivers/tty/serial/mrst_max3110.h
index d1ef43a..d1ef43a 100644
--- a/drivers/serial/mrst_max3110.h
+++ b/drivers/tty/serial/mrst_max3110.h
diff --git a/drivers/serial/msm_serial.c b/drivers/tty/serial/msm_serial.c
index 8e43a7b..8e43a7b 100644
--- a/drivers/serial/msm_serial.c
+++ b/drivers/tty/serial/msm_serial.c
diff --git a/drivers/serial/msm_serial.h b/drivers/tty/serial/msm_serial.h
index f6ca9ca..f6ca9ca 100644
--- a/drivers/serial/msm_serial.h
+++ b/drivers/tty/serial/msm_serial.h
diff --git a/drivers/serial/mux.c b/drivers/tty/serial/mux.c
index 9711e06..9711e06 100644
--- a/drivers/serial/mux.c
+++ b/drivers/tty/serial/mux.c
diff --git a/drivers/serial/netx-serial.c b/drivers/tty/serial/netx-serial.c
index 7735c9f..7735c9f 100644
--- a/drivers/serial/netx-serial.c
+++ b/drivers/tty/serial/netx-serial.c
diff --git a/drivers/serial/nwpserial.c b/drivers/tty/serial/nwpserial.c
index de17367..de17367 100644
--- a/drivers/serial/nwpserial.c
+++ b/drivers/tty/serial/nwpserial.c
diff --git a/drivers/serial/of_serial.c b/drivers/tty/serial/of_serial.c
index 5c7abe4..5c7abe4 100644
--- a/drivers/serial/of_serial.c
+++ b/drivers/tty/serial/of_serial.c
diff --git a/drivers/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
index 7f2f010..7f2f010 100644
--- a/drivers/serial/omap-serial.c
+++ b/drivers/tty/serial/omap-serial.c
diff --git a/drivers/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c
index 70a6145..70a6145 100644
--- a/drivers/serial/pch_uart.c
+++ b/drivers/tty/serial/pch_uart.c
diff --git a/drivers/serial/pmac_zilog.c b/drivers/tty/serial/pmac_zilog.c
index 5b9cde7..5b9cde7 100644
--- a/drivers/serial/pmac_zilog.c
+++ b/drivers/tty/serial/pmac_zilog.c
diff --git a/drivers/serial/pmac_zilog.h b/drivers/tty/serial/pmac_zilog.h
index cbc34fb..cbc34fb 100644
--- a/drivers/serial/pmac_zilog.h
+++ b/drivers/tty/serial/pmac_zilog.h
diff --git a/drivers/serial/pnx8xxx_uart.c b/drivers/tty/serial/pnx8xxx_uart.c
index 0aa75a9..0aa75a9 100644
--- a/drivers/serial/pnx8xxx_uart.c
+++ b/drivers/tty/serial/pnx8xxx_uart.c
diff --git a/drivers/serial/pxa.c b/drivers/tty/serial/pxa.c
index 1102a39..1102a39 100644
--- a/drivers/serial/pxa.c
+++ b/drivers/tty/serial/pxa.c
diff --git a/drivers/serial/s3c2400.c b/drivers/tty/serial/s3c2400.c
index fed1a9a..fed1a9a 100644
--- a/drivers/serial/s3c2400.c
+++ b/drivers/tty/serial/s3c2400.c
diff --git a/drivers/serial/s3c2410.c b/drivers/tty/serial/s3c2410.c
index 73f089d..73f089d 100644
--- a/drivers/serial/s3c2410.c
+++ b/drivers/tty/serial/s3c2410.c
diff --git a/drivers/serial/s3c2412.c b/drivers/tty/serial/s3c2412.c
index 1700b1a..1700b1a 100644
--- a/drivers/serial/s3c2412.c
+++ b/drivers/tty/serial/s3c2412.c
diff --git a/drivers/serial/s3c2440.c b/drivers/tty/serial/s3c2440.c
index 094cc39..094cc39 100644
--- a/drivers/serial/s3c2440.c
+++ b/drivers/tty/serial/s3c2440.c
diff --git a/drivers/serial/s3c24a0.c b/drivers/tty/serial/s3c24a0.c
index fad6083..fad6083 100644
--- a/drivers/serial/s3c24a0.c
+++ b/drivers/tty/serial/s3c24a0.c
diff --git a/drivers/serial/s3c6400.c b/drivers/tty/serial/s3c6400.c
index 4be92ab..4be92ab 100644
--- a/drivers/serial/s3c6400.c
+++ b/drivers/tty/serial/s3c6400.c
diff --git a/drivers/serial/s5pv210.c b/drivers/tty/serial/s5pv210.c
index 6ebccd7..6ebccd7 100644
--- a/drivers/serial/s5pv210.c
+++ b/drivers/tty/serial/s5pv210.c
diff --git a/drivers/serial/sa1100.c b/drivers/tty/serial/sa1100.c
index 2199d81..2199d81 100644
--- a/drivers/serial/sa1100.c
+++ b/drivers/tty/serial/sa1100.c
diff --git a/drivers/serial/samsung.c b/drivers/tty/serial/samsung.c
index 7ac2bf5..2335eda 100644
--- a/drivers/serial/samsung.c
+++ b/drivers/tty/serial/samsung.c
@@ -883,10 +883,10 @@ static struct uart_ops s3c24xx_serial_ops = {
static struct uart_driver s3c24xx_uart_drv = {
.owner = THIS_MODULE,
- .dev_name = "s3c2410_serial",
+ .driver_name = "s3c2410_serial",
.nr = CONFIG_SERIAL_SAMSUNG_UARTS,
.cons = S3C24XX_SERIAL_CONSOLE,
- .driver_name = S3C24XX_SERIAL_NAME,
+ .dev_name = S3C24XX_SERIAL_NAME,
.major = S3C24XX_SERIAL_MAJOR,
.minor = S3C24XX_SERIAL_MINOR,
};
diff --git a/drivers/serial/samsung.h b/drivers/tty/serial/samsung.h
index 0ac06a0..0ac06a0 100644
--- a/drivers/serial/samsung.h
+++ b/drivers/tty/serial/samsung.h
diff --git a/drivers/serial/sb1250-duart.c b/drivers/tty/serial/sb1250-duart.c
index a2f2b32..a2f2b32 100644
--- a/drivers/serial/sb1250-duart.c
+++ b/drivers/tty/serial/sb1250-duart.c
diff --git a/drivers/serial/sc26xx.c b/drivers/tty/serial/sc26xx.c
index 75038ad..75038ad 100644
--- a/drivers/serial/sc26xx.c
+++ b/drivers/tty/serial/sc26xx.c
diff --git a/drivers/serial/serial_core.c b/drivers/tty/serial/serial_core.c
index 460a72d..460a72d 100644
--- a/drivers/serial/serial_core.c
+++ b/drivers/tty/serial/serial_core.c
diff --git a/drivers/serial/serial_cs.c b/drivers/tty/serial/serial_cs.c
index 93760b2..93760b2 100644
--- a/drivers/serial/serial_cs.c
+++ b/drivers/tty/serial/serial_cs.c
diff --git a/drivers/serial/serial_ks8695.c b/drivers/tty/serial/serial_ks8695.c
index b196202..b196202 100644
--- a/drivers/serial/serial_ks8695.c
+++ b/drivers/tty/serial/serial_ks8695.c
diff --git a/drivers/serial/serial_lh7a40x.c b/drivers/tty/serial/serial_lh7a40x.c
index ea74470..ea74470 100644
--- a/drivers/serial/serial_lh7a40x.c
+++ b/drivers/tty/serial/serial_lh7a40x.c
diff --git a/drivers/serial/serial_txx9.c b/drivers/tty/serial/serial_txx9.c
index c50e9fb..c50e9fb 100644
--- a/drivers/serial/serial_txx9.c
+++ b/drivers/tty/serial/serial_txx9.c
diff --git a/drivers/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c
index 92c91c8..92c91c8 100644
--- a/drivers/serial/sh-sci.c
+++ b/drivers/tty/serial/sh-sci.c
diff --git a/drivers/serial/sh-sci.h b/drivers/tty/serial/sh-sci.h
index b223d6c..b223d6c 100644
--- a/drivers/serial/sh-sci.h
+++ b/drivers/tty/serial/sh-sci.h
diff --git a/drivers/serial/sn_console.c b/drivers/tty/serial/sn_console.c
index cff9a30..cff9a30 100644
--- a/drivers/serial/sn_console.c
+++ b/drivers/tty/serial/sn_console.c
diff --git a/drivers/serial/suncore.c b/drivers/tty/serial/suncore.c
index 6381a02..6381a02 100644
--- a/drivers/serial/suncore.c
+++ b/drivers/tty/serial/suncore.c
diff --git a/drivers/serial/suncore.h b/drivers/tty/serial/suncore.h
index db20579..db20579 100644
--- a/drivers/serial/suncore.h
+++ b/drivers/tty/serial/suncore.h
diff --git a/drivers/serial/sunhv.c b/drivers/tty/serial/sunhv.c
index c901486..c901486 100644
--- a/drivers/serial/sunhv.c
+++ b/drivers/tty/serial/sunhv.c
diff --git a/drivers/serial/sunsab.c b/drivers/tty/serial/sunsab.c
index 5b246b1..5b246b1 100644
--- a/drivers/serial/sunsab.c
+++ b/drivers/tty/serial/sunsab.c
diff --git a/drivers/serial/sunsab.h b/drivers/tty/serial/sunsab.h
index b78e1f7..b78e1f7 100644
--- a/drivers/serial/sunsab.h
+++ b/drivers/tty/serial/sunsab.h
diff --git a/drivers/serial/sunsu.c b/drivers/tty/serial/sunsu.c
index 551ebfe..551ebfe 100644
--- a/drivers/serial/sunsu.c
+++ b/drivers/tty/serial/sunsu.c
diff --git a/drivers/serial/sunzilog.c b/drivers/tty/serial/sunzilog.c
index c1967ac..c1967ac 100644
--- a/drivers/serial/sunzilog.c
+++ b/drivers/tty/serial/sunzilog.c
diff --git a/drivers/serial/sunzilog.h b/drivers/tty/serial/sunzilog.h
index 5dec7b4..5dec7b4 100644
--- a/drivers/serial/sunzilog.h
+++ b/drivers/tty/serial/sunzilog.h
diff --git a/drivers/serial/timbuart.c b/drivers/tty/serial/timbuart.c
index 1f36b7e..1f36b7e 100644
--- a/drivers/serial/timbuart.c
+++ b/drivers/tty/serial/timbuart.c
diff --git a/drivers/serial/timbuart.h b/drivers/tty/serial/timbuart.h
index 7e56676..7e56676 100644
--- a/drivers/serial/timbuart.h
+++ b/drivers/tty/serial/timbuart.h
diff --git a/drivers/serial/uartlite.c b/drivers/tty/serial/uartlite.c
index d2fce86..d2fce86 100644
--- a/drivers/serial/uartlite.c
+++ b/drivers/tty/serial/uartlite.c
diff --git a/drivers/serial/ucc_uart.c b/drivers/tty/serial/ucc_uart.c
index 3f4848e..3f4848e 100644
--- a/drivers/serial/ucc_uart.c
+++ b/drivers/tty/serial/ucc_uart.c
diff --git a/drivers/serial/vr41xx_siu.c b/drivers/tty/serial/vr41xx_siu.c
index 3beb6ab..3beb6ab 100644
--- a/drivers/serial/vr41xx_siu.c
+++ b/drivers/tty/serial/vr41xx_siu.c
diff --git a/drivers/serial/vt8500_serial.c b/drivers/tty/serial/vt8500_serial.c
index 322bf56..322bf56 100644
--- a/drivers/serial/vt8500_serial.c
+++ b/drivers/tty/serial/vt8500_serial.c
diff --git a/drivers/serial/zs.c b/drivers/tty/serial/zs.c
index 1a7fd3e..1a7fd3e 100644
--- a/drivers/serial/zs.c
+++ b/drivers/tty/serial/zs.c
diff --git a/drivers/serial/zs.h b/drivers/tty/serial/zs.h
index aa921b5..aa921b5 100644
--- a/drivers/serial/zs.h
+++ b/drivers/tty/serial/zs.h
diff --git a/drivers/usb/core/Kconfig b/drivers/usb/core/Kconfig
index bcc2477..18d02e3 100644
--- a/drivers/usb/core/Kconfig
+++ b/drivers/usb/core/Kconfig
@@ -123,9 +123,9 @@ config USB_OTG
config USB_OTG_WHITELIST
bool "Rely on OTG Targeted Peripherals List"
- depends on USB_OTG || EMBEDDED
+ depends on USB_OTG || EXPERT
default y if USB_OTG
- default n if EMBEDDED
+ default n if EXPERT
help
If you say Y here, the "otg_whitelist.h" file will be used as a
product whitelist, so USB peripherals not listed there will be
@@ -141,7 +141,7 @@ config USB_OTG_WHITELIST
config USB_OTG_BLACKLIST_HUB
bool "Disable external hubs"
- depends on USB_OTG || EMBEDDED
+ depends on USB_OTG || EXPERT
help
If you say Y here, then Linux will refuse to enumerate
external hubs. OTG hosts are allowed to reduce hardware
diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c
index 38244f5..ade0568 100644
--- a/drivers/vhost/vhost.c
+++ b/drivers/vhost/vhost.c
@@ -97,22 +97,26 @@ void vhost_poll_stop(struct vhost_poll *poll)
remove_wait_queue(poll->wqh, &poll->wait);
}
+static bool vhost_work_seq_done(struct vhost_dev *dev, struct vhost_work *work,
+ unsigned seq)
+{
+ int left;
+ spin_lock_irq(&dev->work_lock);
+ left = seq - work->done_seq;
+ spin_unlock_irq(&dev->work_lock);
+ return left <= 0;
+}
+
static void vhost_work_flush(struct vhost_dev *dev, struct vhost_work *work)
{
unsigned seq;
- int left;
int flushing;
spin_lock_irq(&dev->work_lock);
seq = work->queue_seq;
work->flushing++;
spin_unlock_irq(&dev->work_lock);
- wait_event(work->done, ({
- spin_lock_irq(&dev->work_lock);
- left = seq - work->done_seq <= 0;
- spin_unlock_irq(&dev->work_lock);
- left;
- }));
+ wait_event(work->done, vhost_work_seq_done(dev, work, seq));
spin_lock_irq(&dev->work_lock);
flushing = --work->flushing;
spin_unlock_irq(&dev->work_lock);
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index d916ac0..6bafb51b 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -1227,7 +1227,7 @@ config FB_CARILLO_RANCH
config FB_INTEL
tristate "Intel 830M/845G/852GM/855GM/865G/915G/945G/945GM/965G/965GM support (EXPERIMENTAL)"
- depends on EXPERIMENTAL && FB && PCI && X86 && AGP_INTEL && EMBEDDED
+ depends on EXPERIMENTAL && FB && PCI && X86 && AGP_INTEL && EXPERT
select FB_MODE_HELPERS
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
diff --git a/drivers/video/backlight/88pm860x_bl.c b/drivers/video/backlight/88pm860x_bl.c
index c789c46..b224396 100644
--- a/drivers/video/backlight/88pm860x_bl.c
+++ b/drivers/video/backlight/88pm860x_bl.c
@@ -21,7 +21,7 @@
#define MAX_BRIGHTNESS (0xFF)
#define MIN_BRIGHTNESS (0)
-#define CURRENT_MASK (0x1F << 1)
+#define CURRENT_BITMASK (0x1F << 1)
struct pm860x_backlight_data {
struct pm860x_chip *chip;
@@ -85,7 +85,7 @@ static int pm860x_backlight_set(struct backlight_device *bl, int brightness)
if ((data->current_brightness == 0) && brightness) {
if (data->iset) {
ret = pm860x_set_bits(data->i2c, wled_idc(data->port),
- CURRENT_MASK, data->iset);
+ CURRENT_BITMASK, data->iset);
if (ret < 0)
goto out;
}
diff --git a/drivers/video/console/Kconfig b/drivers/video/console/Kconfig
index 5a35f22..2209e35 100644
--- a/drivers/video/console/Kconfig
+++ b/drivers/video/console/Kconfig
@@ -5,7 +5,7 @@
menu "Console display driver support"
config VGA_CONSOLE
- bool "VGA text console" if EMBEDDED || !X86
+ bool "VGA text console" if EXPERT || !X86
depends on !4xx && !8xx && !SPARC && !M68K && !PARISC && !FRV && !SUPERH && !BLACKFIN && !AVR32 && !MN10300 && (!ARM || ARCH_FOOTBRIDGE || ARCH_INTEGRATOR || ARCH_NETWINDER)
default y
help
diff --git a/drivers/video/ep93xx-fb.c b/drivers/video/ep93xx-fb.c
index 0c99de0..b358d04 100644
--- a/drivers/video/ep93xx-fb.c
+++ b/drivers/video/ep93xx-fb.c
@@ -483,7 +483,7 @@ static void ep93xxfb_dealloc_videomem(struct fb_info *info)
info->screen_base, info->fix.smem_start);
}
-static int __init ep93xxfb_probe(struct platform_device *pdev)
+static int __devinit ep93xxfb_probe(struct platform_device *pdev)
{
struct ep93xxfb_mach_info *mach_info = pdev->dev.platform_data;
struct fb_info *info;
@@ -598,7 +598,7 @@ failed:
return err;
}
-static int ep93xxfb_remove(struct platform_device *pdev)
+static int __devexit ep93xxfb_remove(struct platform_device *pdev)
{
struct fb_info *info = platform_get_drvdata(pdev);
struct ep93xx_fbi *fbi = info->par;
@@ -622,7 +622,7 @@ static int ep93xxfb_remove(struct platform_device *pdev)
static struct platform_driver ep93xxfb_driver = {
.probe = ep93xxfb_probe,
- .remove = ep93xxfb_remove,
+ .remove = __devexit_p(ep93xxfb_remove),
.driver = {
.name = "ep93xx-fb",
.owner = THIS_MODULE,
diff --git a/drivers/virtio/virtio_pci.c b/drivers/virtio/virtio_pci.c
index ef8d9d5..4fb5b2b 100644
--- a/drivers/virtio/virtio_pci.c
+++ b/drivers/virtio/virtio_pci.c
@@ -96,11 +96,6 @@ static struct pci_device_id virtio_pci_id_table[] = {
MODULE_DEVICE_TABLE(pci, virtio_pci_id_table);
-/* A PCI device has it's own struct device and so does a virtio device so
- * we create a place for the virtio devices to show up in sysfs. I think it
- * would make more sense for virtio to not insist on having it's own device. */
-static struct device *virtio_pci_root;
-
/* Convert a generic virtio device to our structure */
static struct virtio_pci_device *to_vp_device(struct virtio_device *vdev)
{
@@ -629,7 +624,7 @@ static int __devinit virtio_pci_probe(struct pci_dev *pci_dev,
if (vp_dev == NULL)
return -ENOMEM;
- vp_dev->vdev.dev.parent = virtio_pci_root;
+ vp_dev->vdev.dev.parent = &pci_dev->dev;
vp_dev->vdev.dev.release = virtio_pci_release_dev;
vp_dev->vdev.config = &virtio_pci_config_ops;
vp_dev->pci_dev = pci_dev;
@@ -717,17 +712,7 @@ static struct pci_driver virtio_pci_driver = {
static int __init virtio_pci_init(void)
{
- int err;
-
- virtio_pci_root = root_device_register("virtio-pci");
- if (IS_ERR(virtio_pci_root))
- return PTR_ERR(virtio_pci_root);
-
- err = pci_register_driver(&virtio_pci_driver);
- if (err)
- root_device_unregister(virtio_pci_root);
-
- return err;
+ return pci_register_driver(&virtio_pci_driver);
}
module_init(virtio_pci_init);
@@ -735,7 +720,6 @@ module_init(virtio_pci_init);
static void __exit virtio_pci_exit(void)
{
pci_unregister_driver(&virtio_pci_driver);
- root_device_unregister(virtio_pci_root);
}
module_exit(virtio_pci_exit);
diff --git a/drivers/xen/xenfs/xenbus.c b/drivers/xen/xenfs/xenbus.c
index 1c12360..bbd000f 100644
--- a/drivers/xen/xenfs/xenbus.c
+++ b/drivers/xen/xenfs/xenbus.c
@@ -122,6 +122,7 @@ static ssize_t xenbus_file_read(struct file *filp,
int ret;
mutex_lock(&u->reply_mutex);
+again:
while (list_empty(&u->read_buffers)) {
mutex_unlock(&u->reply_mutex);
if (filp->f_flags & O_NONBLOCK)
@@ -144,7 +145,7 @@ static ssize_t xenbus_file_read(struct file *filp,
i += sz - ret;
rb->cons += sz - ret;
- if (ret != sz) {
+ if (ret != 0) {
if (i == 0)
i = -EFAULT;
goto out;
@@ -160,6 +161,8 @@ static ssize_t xenbus_file_read(struct file *filp,
struct read_buffer, list);
}
}
+ if (i == 0)
+ goto again;
out:
mutex_unlock(&u->reply_mutex);
@@ -407,6 +410,7 @@ static int xenbus_write_watch(unsigned msg_type, struct xenbus_file_priv *u)
mutex_lock(&u->reply_mutex);
rc = queue_reply(&u->read_buffers, &reply, sizeof(reply));
+ wake_up(&u->read_waitq);
mutex_unlock(&u->reply_mutex);
}
@@ -455,7 +459,7 @@ static ssize_t xenbus_file_write(struct file *filp,
ret = copy_from_user(u->u.buffer + u->len, ubuf, len);
- if (ret == len) {
+ if (ret != 0) {
rc = -EFAULT;
goto out;
}
@@ -488,21 +492,6 @@ static ssize_t xenbus_file_write(struct file *filp,
msg_type = u->u.msg.type;
switch (msg_type) {
- case XS_TRANSACTION_START:
- case XS_TRANSACTION_END:
- case XS_DIRECTORY:
- case XS_READ:
- case XS_GET_PERMS:
- case XS_RELEASE:
- case XS_GET_DOMAIN_PATH:
- case XS_WRITE:
- case XS_MKDIR:
- case XS_RM:
- case XS_SET_PERMS:
- /* Send out a transaction */
- ret = xenbus_write_transaction(msg_type, u);
- break;
-
case XS_WATCH:
case XS_UNWATCH:
/* (Un)Ask for some path to be watched for changes */
@@ -510,7 +499,8 @@ static ssize_t xenbus_file_write(struct file *filp,
break;
default:
- ret = -EINVAL;
+ /* Send out a transaction */
+ ret = xenbus_write_transaction(msg_type, u);
break;
}
if (ret != 0)
@@ -555,6 +545,7 @@ static int xenbus_file_release(struct inode *inode, struct file *filp)
struct xenbus_file_priv *u = filp->private_data;
struct xenbus_transaction_holder *trans, *tmp;
struct watch_adapter *watch, *tmp_watch;
+ struct read_buffer *rb, *tmp_rb;
/*
* No need for locking here because there are no other users,
@@ -573,6 +564,10 @@ static int xenbus_file_release(struct inode *inode, struct file *filp)
free_watch_adapter(watch);
}
+ list_for_each_entry_safe(rb, tmp_rb, &u->read_buffers, list) {
+ list_del(&rb->list);
+ kfree(rb);
+ }
kfree(u);
return 0;
diff --git a/fs/Kconfig b/fs/Kconfig
index 771f457..3db9caa 100644
--- a/fs/Kconfig
+++ b/fs/Kconfig
@@ -30,15 +30,6 @@ config FS_MBCACHE
source "fs/reiserfs/Kconfig"
source "fs/jfs/Kconfig"
-config FS_POSIX_ACL
-# Posix ACL utility routines (for now, only ext2/ext3/jfs/reiserfs/nfs4)
-#
-# NOTE: you can implement Posix ACLs without these helpers (XFS does).
-# Never use this symbol for ifdefs.
-#
- bool
- default n
-
source "fs/xfs/Kconfig"
source "fs/gfs2/Kconfig"
source "fs/ocfs2/Kconfig"
@@ -47,11 +38,19 @@ source "fs/nilfs2/Kconfig"
endif # BLOCK
+# Posix ACL utility routines
+#
+# Note: Posix ACLs can be implemented without these helpers. Never use
+# this symbol for ifdefs in core code.
+#
+config FS_POSIX_ACL
+ def_bool n
+
config EXPORTFS
tristate
config FILE_LOCKING
- bool "Enable POSIX file locking API" if EMBEDDED
+ bool "Enable POSIX file locking API" if EXPERT
default y
help
This option enables standard file locking support, required
diff --git a/fs/afs/cmservice.c b/fs/afs/cmservice.c
index a3bcec7..1c8c6cc 100644
--- a/fs/afs/cmservice.c
+++ b/fs/afs/cmservice.c
@@ -289,7 +289,7 @@ static int afs_deliver_cb_callback(struct afs_call *call, struct sk_buff *skb,
call->server = server;
INIT_WORK(&call->work, SRXAFSCB_CallBack);
- schedule_work(&call->work);
+ queue_work(afs_wq, &call->work);
return 0;
}
@@ -336,7 +336,7 @@ static int afs_deliver_cb_init_call_back_state(struct afs_call *call,
call->server = server;
INIT_WORK(&call->work, SRXAFSCB_InitCallBackState);
- schedule_work(&call->work);
+ queue_work(afs_wq, &call->work);
return 0;
}
@@ -367,7 +367,7 @@ static int afs_deliver_cb_init_call_back_state3(struct afs_call *call,
call->server = server;
INIT_WORK(&call->work, SRXAFSCB_InitCallBackState);
- schedule_work(&call->work);
+ queue_work(afs_wq, &call->work);
return 0;
}
@@ -400,7 +400,7 @@ static int afs_deliver_cb_probe(struct afs_call *call, struct sk_buff *skb,
call->state = AFS_CALL_REPLYING;
INIT_WORK(&call->work, SRXAFSCB_Probe);
- schedule_work(&call->work);
+ queue_work(afs_wq, &call->work);
return 0;
}
@@ -496,7 +496,7 @@ static int afs_deliver_cb_probe_uuid(struct afs_call *call, struct sk_buff *skb,
call->state = AFS_CALL_REPLYING;
INIT_WORK(&call->work, SRXAFSCB_ProbeUuid);
- schedule_work(&call->work);
+ queue_work(afs_wq, &call->work);
return 0;
}
@@ -580,6 +580,6 @@ static int afs_deliver_cb_tell_me_about_yourself(struct afs_call *call,
call->state = AFS_CALL_REPLYING;
INIT_WORK(&call->work, SRXAFSCB_TellMeAboutYourself);
- schedule_work(&call->work);
+ queue_work(afs_wq, &call->work);
return 0;
}
diff --git a/fs/afs/dir.c b/fs/afs/dir.c
index e6a4ab9..20c106f 100644
--- a/fs/afs/dir.c
+++ b/fs/afs/dir.c
@@ -66,6 +66,7 @@ const struct dentry_operations afs_fs_dentry_operations = {
.d_revalidate = afs_d_revalidate,
.d_delete = afs_d_delete,
.d_release = afs_d_release,
+ .d_automount = afs_d_automount,
};
#define AFS_DIR_HASHTBL_SIZE 128
diff --git a/fs/afs/inode.c b/fs/afs/inode.c
index 0747339..db66c52 100644
--- a/fs/afs/inode.c
+++ b/fs/afs/inode.c
@@ -184,7 +184,8 @@ struct inode *afs_iget_autocell(struct inode *dir, const char *dev_name,
inode->i_generation = 0;
set_bit(AFS_VNODE_PSEUDODIR, &vnode->flags);
- inode->i_flags |= S_NOATIME;
+ set_bit(AFS_VNODE_MOUNTPOINT, &vnode->flags);
+ inode->i_flags |= S_AUTOMOUNT | S_NOATIME;
unlock_new_inode(inode);
_leave(" = %p", inode);
return inode;
diff --git a/fs/afs/internal.h b/fs/afs/internal.h
index ab6db5a..5a9b684 100644
--- a/fs/afs/internal.h
+++ b/fs/afs/internal.h
@@ -577,6 +577,7 @@ extern int afs_drop_inode(struct inode *);
/*
* main.c
*/
+extern struct workqueue_struct *afs_wq;
extern struct afs_uuid afs_uuid;
/*
@@ -591,6 +592,7 @@ extern const struct inode_operations afs_mntpt_inode_operations;
extern const struct inode_operations afs_autocell_inode_operations;
extern const struct file_operations afs_mntpt_file_operations;
+extern struct vfsmount *afs_d_automount(struct path *);
extern int afs_mntpt_check_symlink(struct afs_vnode *, struct key *);
extern void afs_mntpt_kill_timer(void);
diff --git a/fs/afs/main.c b/fs/afs/main.c
index cfd1cbe..42dd2e4 100644
--- a/fs/afs/main.c
+++ b/fs/afs/main.c
@@ -30,6 +30,7 @@ module_param(rootcell, charp, 0);
MODULE_PARM_DESC(rootcell, "root AFS cell name and VL server IP addr list");
struct afs_uuid afs_uuid;
+struct workqueue_struct *afs_wq;
/*
* get a client UUID
@@ -87,10 +88,16 @@ static int __init afs_init(void)
if (ret < 0)
return ret;
+ /* create workqueue */
+ ret = -ENOMEM;
+ afs_wq = alloc_workqueue("afs", 0, 0);
+ if (!afs_wq)
+ return ret;
+
/* register the /proc stuff */
ret = afs_proc_init();
if (ret < 0)
- return ret;
+ goto error_proc;
#ifdef CONFIG_AFS_FSCACHE
/* we want to be able to cache */
@@ -140,6 +147,8 @@ error_cell_init:
error_cache:
#endif
afs_proc_cleanup();
+error_proc:
+ destroy_workqueue(afs_wq);
rcu_barrier();
printk(KERN_ERR "kAFS: failed to register: %d\n", ret);
return ret;
@@ -163,7 +172,7 @@ static void __exit afs_exit(void)
afs_purge_servers();
afs_callback_update_kill();
afs_vlocation_purge();
- flush_scheduled_work();
+ destroy_workqueue(afs_wq);
afs_cell_purge();
#ifdef CONFIG_AFS_FSCACHE
fscache_unregister_netfs(&afs_cache_netfs);
diff --git a/fs/afs/mntpt.c b/fs/afs/mntpt.c
index 6153417..aa59184 100644
--- a/fs/afs/mntpt.c
+++ b/fs/afs/mntpt.c
@@ -24,7 +24,6 @@ static struct dentry *afs_mntpt_lookup(struct inode *dir,
struct dentry *dentry,
struct nameidata *nd);
static int afs_mntpt_open(struct inode *inode, struct file *file);
-static void *afs_mntpt_follow_link(struct dentry *dentry, struct nameidata *nd);
static void afs_mntpt_expiry_timed_out(struct work_struct *work);
const struct file_operations afs_mntpt_file_operations = {
@@ -34,13 +33,11 @@ const struct file_operations afs_mntpt_file_operations = {
const struct inode_operations afs_mntpt_inode_operations = {
.lookup = afs_mntpt_lookup,
- .follow_link = afs_mntpt_follow_link,
.readlink = page_readlink,
.getattr = afs_getattr,
};
const struct inode_operations afs_autocell_inode_operations = {
- .follow_link = afs_mntpt_follow_link,
.getattr = afs_getattr,
};
@@ -88,6 +85,7 @@ int afs_mntpt_check_symlink(struct afs_vnode *vnode, struct key *key)
_debug("symlink is a mountpoint");
spin_lock(&vnode->lock);
set_bit(AFS_VNODE_MOUNTPOINT, &vnode->flags);
+ vnode->vfs_inode.i_flags |= S_AUTOMOUNT;
spin_unlock(&vnode->lock);
}
@@ -238,52 +236,24 @@ error_no_devname:
}
/*
- * follow a link from a mountpoint directory, thus causing it to be mounted
+ * handle an automount point
*/
-static void *afs_mntpt_follow_link(struct dentry *dentry, struct nameidata *nd)
+struct vfsmount *afs_d_automount(struct path *path)
{
struct vfsmount *newmnt;
- int err;
- _enter("%p{%s},{%s:%p{%s},}",
- dentry,
- dentry->d_name.name,
- nd->path.mnt->mnt_devname,
- dentry,
- nd->path.dentry->d_name.name);
-
- dput(nd->path.dentry);
- nd->path.dentry = dget(dentry);
+ _enter("{%s,%s}", path->mnt->mnt_devname, path->dentry->d_name.name);
- newmnt = afs_mntpt_do_automount(nd->path.dentry);
- if (IS_ERR(newmnt)) {
- path_put(&nd->path);
- return (void *)newmnt;
- }
-
- mntget(newmnt);
- err = do_add_mount(newmnt, &nd->path, MNT_SHRINKABLE, &afs_vfsmounts);
- switch (err) {
- case 0:
- path_put(&nd->path);
- nd->path.mnt = newmnt;
- nd->path.dentry = dget(newmnt->mnt_root);
- schedule_delayed_work(&afs_mntpt_expiry_timer,
- afs_mntpt_expiry_timeout * HZ);
- break;
- case -EBUSY:
- /* someone else made a mount here whilst we were busy */
- while (d_mountpoint(nd->path.dentry) &&
- follow_down(&nd->path))
- ;
- err = 0;
- default:
- mntput(newmnt);
- break;
- }
+ newmnt = afs_mntpt_do_automount(path->dentry);
+ if (IS_ERR(newmnt))
+ return newmnt;
- _leave(" = %d", err);
- return ERR_PTR(err);
+ mntget(newmnt); /* prevent immediate expiration */
+ mnt_set_expiry(newmnt, &afs_vfsmounts);
+ queue_delayed_work(afs_wq, &afs_mntpt_expiry_timer,
+ afs_mntpt_expiry_timeout * HZ);
+ _leave(" = %p {%s}", newmnt, newmnt->mnt_devname);
+ return newmnt;
}
/*
@@ -295,8 +265,8 @@ static void afs_mntpt_expiry_timed_out(struct work_struct *work)
if (!list_empty(&afs_vfsmounts)) {
mark_mounts_for_expiry(&afs_vfsmounts);
- schedule_delayed_work(&afs_mntpt_expiry_timer,
- afs_mntpt_expiry_timeout * HZ);
+ queue_delayed_work(afs_wq, &afs_mntpt_expiry_timer,
+ afs_mntpt_expiry_timeout * HZ);
}
_leave("");
@@ -310,6 +280,5 @@ void afs_mntpt_kill_timer(void)
_enter("");
ASSERT(list_empty(&afs_vfsmounts));
- cancel_delayed_work(&afs_mntpt_expiry_timer);
- flush_scheduled_work();
+ cancel_delayed_work_sync(&afs_mntpt_expiry_timer);
}
diff --git a/fs/afs/rxrpc.c b/fs/afs/rxrpc.c
index 654d8fd..e45a323 100644
--- a/fs/afs/rxrpc.c
+++ b/fs/afs/rxrpc.c
@@ -410,7 +410,7 @@ static void afs_rx_interceptor(struct sock *sk, unsigned long user_call_ID,
if (!call) {
/* its an incoming call for our callback service */
skb_queue_tail(&afs_incoming_calls, skb);
- schedule_work(&afs_collect_incoming_call_work);
+ queue_work(afs_wq, &afs_collect_incoming_call_work);
} else {
/* route the messages directly to the appropriate call */
skb_queue_tail(&call->rx_queue, skb);
diff --git a/fs/afs/server.c b/fs/afs/server.c
index 9fdc7fe..d59b751 100644
--- a/fs/afs/server.c
+++ b/fs/afs/server.c
@@ -238,8 +238,8 @@ void afs_put_server(struct afs_server *server)
if (atomic_read(&server->usage) == 0) {
list_move_tail(&server->grave, &afs_server_graveyard);
server->time_of_death = get_seconds();
- schedule_delayed_work(&afs_server_reaper,
- afs_server_timeout * HZ);
+ queue_delayed_work(afs_wq, &afs_server_reaper,
+ afs_server_timeout * HZ);
}
spin_unlock(&afs_server_graveyard_lock);
_leave(" [dead]");
@@ -285,10 +285,11 @@ static void afs_reap_server(struct work_struct *work)
expiry = server->time_of_death + afs_server_timeout;
if (expiry > now) {
delay = (expiry - now) * HZ;
- if (!schedule_delayed_work(&afs_server_reaper, delay)) {
+ if (!queue_delayed_work(afs_wq, &afs_server_reaper,
+ delay)) {
cancel_delayed_work(&afs_server_reaper);
- schedule_delayed_work(&afs_server_reaper,
- delay);
+ queue_delayed_work(afs_wq, &afs_server_reaper,
+ delay);
}
break;
}
@@ -323,5 +324,5 @@ void __exit afs_purge_servers(void)
{
afs_server_timeout = 0;
cancel_delayed_work(&afs_server_reaper);
- schedule_delayed_work(&afs_server_reaper, 0);
+ queue_delayed_work(afs_wq, &afs_server_reaper, 0);
}
diff --git a/fs/afs/vlocation.c b/fs/afs/vlocation.c
index 9ac260d..431984d 100644
--- a/fs/afs/vlocation.c
+++ b/fs/afs/vlocation.c
@@ -507,8 +507,8 @@ void afs_put_vlocation(struct afs_vlocation *vl)
_debug("buried");
list_move_tail(&vl->grave, &afs_vlocation_graveyard);
vl->time_of_death = get_seconds();
- schedule_delayed_work(&afs_vlocation_reap,
- afs_vlocation_timeout * HZ);
+ queue_delayed_work(afs_wq, &afs_vlocation_reap,
+ afs_vlocation_timeout * HZ);
/* suspend updates on this record */
if (!list_empty(&vl->update)) {
@@ -561,11 +561,11 @@ static void afs_vlocation_reaper(struct work_struct *work)
if (expiry > now) {
delay = (expiry - now) * HZ;
_debug("delay %lu", delay);
- if (!schedule_delayed_work(&afs_vlocation_reap,
- delay)) {
+ if (!queue_delayed_work(afs_wq, &afs_vlocation_reap,
+ delay)) {
cancel_delayed_work(&afs_vlocation_reap);
- schedule_delayed_work(&afs_vlocation_reap,
- delay);
+ queue_delayed_work(afs_wq, &afs_vlocation_reap,
+ delay);
}
break;
}
@@ -620,7 +620,7 @@ void afs_vlocation_purge(void)
destroy_workqueue(afs_vlocation_update_worker);
cancel_delayed_work(&afs_vlocation_reap);
- schedule_delayed_work(&afs_vlocation_reap, 0);
+ queue_delayed_work(afs_wq, &afs_vlocation_reap, 0);
}
/*
diff --git a/fs/aio.c b/fs/aio.c
index 5e00f15..fc557a3 100644
--- a/fs/aio.c
+++ b/fs/aio.c
@@ -87,7 +87,7 @@ static int __init aio_setup(void)
aio_wq = create_workqueue("aio");
abe_pool = mempool_create_kmalloc_pool(1, sizeof(struct aio_batch_entry));
- BUG_ON(!abe_pool);
+ BUG_ON(!aio_wq || !abe_pool);
pr_debug("aio_setup: sizeof(struct page) = %d\n", (int)sizeof(struct page));
diff --git a/fs/anon_inodes.c b/fs/anon_inodes.c
index cbe57f3..c5567cb 100644
--- a/fs/anon_inodes.c
+++ b/fs/anon_inodes.c
@@ -233,7 +233,7 @@ static int __init anon_inode_init(void)
return 0;
err_mntput:
- mntput_long(anon_inode_mnt);
+ mntput(anon_inode_mnt);
err_unregister_filesystem:
unregister_filesystem(&anon_inode_fs_type);
err_exit:
diff --git a/fs/autofs4/autofs_i.h b/fs/autofs4/autofs_i.h
index 0fffe1c..54f9237 100644
--- a/fs/autofs4/autofs_i.h
+++ b/fs/autofs4/autofs_i.h
@@ -88,18 +88,9 @@ struct autofs_info {
uid_t uid;
gid_t gid;
-
- mode_t mode;
- size_t size;
-
- void (*free)(struct autofs_info *);
- union {
- const char *symlink;
- } u;
};
#define AUTOFS_INF_EXPIRING (1<<0) /* dentry is in the process of expiring */
-#define AUTOFS_INF_MOUNTPOINT (1<<1) /* mountpoint status for direct expire */
#define AUTOFS_INF_PENDING (1<<2) /* dentry pending mount */
struct autofs_wait_queue {
@@ -176,14 +167,7 @@ static inline int autofs4_ispending(struct dentry *dentry)
return 0;
}
-static inline void autofs4_copy_atime(struct file *src, struct file *dst)
-{
- dst->f_path.dentry->d_inode->i_atime =
- src->f_path.dentry->d_inode->i_atime;
- return;
-}
-
-struct inode *autofs4_get_inode(struct super_block *, struct autofs_info *);
+struct inode *autofs4_get_inode(struct super_block *, mode_t);
void autofs4_free_ino(struct autofs_info *);
/* Expiration */
@@ -212,16 +196,89 @@ void autofs_dev_ioctl_exit(void);
extern const struct inode_operations autofs4_symlink_inode_operations;
extern const struct inode_operations autofs4_dir_inode_operations;
-extern const struct inode_operations autofs4_root_inode_operations;
-extern const struct inode_operations autofs4_indirect_root_inode_operations;
-extern const struct inode_operations autofs4_direct_root_inode_operations;
extern const struct file_operations autofs4_dir_operations;
extern const struct file_operations autofs4_root_operations;
+extern const struct dentry_operations autofs4_dentry_operations;
+
+/* VFS automount flags management functions */
+
+static inline void __managed_dentry_set_automount(struct dentry *dentry)
+{
+ dentry->d_flags |= DCACHE_NEED_AUTOMOUNT;
+}
+
+static inline void managed_dentry_set_automount(struct dentry *dentry)
+{
+ spin_lock(&dentry->d_lock);
+ __managed_dentry_set_automount(dentry);
+ spin_unlock(&dentry->d_lock);
+}
+
+static inline void __managed_dentry_clear_automount(struct dentry *dentry)
+{
+ dentry->d_flags &= ~DCACHE_NEED_AUTOMOUNT;
+}
+
+static inline void managed_dentry_clear_automount(struct dentry *dentry)
+{
+ spin_lock(&dentry->d_lock);
+ __managed_dentry_clear_automount(dentry);
+ spin_unlock(&dentry->d_lock);
+}
+
+static inline void __managed_dentry_set_transit(struct dentry *dentry)
+{
+ dentry->d_flags |= DCACHE_MANAGE_TRANSIT;
+}
+
+static inline void managed_dentry_set_transit(struct dentry *dentry)
+{
+ spin_lock(&dentry->d_lock);
+ __managed_dentry_set_transit(dentry);
+ spin_unlock(&dentry->d_lock);
+}
+
+static inline void __managed_dentry_clear_transit(struct dentry *dentry)
+{
+ dentry->d_flags &= ~DCACHE_MANAGE_TRANSIT;
+}
+
+static inline void managed_dentry_clear_transit(struct dentry *dentry)
+{
+ spin_lock(&dentry->d_lock);
+ __managed_dentry_clear_transit(dentry);
+ spin_unlock(&dentry->d_lock);
+}
+
+static inline void __managed_dentry_set_managed(struct dentry *dentry)
+{
+ dentry->d_flags |= (DCACHE_NEED_AUTOMOUNT|DCACHE_MANAGE_TRANSIT);
+}
+
+static inline void managed_dentry_set_managed(struct dentry *dentry)
+{
+ spin_lock(&dentry->d_lock);
+ __managed_dentry_set_managed(dentry);
+ spin_unlock(&dentry->d_lock);
+}
+
+static inline void __managed_dentry_clear_managed(struct dentry *dentry)
+{
+ dentry->d_flags &= ~(DCACHE_NEED_AUTOMOUNT|DCACHE_MANAGE_TRANSIT);
+}
+
+static inline void managed_dentry_clear_managed(struct dentry *dentry)
+{
+ spin_lock(&dentry->d_lock);
+ __managed_dentry_clear_managed(dentry);
+ spin_unlock(&dentry->d_lock);
+}
/* Initializing function */
int autofs4_fill_super(struct super_block *, void *, int);
-struct autofs_info *autofs4_init_ino(struct autofs_info *, struct autofs_sb_info *sbi, mode_t mode);
+struct autofs_info *autofs4_new_ino(struct autofs_sb_info *);
+void autofs4_clean_ino(struct autofs_info *);
/* Queue management functions */
@@ -229,19 +286,6 @@ int autofs4_wait(struct autofs_sb_info *,struct dentry *, enum autofs_notify);
int autofs4_wait_release(struct autofs_sb_info *,autofs_wqt_t,int);
void autofs4_catatonic_mode(struct autofs_sb_info *);
-static inline int autofs4_follow_mount(struct path *path)
-{
- int res = 0;
-
- while (d_mountpoint(path->dentry)) {
- int followed = follow_down(path);
- if (!followed)
- break;
- res = 1;
- }
- return res;
-}
-
static inline u32 autofs4_get_dev(struct autofs_sb_info *sbi)
{
return new_encode_dev(sbi->sb->s_dev);
@@ -294,5 +338,4 @@ static inline void autofs4_del_expiring(struct dentry *dentry)
return;
}
-void autofs4_dentry_release(struct dentry *);
extern void autofs4_kill_sb(struct super_block *);
diff --git a/fs/autofs4/dev-ioctl.c b/fs/autofs4/dev-ioctl.c
index eff9a41..1442da4 100644
--- a/fs/autofs4/dev-ioctl.c
+++ b/fs/autofs4/dev-ioctl.c
@@ -551,7 +551,7 @@ static int autofs_dev_ioctl_ismountpoint(struct file *fp,
err = have_submounts(path.dentry);
- if (follow_down(&path))
+ if (follow_down_one(&path))
magic = path.mnt->mnt_sb->s_magic;
}
diff --git a/fs/autofs4/expire.c b/fs/autofs4/expire.c
index cc1d013..f43100b 100644
--- a/fs/autofs4/expire.c
+++ b/fs/autofs4/expire.c
@@ -26,10 +26,6 @@ static inline int autofs4_can_expire(struct dentry *dentry,
if (ino == NULL)
return 0;
- /* No point expiring a pending mount */
- if (ino->flags & AUTOFS_INF_PENDING)
- return 0;
-
if (!do_now) {
/* Too young to die */
if (!timeout || time_after(ino->last_used + timeout, now))
@@ -56,7 +52,7 @@ static int autofs4_mount_busy(struct vfsmount *mnt, struct dentry *dentry)
path_get(&path);
- if (!follow_down(&path))
+ if (!follow_down_one(&path))
goto done;
if (is_autofs4_dentry(path.dentry)) {
@@ -100,7 +96,7 @@ static struct dentry *get_next_positive_dentry(struct dentry *prev,
struct dentry *p, *ret;
if (prev == NULL)
- return dget(prev);
+ return dget(root);
spin_lock(&autofs4_lock);
relock:
@@ -137,7 +133,7 @@ again:
spin_lock_nested(&ret->d_lock, DENTRY_D_LOCK_NESTED);
/* Negative dentry - try next */
if (!simple_positive(ret)) {
- spin_unlock(&ret->d_lock);
+ spin_unlock(&p->d_lock);
p = ret;
goto again;
}
@@ -283,6 +279,7 @@ struct dentry *autofs4_expire_direct(struct super_block *sb,
unsigned long timeout;
struct dentry *root = dget(sb->s_root);
int do_now = how & AUTOFS_EXP_IMMEDIATE;
+ struct autofs_info *ino;
if (!root)
return NULL;
@@ -291,19 +288,21 @@ struct dentry *autofs4_expire_direct(struct super_block *sb,
timeout = sbi->exp_timeout;
spin_lock(&sbi->fs_lock);
+ ino = autofs4_dentry_ino(root);
+ /* No point expiring a pending mount */
+ if (ino->flags & AUTOFS_INF_PENDING) {
+ spin_unlock(&sbi->fs_lock);
+ return NULL;
+ }
+ managed_dentry_set_transit(root);
if (!autofs4_direct_busy(mnt, root, timeout, do_now)) {
struct autofs_info *ino = autofs4_dentry_ino(root);
- if (d_mountpoint(root)) {
- ino->flags |= AUTOFS_INF_MOUNTPOINT;
- spin_lock(&root->d_lock);
- root->d_flags &= ~DCACHE_MOUNTED;
- spin_unlock(&root->d_lock);
- }
ino->flags |= AUTOFS_INF_EXPIRING;
init_completion(&ino->expire_complete);
spin_unlock(&sbi->fs_lock);
return root;
}
+ managed_dentry_clear_transit(root);
spin_unlock(&sbi->fs_lock);
dput(root);
@@ -340,6 +339,10 @@ struct dentry *autofs4_expire_indirect(struct super_block *sb,
while ((dentry = get_next_positive_dentry(dentry, root))) {
spin_lock(&sbi->fs_lock);
ino = autofs4_dentry_ino(dentry);
+ /* No point expiring a pending mount */
+ if (ino->flags & AUTOFS_INF_PENDING)
+ goto cont;
+ managed_dentry_set_transit(dentry);
/*
* Case 1: (i) indirect mount or top level pseudo direct mount
@@ -399,6 +402,8 @@ struct dentry *autofs4_expire_indirect(struct super_block *sb,
}
}
next:
+ managed_dentry_clear_transit(dentry);
+cont:
spin_unlock(&sbi->fs_lock);
}
return NULL;
@@ -479,6 +484,8 @@ int autofs4_expire_run(struct super_block *sb,
spin_lock(&sbi->fs_lock);
ino = autofs4_dentry_ino(dentry);
ino->flags &= ~AUTOFS_INF_EXPIRING;
+ if (!d_unhashed(dentry))
+ managed_dentry_clear_transit(dentry);
complete_all(&ino->expire_complete);
spin_unlock(&sbi->fs_lock);
@@ -504,18 +511,18 @@ int autofs4_do_expire_multi(struct super_block *sb, struct vfsmount *mnt,
ret = autofs4_wait(sbi, dentry, NFY_EXPIRE);
spin_lock(&sbi->fs_lock);
- if (ino->flags & AUTOFS_INF_MOUNTPOINT) {
- spin_lock(&sb->s_root->d_lock);
- /*
- * If we haven't been expired away, then reset
- * mounted status.
- */
- if (mnt->mnt_parent != mnt)
- sb->s_root->d_flags |= DCACHE_MOUNTED;
- spin_unlock(&sb->s_root->d_lock);
- ino->flags &= ~AUTOFS_INF_MOUNTPOINT;
- }
ino->flags &= ~AUTOFS_INF_EXPIRING;
+ spin_lock(&dentry->d_lock);
+ if (ret)
+ __managed_dentry_clear_transit(dentry);
+ else {
+ if ((IS_ROOT(dentry) ||
+ (autofs_type_indirect(sbi->type) &&
+ IS_ROOT(dentry->d_parent))) &&
+ !(dentry->d_flags & DCACHE_NEED_AUTOMOUNT))
+ __managed_dentry_set_automount(dentry);
+ }
+ spin_unlock(&dentry->d_lock);
complete_all(&ino->expire_complete);
spin_unlock(&sbi->fs_lock);
dput(dentry);
diff --git a/fs/autofs4/inode.c b/fs/autofs4/inode.c
index a7bdb9d..180fa24 100644
--- a/fs/autofs4/inode.c
+++ b/fs/autofs4/inode.c
@@ -22,77 +22,27 @@
#include "autofs_i.h"
#include <linux/module.h>
-static void ino_lnkfree(struct autofs_info *ino)
+struct autofs_info *autofs4_new_ino(struct autofs_sb_info *sbi)
{
- if (ino->u.symlink) {
- kfree(ino->u.symlink);
- ino->u.symlink = NULL;
- }
-}
-
-struct autofs_info *autofs4_init_ino(struct autofs_info *ino,
- struct autofs_sb_info *sbi, mode_t mode)
-{
- int reinit = 1;
-
- if (ino == NULL) {
- reinit = 0;
- ino = kmalloc(sizeof(*ino), GFP_KERNEL);
- }
-
- if (ino == NULL)
- return NULL;
-
- if (!reinit) {
- ino->flags = 0;
- ino->inode = NULL;
- ino->dentry = NULL;
- ino->size = 0;
+ struct autofs_info *ino = kzalloc(sizeof(*ino), GFP_KERNEL);
+ if (ino) {
INIT_LIST_HEAD(&ino->active);
- ino->active_count = 0;
INIT_LIST_HEAD(&ino->expiring);
- atomic_set(&ino->count, 0);
+ ino->last_used = jiffies;
+ ino->sbi = sbi;
}
+ return ino;
+}
+void autofs4_clean_ino(struct autofs_info *ino)
+{
ino->uid = 0;
ino->gid = 0;
- ino->mode = mode;
ino->last_used = jiffies;
-
- ino->sbi = sbi;
-
- if (reinit && ino->free)
- (ino->free)(ino);
-
- memset(&ino->u, 0, sizeof(ino->u));
-
- ino->free = NULL;
-
- if (S_ISLNK(mode))
- ino->free = ino_lnkfree;
-
- return ino;
}
void autofs4_free_ino(struct autofs_info *ino)
{
- struct autofs_info *p_ino;
-
- if (ino->dentry) {
- ino->dentry->d_fsdata = NULL;
- if (ino->dentry->d_inode) {
- struct dentry *parent = ino->dentry->d_parent;
- if (atomic_dec_and_test(&ino->count)) {
- p_ino = autofs4_dentry_ino(parent);
- if (p_ino && parent != ino->dentry)
- atomic_dec(&p_ino->count);
- }
- dput(ino->dentry);
- }
- ino->dentry = NULL;
- }
- if (ino->free)
- (ino->free)(ino);
kfree(ino);
}
@@ -148,9 +98,16 @@ static int autofs4_show_options(struct seq_file *m, struct vfsmount *mnt)
return 0;
}
+static void autofs4_evict_inode(struct inode *inode)
+{
+ end_writeback(inode);
+ kfree(inode->i_private);
+}
+
static const struct super_operations autofs4_sops = {
.statfs = simple_statfs,
.show_options = autofs4_show_options,
+ .evict_inode = autofs4_evict_inode,
};
enum {Opt_err, Opt_fd, Opt_uid, Opt_gid, Opt_pgrp, Opt_minproto, Opt_maxproto,
@@ -240,21 +197,6 @@ static int parse_options(char *options, int *pipefd, uid_t *uid, gid_t *gid,
return (*pipefd < 0);
}
-static struct autofs_info *autofs4_mkroot(struct autofs_sb_info *sbi)
-{
- struct autofs_info *ino;
-
- ino = autofs4_init_ino(NULL, sbi, S_IFDIR | 0755);
- if (!ino)
- return NULL;
-
- return ino;
-}
-
-static const struct dentry_operations autofs4_sb_dentry_operations = {
- .d_release = autofs4_dentry_release,
-};
-
int autofs4_fill_super(struct super_block *s, void *data, int silent)
{
struct inode * root_inode;
@@ -292,15 +234,16 @@ int autofs4_fill_super(struct super_block *s, void *data, int silent)
s->s_blocksize_bits = 10;
s->s_magic = AUTOFS_SUPER_MAGIC;
s->s_op = &autofs4_sops;
+ s->s_d_op = &autofs4_dentry_operations;
s->s_time_gran = 1;
/*
* Get the root inode and dentry, but defer checking for errors.
*/
- ino = autofs4_mkroot(sbi);
+ ino = autofs4_new_ino(sbi);
if (!ino)
goto fail_free;
- root_inode = autofs4_get_inode(s, ino);
+ root_inode = autofs4_get_inode(s, S_IFDIR | 0755);
if (!root_inode)
goto fail_ino;
@@ -309,7 +252,6 @@ int autofs4_fill_super(struct super_block *s, void *data, int silent)
goto fail_iput;
pipe = NULL;
- d_set_d_op(root, &autofs4_sb_dentry_operations);
root->d_fsdata = ino;
/* Can this call block? */
@@ -320,10 +262,11 @@ int autofs4_fill_super(struct super_block *s, void *data, int silent)
goto fail_dput;
}
+ if (autofs_type_trigger(sbi->type))
+ __managed_dentry_set_managed(root);
+
root_inode->i_fop = &autofs4_root_operations;
- root_inode->i_op = autofs_type_trigger(sbi->type) ?
- &autofs4_direct_root_inode_operations :
- &autofs4_indirect_root_inode_operations;
+ root_inode->i_op = &autofs4_dir_inode_operations;
/* Couldn't this be tested earlier? */
if (sbi->max_proto < AUTOFS_MIN_PROTO_VERSION ||
@@ -383,16 +326,14 @@ fail_unlock:
return -EINVAL;
}
-struct inode *autofs4_get_inode(struct super_block *sb,
- struct autofs_info *inf)
+struct inode *autofs4_get_inode(struct super_block *sb, mode_t mode)
{
struct inode *inode = new_inode(sb);
if (inode == NULL)
return NULL;
- inf->inode = inode;
- inode->i_mode = inf->mode;
+ inode->i_mode = mode;
if (sb->s_root) {
inode->i_uid = sb->s_root->d_inode->i_uid;
inode->i_gid = sb->s_root->d_inode->i_gid;
@@ -400,12 +341,11 @@ struct inode *autofs4_get_inode(struct super_block *sb,
inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
inode->i_ino = get_next_ino();
- if (S_ISDIR(inf->mode)) {
+ if (S_ISDIR(mode)) {
inode->i_nlink = 2;
inode->i_op = &autofs4_dir_inode_operations;
inode->i_fop = &autofs4_dir_operations;
- } else if (S_ISLNK(inf->mode)) {
- inode->i_size = inf->size;
+ } else if (S_ISLNK(mode)) {
inode->i_op = &autofs4_symlink_inode_operations;
}
diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c
index 651e4ef..014e7ab 100644
--- a/fs/autofs4/root.c
+++ b/fs/autofs4/root.c
@@ -35,10 +35,9 @@ static long autofs4_root_compat_ioctl(struct file *,unsigned int,unsigned long);
#endif
static int autofs4_dir_open(struct inode *inode, struct file *file);
static struct dentry *autofs4_lookup(struct inode *,struct dentry *, struct nameidata *);
-static void *autofs4_follow_link(struct dentry *, struct nameidata *);
-
-#define TRIGGER_FLAGS (LOOKUP_CONTINUE | LOOKUP_DIRECTORY)
-#define TRIGGER_INTENTS (LOOKUP_OPEN | LOOKUP_CREATE)
+static struct vfsmount *autofs4_d_automount(struct path *);
+static int autofs4_d_manage(struct dentry *, bool, bool);
+static void autofs4_dentry_release(struct dentry *);
const struct file_operations autofs4_root_operations = {
.open = dcache_dir_open,
@@ -60,7 +59,7 @@ const struct file_operations autofs4_dir_operations = {
.llseek = dcache_dir_lseek,
};
-const struct inode_operations autofs4_indirect_root_inode_operations = {
+const struct inode_operations autofs4_dir_inode_operations = {
.lookup = autofs4_lookup,
.unlink = autofs4_dir_unlink,
.symlink = autofs4_dir_symlink,
@@ -68,20 +67,10 @@ const struct inode_operations autofs4_indirect_root_inode_operations = {
.rmdir = autofs4_dir_rmdir,
};
-const struct inode_operations autofs4_direct_root_inode_operations = {
- .lookup = autofs4_lookup,
- .unlink = autofs4_dir_unlink,
- .mkdir = autofs4_dir_mkdir,
- .rmdir = autofs4_dir_rmdir,
- .follow_link = autofs4_follow_link,
-};
-
-const struct inode_operations autofs4_dir_inode_operations = {
- .lookup = autofs4_lookup,
- .unlink = autofs4_dir_unlink,
- .symlink = autofs4_dir_symlink,
- .mkdir = autofs4_dir_mkdir,
- .rmdir = autofs4_dir_rmdir,
+const struct dentry_operations autofs4_dentry_operations = {
+ .d_automount = autofs4_d_automount,
+ .d_manage = autofs4_d_manage,
+ .d_release = autofs4_dentry_release,
};
static void autofs4_add_active(struct dentry *dentry)
@@ -116,14 +105,6 @@ static void autofs4_del_active(struct dentry *dentry)
return;
}
-static unsigned int autofs4_need_mount(unsigned int flags)
-{
- unsigned int res = 0;
- if (flags & (TRIGGER_FLAGS | TRIGGER_INTENTS))
- res = 1;
- return res;
-}
-
static int autofs4_dir_open(struct inode *inode, struct file *file)
{
struct dentry *dentry = file->f_path.dentry;
@@ -158,278 +139,27 @@ out:
return dcache_dir_open(inode, file);
}
-static int try_to_fill_dentry(struct dentry *dentry, int flags)
-{
- struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb);
- struct autofs_info *ino = autofs4_dentry_ino(dentry);
- int status;
-
- DPRINTK("dentry=%p %.*s ino=%p",
- dentry, dentry->d_name.len, dentry->d_name.name, dentry->d_inode);
-
- /*
- * Wait for a pending mount, triggering one if there
- * isn't one already
- */
- if (dentry->d_inode == NULL) {
- DPRINTK("waiting for mount name=%.*s",
- dentry->d_name.len, dentry->d_name.name);
-
- status = autofs4_wait(sbi, dentry, NFY_MOUNT);
-
- DPRINTK("mount done status=%d", status);
-
- /* Turn this into a real negative dentry? */
- if (status == -ENOENT) {
- spin_lock(&sbi->fs_lock);
- ino->flags &= ~AUTOFS_INF_PENDING;
- spin_unlock(&sbi->fs_lock);
- return status;
- } else if (status) {
- /* Return a negative dentry, but leave it "pending" */
- return status;
- }
- /* Trigger mount for path component or follow link */
- } else if (ino->flags & AUTOFS_INF_PENDING ||
- autofs4_need_mount(flags)) {
- DPRINTK("waiting for mount name=%.*s",
- dentry->d_name.len, dentry->d_name.name);
-
- spin_lock(&sbi->fs_lock);
- ino->flags |= AUTOFS_INF_PENDING;
- spin_unlock(&sbi->fs_lock);
- status = autofs4_wait(sbi, dentry, NFY_MOUNT);
-
- DPRINTK("mount done status=%d", status);
-
- if (status) {
- spin_lock(&sbi->fs_lock);
- ino->flags &= ~AUTOFS_INF_PENDING;
- spin_unlock(&sbi->fs_lock);
- return status;
- }
- }
-
- /* Initialize expiry counter after successful mount */
- ino->last_used = jiffies;
-
- spin_lock(&sbi->fs_lock);
- ino->flags &= ~AUTOFS_INF_PENDING;
- spin_unlock(&sbi->fs_lock);
-
- return 0;
-}
-
-/* For autofs direct mounts the follow link triggers the mount */
-static void *autofs4_follow_link(struct dentry *dentry, struct nameidata *nd)
-{
- struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb);
- struct autofs_info *ino = autofs4_dentry_ino(dentry);
- int oz_mode = autofs4_oz_mode(sbi);
- unsigned int lookup_type;
- int status;
-
- DPRINTK("dentry=%p %.*s oz_mode=%d nd->flags=%d",
- dentry, dentry->d_name.len, dentry->d_name.name, oz_mode,
- nd->flags);
- /*
- * For an expire of a covered direct or offset mount we need
- * to break out of follow_down() at the autofs mount trigger
- * (d_mounted--), so we can see the expiring flag, and manage
- * the blocking and following here until the expire is completed.
- */
- if (oz_mode) {
- spin_lock(&sbi->fs_lock);
- if (ino->flags & AUTOFS_INF_EXPIRING) {
- spin_unlock(&sbi->fs_lock);
- /* Follow down to our covering mount. */
- if (!follow_down(&nd->path))
- goto done;
- goto follow;
- }
- spin_unlock(&sbi->fs_lock);
- goto done;
- }
-
- /* If an expire request is pending everyone must wait. */
- autofs4_expire_wait(dentry);
-
- /* We trigger a mount for almost all flags */
- lookup_type = autofs4_need_mount(nd->flags);
- spin_lock(&sbi->fs_lock);
- spin_lock(&autofs4_lock);
- spin_lock(&dentry->d_lock);
- if (!(lookup_type || ino->flags & AUTOFS_INF_PENDING)) {
- spin_unlock(&dentry->d_lock);
- spin_unlock(&autofs4_lock);
- spin_unlock(&sbi->fs_lock);
- goto follow;
- }
-
- /*
- * If the dentry contains directories then it is an autofs
- * multi-mount with no root mount offset. So don't try to
- * mount it again.
- */
- if (ino->flags & AUTOFS_INF_PENDING ||
- (!d_mountpoint(dentry) && list_empty(&dentry->d_subdirs))) {
- spin_unlock(&dentry->d_lock);
- spin_unlock(&autofs4_lock);
- spin_unlock(&sbi->fs_lock);
-
- status = try_to_fill_dentry(dentry, nd->flags);
- if (status)
- goto out_error;
-
- goto follow;
- }
- spin_unlock(&dentry->d_lock);
- spin_unlock(&autofs4_lock);
- spin_unlock(&sbi->fs_lock);
-follow:
- /*
- * If there is no root mount it must be an autofs
- * multi-mount with no root offset so we don't need
- * to follow it.
- */
- if (d_mountpoint(dentry)) {
- if (!autofs4_follow_mount(&nd->path)) {
- status = -ENOENT;
- goto out_error;
- }
- }
-
-done:
- return NULL;
-
-out_error:
- path_put(&nd->path);
- return ERR_PTR(status);
-}
-
-/*
- * Revalidate is called on every cache lookup. Some of those
- * cache lookups may actually happen while the dentry is not
- * yet completely filled in, and revalidate has to delay such
- * lookups..
- */
-static int autofs4_revalidate(struct dentry *dentry, struct nameidata *nd)
+static void autofs4_dentry_release(struct dentry *de)
{
- struct inode *dir;
- struct autofs_sb_info *sbi;
- int oz_mode;
- int flags = nd ? nd->flags : 0;
- int status = 1;
-
- if (flags & LOOKUP_RCU)
- return -ECHILD;
-
- dir = dentry->d_parent->d_inode;
- sbi = autofs4_sbi(dir->i_sb);
- oz_mode = autofs4_oz_mode(sbi);
-
- /* Pending dentry */
- spin_lock(&sbi->fs_lock);
- if (autofs4_ispending(dentry)) {
- /* The daemon never causes a mount to trigger */
- spin_unlock(&sbi->fs_lock);
-
- if (oz_mode)
- return 1;
-
- /*
- * If the directory has gone away due to an expire
- * we have been called as ->d_revalidate() and so
- * we need to return false and proceed to ->lookup().
- */
- if (autofs4_expire_wait(dentry) == -EAGAIN)
- return 0;
-
- /*
- * A zero status is success otherwise we have a
- * negative error code.
- */
- status = try_to_fill_dentry(dentry, flags);
- if (status == 0)
- return 1;
-
- return status;
- }
- spin_unlock(&sbi->fs_lock);
-
- /* Negative dentry.. invalidate if "old" */
- if (dentry->d_inode == NULL)
- return 0;
-
- /* Check for a non-mountpoint directory with no contents */
- spin_lock(&autofs4_lock);
- spin_lock(&dentry->d_lock);
- if (S_ISDIR(dentry->d_inode->i_mode) &&
- !d_mountpoint(dentry) && list_empty(&dentry->d_subdirs)) {
- DPRINTK("dentry=%p %.*s, emptydir",
- dentry, dentry->d_name.len, dentry->d_name.name);
- spin_unlock(&dentry->d_lock);
- spin_unlock(&autofs4_lock);
-
- /* The daemon never causes a mount to trigger */
- if (oz_mode)
- return 1;
-
- /*
- * A zero status is success otherwise we have a
- * negative error code.
- */
- status = try_to_fill_dentry(dentry, flags);
- if (status == 0)
- return 1;
-
- return status;
- }
- spin_unlock(&dentry->d_lock);
- spin_unlock(&autofs4_lock);
-
- return 1;
-}
-
-void autofs4_dentry_release(struct dentry *de)
-{
- struct autofs_info *inf;
+ struct autofs_info *ino = autofs4_dentry_ino(de);
+ struct autofs_sb_info *sbi = autofs4_sbi(de->d_sb);
DPRINTK("releasing %p", de);
- inf = autofs4_dentry_ino(de);
- de->d_fsdata = NULL;
-
- if (inf) {
- struct autofs_sb_info *sbi = autofs4_sbi(de->d_sb);
-
- if (sbi) {
- spin_lock(&sbi->lookup_lock);
- if (!list_empty(&inf->active))
- list_del(&inf->active);
- if (!list_empty(&inf->expiring))
- list_del(&inf->expiring);
- spin_unlock(&sbi->lookup_lock);
- }
-
- inf->dentry = NULL;
- inf->inode = NULL;
+ if (!ino)
+ return;
- autofs4_free_ino(inf);
+ if (sbi) {
+ spin_lock(&sbi->lookup_lock);
+ if (!list_empty(&ino->active))
+ list_del(&ino->active);
+ if (!list_empty(&ino->expiring))
+ list_del(&ino->expiring);
+ spin_unlock(&sbi->lookup_lock);
}
-}
-/* For dentries of directories in the root dir */
-static const struct dentry_operations autofs4_root_dentry_operations = {
- .d_revalidate = autofs4_revalidate,
- .d_release = autofs4_dentry_release,
-};
-
-/* For other dentries */
-static const struct dentry_operations autofs4_dentry_operations = {
- .d_revalidate = autofs4_revalidate,
- .d_release = autofs4_dentry_release,
-};
+ autofs4_free_ino(ino);
+}
static struct dentry *autofs4_lookup_active(struct dentry *dentry)
{
@@ -541,51 +271,246 @@ next:
return NULL;
}
+static int autofs4_mount_wait(struct dentry *dentry)
+{
+ struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb);
+ struct autofs_info *ino = autofs4_dentry_ino(dentry);
+ int status;
+
+ if (ino->flags & AUTOFS_INF_PENDING) {
+ DPRINTK("waiting for mount name=%.*s",
+ dentry->d_name.len, dentry->d_name.name);
+ status = autofs4_wait(sbi, dentry, NFY_MOUNT);
+ DPRINTK("mount wait done status=%d", status);
+ ino->last_used = jiffies;
+ return status;
+ }
+ return 0;
+}
+
+static int do_expire_wait(struct dentry *dentry)
+{
+ struct dentry *expiring;
+
+ expiring = autofs4_lookup_expiring(dentry);
+ if (!expiring)
+ return autofs4_expire_wait(dentry);
+ else {
+ /*
+ * If we are racing with expire the request might not
+ * be quite complete, but the directory has been removed
+ * so it must have been successful, just wait for it.
+ */
+ autofs4_expire_wait(expiring);
+ autofs4_del_expiring(expiring);
+ dput(expiring);
+ }
+ return 0;
+}
+
+static struct dentry *autofs4_mountpoint_changed(struct path *path)
+{
+ struct dentry *dentry = path->dentry;
+ struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb);
+
+ /*
+ * If this is an indirect mount the dentry could have gone away
+ * as a result of an expire and a new one created.
+ */
+ if (autofs_type_indirect(sbi->type) && d_unhashed(dentry)) {
+ struct dentry *parent = dentry->d_parent;
+ struct dentry *new = d_lookup(parent, &dentry->d_name);
+ if (!new)
+ return NULL;
+ dput(path->dentry);
+ path->dentry = new;
+ }
+ return path->dentry;
+}
+
+static struct vfsmount *autofs4_d_automount(struct path *path)
+{
+ struct dentry *dentry = path->dentry;
+ struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb);
+ struct autofs_info *ino = autofs4_dentry_ino(dentry);
+ int status;
+
+ DPRINTK("dentry=%p %.*s",
+ dentry, dentry->d_name.len, dentry->d_name.name);
+
+ /*
+ * Someone may have manually umounted this or it was a submount
+ * that has gone away.
+ */
+ spin_lock(&dentry->d_lock);
+ if (!d_mountpoint(dentry) && list_empty(&dentry->d_subdirs)) {
+ if (!(dentry->d_flags & DCACHE_MANAGE_TRANSIT) &&
+ (dentry->d_flags & DCACHE_NEED_AUTOMOUNT))
+ __managed_dentry_set_transit(path->dentry);
+ }
+ spin_unlock(&dentry->d_lock);
+
+ /* The daemon never triggers a mount. */
+ if (autofs4_oz_mode(sbi))
+ return NULL;
+
+ /*
+ * If an expire request is pending everyone must wait.
+ * If the expire fails we're still mounted so continue
+ * the follow and return. A return of -EAGAIN (which only
+ * happens with indirect mounts) means the expire completed
+ * and the directory was removed, so just go ahead and try
+ * the mount.
+ */
+ status = do_expire_wait(dentry);
+ if (status && status != -EAGAIN)
+ return NULL;
+
+ /* Callback to the daemon to perform the mount or wait */
+ spin_lock(&sbi->fs_lock);
+ if (ino->flags & AUTOFS_INF_PENDING) {
+ spin_unlock(&sbi->fs_lock);
+ status = autofs4_mount_wait(dentry);
+ if (status)
+ return ERR_PTR(status);
+ spin_lock(&sbi->fs_lock);
+ goto done;
+ }
+
+ /*
+ * If the dentry is a symlink it's equivalent to a directory
+ * having d_mountpoint() true, so there's no need to call back
+ * to the daemon.
+ */
+ if (dentry->d_inode && S_ISLNK(dentry->d_inode->i_mode))
+ goto done;
+ if (!d_mountpoint(dentry)) {
+ /*
+ * It's possible that user space hasn't removed directories
+ * after umounting a rootless multi-mount, although it
+ * should. For v5 have_submounts() is sufficient to handle
+ * this because the leaves of the directory tree under the
+ * mount never trigger mounts themselves (they have an autofs
+ * trigger mount mounted on them). But v4 pseudo direct mounts
+ * do need the leaves to to trigger mounts. In this case we
+ * have no choice but to use the list_empty() check and
+ * require user space behave.
+ */
+ if (sbi->version > 4) {
+ if (have_submounts(dentry))
+ goto done;
+ } else {
+ spin_lock(&dentry->d_lock);
+ if (!list_empty(&dentry->d_subdirs)) {
+ spin_unlock(&dentry->d_lock);
+ goto done;
+ }
+ spin_unlock(&dentry->d_lock);
+ }
+ ino->flags |= AUTOFS_INF_PENDING;
+ spin_unlock(&sbi->fs_lock);
+ status = autofs4_mount_wait(dentry);
+ if (status)
+ return ERR_PTR(status);
+ spin_lock(&sbi->fs_lock);
+ ino->flags &= ~AUTOFS_INF_PENDING;
+ }
+done:
+ if (!(ino->flags & AUTOFS_INF_EXPIRING)) {
+ /*
+ * Any needed mounting has been completed and the path updated
+ * so turn this into a normal dentry so we don't continually
+ * call ->d_automount() and ->d_manage().
+ */
+ spin_lock(&dentry->d_lock);
+ __managed_dentry_clear_transit(dentry);
+ /*
+ * Only clear DMANAGED_AUTOMOUNT for rootless multi-mounts and
+ * symlinks as in all other cases the dentry will be covered by
+ * an actual mount so ->d_automount() won't be called during
+ * the follow.
+ */
+ if ((!d_mountpoint(dentry) &&
+ !list_empty(&dentry->d_subdirs)) ||
+ (dentry->d_inode && S_ISLNK(dentry->d_inode->i_mode)))
+ __managed_dentry_clear_automount(dentry);
+ spin_unlock(&dentry->d_lock);
+ }
+ spin_unlock(&sbi->fs_lock);
+
+ /* Mount succeeded, check if we ended up with a new dentry */
+ dentry = autofs4_mountpoint_changed(path);
+ if (!dentry)
+ return ERR_PTR(-ENOENT);
+
+ return NULL;
+}
+
+int autofs4_d_manage(struct dentry *dentry, bool mounting_here, bool rcu_walk)
+{
+ struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb);
+
+ DPRINTK("dentry=%p %.*s",
+ dentry, dentry->d_name.len, dentry->d_name.name);
+
+ /* The daemon never waits. */
+ if (autofs4_oz_mode(sbi) || mounting_here) {
+ if (!d_mountpoint(dentry))
+ return -EISDIR;
+ return 0;
+ }
+
+ /* We need to sleep, so we need pathwalk to be in ref-mode */
+ if (rcu_walk)
+ return -ECHILD;
+
+ /* Wait for pending expires */
+ do_expire_wait(dentry);
+
+ /*
+ * This dentry may be under construction so wait on mount
+ * completion.
+ */
+ return autofs4_mount_wait(dentry);
+}
+
/* Lookups in the root directory */
static struct dentry *autofs4_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
{
struct autofs_sb_info *sbi;
struct autofs_info *ino;
- struct dentry *expiring, *active;
- int oz_mode;
+ struct dentry *active;
- DPRINTK("name = %.*s",
- dentry->d_name.len, dentry->d_name.name);
+ DPRINTK("name = %.*s", dentry->d_name.len, dentry->d_name.name);
/* File name too long to exist */
if (dentry->d_name.len > NAME_MAX)
return ERR_PTR(-ENAMETOOLONG);
sbi = autofs4_sbi(dir->i_sb);
- oz_mode = autofs4_oz_mode(sbi);
DPRINTK("pid = %u, pgrp = %u, catatonic = %d, oz_mode = %d",
- current->pid, task_pgrp_nr(current), sbi->catatonic, oz_mode);
+ current->pid, task_pgrp_nr(current), sbi->catatonic,
+ autofs4_oz_mode(sbi));
active = autofs4_lookup_active(dentry);
if (active) {
- dentry = active;
- ino = autofs4_dentry_ino(dentry);
+ return active;
} else {
/*
- * Mark the dentry incomplete but don't hash it. We do this
- * to serialize our inode creation operations (symlink and
- * mkdir) which prevents deadlock during the callback to
- * the daemon. Subsequent user space lookups for the same
- * dentry are placed on the wait queue while the daemon
- * itself is allowed passage unresticted so the create
- * operation itself can then hash the dentry. Finally,
- * we check for the hashed dentry and return the newly
- * hashed dentry.
+ * A dentry that is not within the root can never trigger a
+ * mount operation, unless the directory already exists, so we
+ * can return fail immediately. The daemon however does need
+ * to create directories within the file system.
*/
- d_set_d_op(dentry, &autofs4_root_dentry_operations);
+ if (!autofs4_oz_mode(sbi) && !IS_ROOT(dentry->d_parent))
+ return ERR_PTR(-ENOENT);
- /*
- * And we need to ensure that the same dentry is used for
- * all following lookup calls until it is hashed so that
- * the dentry flags are persistent throughout the request.
- */
- ino = autofs4_init_ino(NULL, sbi, 0555);
+ /* Mark entries in the root as mount triggers */
+ if (autofs_type_indirect(sbi->type) && IS_ROOT(dentry->d_parent))
+ __managed_dentry_set_managed(dentry);
+
+ ino = autofs4_new_ino(sbi);
if (!ino)
return ERR_PTR(-ENOMEM);
@@ -596,82 +521,6 @@ static struct dentry *autofs4_lookup(struct inode *dir, struct dentry *dentry, s
d_instantiate(dentry, NULL);
}
-
- if (!oz_mode) {
- mutex_unlock(&dir->i_mutex);
- expiring = autofs4_lookup_expiring(dentry);
- if (expiring) {
- /*
- * If we are racing with expire the request might not
- * be quite complete but the directory has been removed
- * so it must have been successful, so just wait for it.
- */
- autofs4_expire_wait(expiring);
- autofs4_del_expiring(expiring);
- dput(expiring);
- }
-
- spin_lock(&sbi->fs_lock);
- ino->flags |= AUTOFS_INF_PENDING;
- spin_unlock(&sbi->fs_lock);
- if (dentry->d_op && dentry->d_op->d_revalidate)
- (dentry->d_op->d_revalidate)(dentry, nd);
- mutex_lock(&dir->i_mutex);
- }
-
- /*
- * If we are still pending, check if we had to handle
- * a signal. If so we can force a restart..
- */
- if (ino->flags & AUTOFS_INF_PENDING) {
- /* See if we were interrupted */
- if (signal_pending(current)) {
- sigset_t *sigset = &current->pending.signal;
- if (sigismember (sigset, SIGKILL) ||
- sigismember (sigset, SIGQUIT) ||
- sigismember (sigset, SIGINT)) {
- if (active)
- dput(active);
- return ERR_PTR(-ERESTARTNOINTR);
- }
- }
- if (!oz_mode) {
- spin_lock(&sbi->fs_lock);
- ino->flags &= ~AUTOFS_INF_PENDING;
- spin_unlock(&sbi->fs_lock);
- }
- }
-
- /*
- * If this dentry is unhashed, then we shouldn't honour this
- * lookup. Returning ENOENT here doesn't do the right thing
- * for all system calls, but it should be OK for the operations
- * we permit from an autofs.
- */
- if (!oz_mode && d_unhashed(dentry)) {
- /*
- * A user space application can (and has done in the past)
- * remove and re-create this directory during the callback.
- * This can leave us with an unhashed dentry, but a
- * successful mount! So we need to perform another
- * cached lookup in case the dentry now exists.
- */
- struct dentry *parent = dentry->d_parent;
- struct dentry *new = d_lookup(parent, &dentry->d_name);
- if (new != NULL)
- dentry = new;
- else
- dentry = ERR_PTR(-ENOENT);
-
- if (active)
- dput(active);
-
- return dentry;
- }
-
- if (active)
- return active;
-
return NULL;
}
@@ -683,6 +532,7 @@ static int autofs4_dir_symlink(struct inode *dir,
struct autofs_info *ino = autofs4_dentry_ino(dentry);
struct autofs_info *p_ino;
struct inode *inode;
+ size_t size = strlen(symname);
char *cp;
DPRINTK("%s <- %.*s", symname,
@@ -691,45 +541,35 @@ static int autofs4_dir_symlink(struct inode *dir,
if (!autofs4_oz_mode(sbi))
return -EACCES;
- ino = autofs4_init_ino(ino, sbi, S_IFLNK | 0555);
- if (!ino)
- return -ENOMEM;
+ BUG_ON(!ino);
+
+ autofs4_clean_ino(ino);
autofs4_del_active(dentry);
- ino->size = strlen(symname);
- cp = kmalloc(ino->size + 1, GFP_KERNEL);
- if (!cp) {
- if (!dentry->d_fsdata)
- kfree(ino);
+ cp = kmalloc(size + 1, GFP_KERNEL);
+ if (!cp)
return -ENOMEM;
- }
strcpy(cp, symname);
- inode = autofs4_get_inode(dir->i_sb, ino);
+ inode = autofs4_get_inode(dir->i_sb, S_IFLNK | 0555);
if (!inode) {
kfree(cp);
if (!dentry->d_fsdata)
kfree(ino);
return -ENOMEM;
}
+ inode->i_private = cp;
+ inode->i_size = size;
d_add(dentry, inode);
- if (dir == dir->i_sb->s_root->d_inode)
- d_set_d_op(dentry, &autofs4_root_dentry_operations);
- else
- d_set_d_op(dentry, &autofs4_dentry_operations);
-
- dentry->d_fsdata = ino;
- ino->dentry = dget(dentry);
+ dget(dentry);
atomic_inc(&ino->count);
p_ino = autofs4_dentry_ino(dentry->d_parent);
if (p_ino && dentry->d_parent != dentry)
atomic_inc(&p_ino->count);
- ino->inode = inode;
- ino->u.symlink = cp;
dir->i_mtime = CURRENT_TIME;
return 0;
@@ -782,6 +622,58 @@ static int autofs4_dir_unlink(struct inode *dir, struct dentry *dentry)
return 0;
}
+/*
+ * Version 4 of autofs provides a pseudo direct mount implementation
+ * that relies on directories at the leaves of a directory tree under
+ * an indirect mount to trigger mounts. To allow for this we need to
+ * set the DMANAGED_AUTOMOUNT and DMANAGED_TRANSIT flags on the leaves
+ * of the directory tree. There is no need to clear the automount flag
+ * following a mount or restore it after an expire because these mounts
+ * are always covered. However, it is neccessary to ensure that these
+ * flags are clear on non-empty directories to avoid unnecessary calls
+ * during path walks.
+ */
+static void autofs_set_leaf_automount_flags(struct dentry *dentry)
+{
+ struct dentry *parent;
+
+ /* root and dentrys in the root are already handled */
+ if (IS_ROOT(dentry->d_parent))
+ return;
+
+ managed_dentry_set_managed(dentry);
+
+ parent = dentry->d_parent;
+ /* only consider parents below dentrys in the root */
+ if (IS_ROOT(parent->d_parent))
+ return;
+ managed_dentry_clear_managed(parent);
+ return;
+}
+
+static void autofs_clear_leaf_automount_flags(struct dentry *dentry)
+{
+ struct list_head *d_child;
+ struct dentry *parent;
+
+ /* flags for dentrys in the root are handled elsewhere */
+ if (IS_ROOT(dentry->d_parent))
+ return;
+
+ managed_dentry_clear_managed(dentry);
+
+ parent = dentry->d_parent;
+ /* only consider parents below dentrys in the root */
+ if (IS_ROOT(parent->d_parent))
+ return;
+ d_child = &dentry->d_u.d_child;
+ /* Set parent managed if it's becoming empty */
+ if (d_child->next == &parent->d_subdirs &&
+ d_child->prev == &parent->d_subdirs)
+ managed_dentry_set_managed(parent);
+ return;
+}
+
static int autofs4_dir_rmdir(struct inode *dir, struct dentry *dentry)
{
struct autofs_sb_info *sbi = autofs4_sbi(dir->i_sb);
@@ -809,6 +701,9 @@ static int autofs4_dir_rmdir(struct inode *dir, struct dentry *dentry)
spin_unlock(&dentry->d_lock);
spin_unlock(&autofs4_lock);
+ if (sbi->version < 5)
+ autofs_clear_leaf_automount_flags(dentry);
+
if (atomic_dec_and_test(&ino->count)) {
p_ino = autofs4_dentry_ino(dentry->d_parent);
if (p_ino && dentry->d_parent != dentry)
@@ -837,32 +732,25 @@ static int autofs4_dir_mkdir(struct inode *dir, struct dentry *dentry, int mode)
DPRINTK("dentry %p, creating %.*s",
dentry, dentry->d_name.len, dentry->d_name.name);
- ino = autofs4_init_ino(ino, sbi, S_IFDIR | 0555);
- if (!ino)
- return -ENOMEM;
+ BUG_ON(!ino);
+
+ autofs4_clean_ino(ino);
autofs4_del_active(dentry);
- inode = autofs4_get_inode(dir->i_sb, ino);
- if (!inode) {
- if (!dentry->d_fsdata)
- kfree(ino);
+ inode = autofs4_get_inode(dir->i_sb, S_IFDIR | 0555);
+ if (!inode)
return -ENOMEM;
- }
d_add(dentry, inode);
- if (dir == dir->i_sb->s_root->d_inode)
- d_set_d_op(dentry, &autofs4_root_dentry_operations);
- else
- d_set_d_op(dentry, &autofs4_dentry_operations);
+ if (sbi->version < 5)
+ autofs_set_leaf_automount_flags(dentry);
- dentry->d_fsdata = ino;
- ino->dentry = dget(dentry);
+ dget(dentry);
atomic_inc(&ino->count);
p_ino = autofs4_dentry_ino(dentry->d_parent);
if (p_ino && dentry->d_parent != dentry)
atomic_inc(&p_ino->count);
- ino->inode = inode;
inc_nlink(dir);
dir->i_mtime = CURRENT_TIME;
@@ -944,8 +832,7 @@ static inline int autofs4_ask_umount(struct vfsmount *mnt, int __user *p)
int is_autofs4_dentry(struct dentry *dentry)
{
return dentry && dentry->d_inode &&
- (dentry->d_op == &autofs4_root_dentry_operations ||
- dentry->d_op == &autofs4_dentry_operations) &&
+ dentry->d_op == &autofs4_dentry_operations &&
dentry->d_fsdata != NULL;
}
diff --git a/fs/autofs4/symlink.c b/fs/autofs4/symlink.c
index b4ea829..f27c094 100644
--- a/fs/autofs4/symlink.c
+++ b/fs/autofs4/symlink.c
@@ -14,8 +14,7 @@
static void *autofs4_follow_link(struct dentry *dentry, struct nameidata *nd)
{
- struct autofs_info *ino = autofs4_dentry_ino(dentry);
- nd_set_link(nd, (char *)ino->u.symlink);
+ nd_set_link(nd, dentry->d_inode->i_private);
return NULL;
}
diff --git a/fs/autofs4/waitq.c b/fs/autofs4/waitq.c
index c5f8459..5601005 100644
--- a/fs/autofs4/waitq.c
+++ b/fs/autofs4/waitq.c
@@ -309,6 +309,9 @@ static int validate_request(struct autofs_wait_queue **wait,
* completed while we waited on the mutex ...
*/
if (notify == NFY_MOUNT) {
+ struct dentry *new = NULL;
+ int valid = 1;
+
/*
* If the dentry was successfully mounted while we slept
* on the wait queue mutex we can return success. If it
@@ -316,8 +319,20 @@ static int validate_request(struct autofs_wait_queue **wait,
* a multi-mount with no mount at it's base) we can
* continue on and create a new request.
*/
+ if (!IS_ROOT(dentry)) {
+ if (dentry->d_inode && d_unhashed(dentry)) {
+ struct dentry *parent = dentry->d_parent;
+ new = d_lookup(parent, &dentry->d_name);
+ if (new)
+ dentry = new;
+ }
+ }
if (have_submounts(dentry))
- return 0;
+ valid = 0;
+
+ if (new)
+ dput(new);
+ return valid;
}
return 1;
diff --git a/fs/block_dev.c b/fs/block_dev.c
index fe3f59c1..333a7bb 100644
--- a/fs/block_dev.c
+++ b/fs/block_dev.c
@@ -432,6 +432,9 @@ static void init_once(void *foo)
mutex_init(&bdev->bd_mutex);
INIT_LIST_HEAD(&bdev->bd_inodes);
INIT_LIST_HEAD(&bdev->bd_list);
+#ifdef CONFIG_SYSFS
+ INIT_LIST_HEAD(&bdev->bd_holder_disks);
+#endif
inode_init_once(&ei->vfs_inode);
/* Initialize mutex for freeze. */
mutex_init(&bdev->bd_fsfreeze_mutex);
@@ -779,6 +782,23 @@ static struct block_device *bd_start_claiming(struct block_device *bdev,
}
#ifdef CONFIG_SYSFS
+struct bd_holder_disk {
+ struct list_head list;
+ struct gendisk *disk;
+ int refcnt;
+};
+
+static struct bd_holder_disk *bd_find_holder_disk(struct block_device *bdev,
+ struct gendisk *disk)
+{
+ struct bd_holder_disk *holder;
+
+ list_for_each_entry(holder, &bdev->bd_holder_disks, list)
+ if (holder->disk == disk)
+ return holder;
+ return NULL;
+}
+
static int add_symlink(struct kobject *from, struct kobject *to)
{
return sysfs_create_link(from, to, kobject_name(to));
@@ -794,6 +814,8 @@ static void del_symlink(struct kobject *from, struct kobject *to)
* @bdev: the claimed slave bdev
* @disk: the holding disk
*
+ * DON'T USE THIS UNLESS YOU'RE ALREADY USING IT.
+ *
* This functions creates the following sysfs symlinks.
*
* - from "slaves" directory of the holder @disk to the claimed @bdev
@@ -817,47 +839,83 @@ static void del_symlink(struct kobject *from, struct kobject *to)
*/
int bd_link_disk_holder(struct block_device *bdev, struct gendisk *disk)
{
+ struct bd_holder_disk *holder;
int ret = 0;
mutex_lock(&bdev->bd_mutex);
- WARN_ON_ONCE(!bdev->bd_holder || bdev->bd_holder_disk);
+ WARN_ON_ONCE(!bdev->bd_holder);
/* FIXME: remove the following once add_disk() handles errors */
if (WARN_ON(!disk->slave_dir || !bdev->bd_part->holder_dir))
goto out_unlock;
- ret = add_symlink(disk->slave_dir, &part_to_dev(bdev->bd_part)->kobj);
- if (ret)
+ holder = bd_find_holder_disk(bdev, disk);
+ if (holder) {
+ holder->refcnt++;
goto out_unlock;
+ }
- ret = add_symlink(bdev->bd_part->holder_dir, &disk_to_dev(disk)->kobj);
- if (ret) {
- del_symlink(disk->slave_dir, &part_to_dev(bdev->bd_part)->kobj);
+ holder = kzalloc(sizeof(*holder), GFP_KERNEL);
+ if (!holder) {
+ ret = -ENOMEM;
goto out_unlock;
}
- bdev->bd_holder_disk = disk;
+ INIT_LIST_HEAD(&holder->list);
+ holder->disk = disk;
+ holder->refcnt = 1;
+
+ ret = add_symlink(disk->slave_dir, &part_to_dev(bdev->bd_part)->kobj);
+ if (ret)
+ goto out_free;
+
+ ret = add_symlink(bdev->bd_part->holder_dir, &disk_to_dev(disk)->kobj);
+ if (ret)
+ goto out_del;
+
+ list_add(&holder->list, &bdev->bd_holder_disks);
+ goto out_unlock;
+
+out_del:
+ del_symlink(disk->slave_dir, &part_to_dev(bdev->bd_part)->kobj);
+out_free:
+ kfree(holder);
out_unlock:
mutex_unlock(&bdev->bd_mutex);
return ret;
}
EXPORT_SYMBOL_GPL(bd_link_disk_holder);
-static void bd_unlink_disk_holder(struct block_device *bdev)
+/**
+ * bd_unlink_disk_holder - destroy symlinks created by bd_link_disk_holder()
+ * @bdev: the calimed slave bdev
+ * @disk: the holding disk
+ *
+ * DON'T USE THIS UNLESS YOU'RE ALREADY USING IT.
+ *
+ * CONTEXT:
+ * Might sleep.
+ */
+void bd_unlink_disk_holder(struct block_device *bdev, struct gendisk *disk)
{
- struct gendisk *disk = bdev->bd_holder_disk;
+ struct bd_holder_disk *holder;
- bdev->bd_holder_disk = NULL;
- if (!disk)
- return;
+ mutex_lock(&bdev->bd_mutex);
- del_symlink(disk->slave_dir, &part_to_dev(bdev->bd_part)->kobj);
- del_symlink(bdev->bd_part->holder_dir, &disk_to_dev(disk)->kobj);
+ holder = bd_find_holder_disk(bdev, disk);
+
+ if (!WARN_ON_ONCE(holder == NULL) && !--holder->refcnt) {
+ del_symlink(disk->slave_dir, &part_to_dev(bdev->bd_part)->kobj);
+ del_symlink(bdev->bd_part->holder_dir,
+ &disk_to_dev(disk)->kobj);
+ list_del_init(&holder->list);
+ kfree(holder);
+ }
+
+ mutex_unlock(&bdev->bd_mutex);
}
-#else
-static inline void bd_unlink_disk_holder(struct block_device *bdev)
-{ }
+EXPORT_SYMBOL_GPL(bd_unlink_disk_holder);
#endif
/**
@@ -1380,7 +1438,6 @@ int blkdev_put(struct block_device *bdev, fmode_t mode)
* unblock evpoll if it was a write holder.
*/
if (bdev_free) {
- bd_unlink_disk_holder(bdev);
if (bdev->bd_write_holder) {
disk_unblock_events(bdev->bd_disk);
bdev->bd_write_holder = false;
diff --git a/fs/btrfs/Kconfig b/fs/btrfs/Kconfig
index 7bb3c02..ecb9fd3 100644
--- a/fs/btrfs/Kconfig
+++ b/fs/btrfs/Kconfig
@@ -4,6 +4,8 @@ config BTRFS_FS
select LIBCRC32C
select ZLIB_INFLATE
select ZLIB_DEFLATE
+ select LZO_COMPRESS
+ select LZO_DECOMPRESS
help
Btrfs is a new filesystem with extents, writable snapshotting,
support for multiple devices and many more features.
diff --git a/fs/btrfs/Makefile b/fs/btrfs/Makefile
index a35eb36..31610ea 100644
--- a/fs/btrfs/Makefile
+++ b/fs/btrfs/Makefile
@@ -6,5 +6,5 @@ btrfs-y += super.o ctree.o extent-tree.o print-tree.o root-tree.o dir-item.o \
transaction.o inode.o file.o tree-defrag.o \
extent_map.o sysfs.o struct-funcs.o xattr.o ordered-data.o \
extent_io.o volumes.o async-thread.o ioctl.o locking.o orphan.o \
- export.o tree-log.o acl.o free-space-cache.o zlib.o \
+ export.o tree-log.o acl.o free-space-cache.o zlib.o lzo.o \
compression.o delayed-ref.o relocation.o
diff --git a/fs/btrfs/acl.c b/fs/btrfs/acl.c
index 6ae2c8c..15b5ca2 100644
--- a/fs/btrfs/acl.c
+++ b/fs/btrfs/acl.c
@@ -60,8 +60,10 @@ static struct posix_acl *btrfs_get_acl(struct inode *inode, int type)
size = __btrfs_getxattr(inode, name, value, size);
if (size > 0) {
acl = posix_acl_from_xattr(value, size);
- if (IS_ERR(acl))
+ if (IS_ERR(acl)) {
+ kfree(value);
return acl;
+ }
set_cached_acl(inode, type, acl);
}
kfree(value);
diff --git a/fs/btrfs/btrfs_inode.h b/fs/btrfs/btrfs_inode.h
index 6ad63f1..ccc991c 100644
--- a/fs/btrfs/btrfs_inode.h
+++ b/fs/btrfs/btrfs_inode.h
@@ -157,7 +157,7 @@ struct btrfs_inode {
/*
* always compress this one file
*/
- unsigned force_compress:1;
+ unsigned force_compress:4;
struct inode vfs_inode;
};
diff --git a/fs/btrfs/compression.c b/fs/btrfs/compression.c
index b50bc4b..f745287 100644
--- a/fs/btrfs/compression.c
+++ b/fs/btrfs/compression.c
@@ -62,6 +62,9 @@ struct compressed_bio {
/* number of bytes on disk */
unsigned long compressed_len;
+ /* the compression algorithm for this bio */
+ int compress_type;
+
/* number of compressed pages in the array */
unsigned long nr_pages;
@@ -173,11 +176,12 @@ static void end_compressed_bio_read(struct bio *bio, int err)
/* ok, we're the last bio for this extent, lets start
* the decompression.
*/
- ret = btrfs_zlib_decompress_biovec(cb->compressed_pages,
- cb->start,
- cb->orig_bio->bi_io_vec,
- cb->orig_bio->bi_vcnt,
- cb->compressed_len);
+ ret = btrfs_decompress_biovec(cb->compress_type,
+ cb->compressed_pages,
+ cb->start,
+ cb->orig_bio->bi_io_vec,
+ cb->orig_bio->bi_vcnt,
+ cb->compressed_len);
csum_failed:
if (ret)
cb->errors = 1;
@@ -588,6 +592,7 @@ int btrfs_submit_compressed_read(struct inode *inode, struct bio *bio,
cb->len = uncompressed_len;
cb->compressed_len = compressed_len;
+ cb->compress_type = extent_compress_type(bio_flags);
cb->orig_bio = bio;
nr_pages = (compressed_len + PAGE_CACHE_SIZE - 1) /
@@ -677,3 +682,317 @@ int btrfs_submit_compressed_read(struct inode *inode, struct bio *bio,
bio_put(comp_bio);
return 0;
}
+
+static struct list_head comp_idle_workspace[BTRFS_COMPRESS_TYPES];
+static spinlock_t comp_workspace_lock[BTRFS_COMPRESS_TYPES];
+static int comp_num_workspace[BTRFS_COMPRESS_TYPES];
+static atomic_t comp_alloc_workspace[BTRFS_COMPRESS_TYPES];
+static wait_queue_head_t comp_workspace_wait[BTRFS_COMPRESS_TYPES];
+
+struct btrfs_compress_op *btrfs_compress_op[] = {
+ &btrfs_zlib_compress,
+ &btrfs_lzo_compress,
+};
+
+int __init btrfs_init_compress(void)
+{
+ int i;
+
+ for (i = 0; i < BTRFS_COMPRESS_TYPES; i++) {
+ INIT_LIST_HEAD(&comp_idle_workspace[i]);
+ spin_lock_init(&comp_workspace_lock[i]);
+ atomic_set(&comp_alloc_workspace[i], 0);
+ init_waitqueue_head(&comp_workspace_wait[i]);
+ }
+ return 0;
+}
+
+/*
+ * this finds an available workspace or allocates a new one
+ * ERR_PTR is returned if things go bad.
+ */
+static struct list_head *find_workspace(int type)
+{
+ struct list_head *workspace;
+ int cpus = num_online_cpus();
+ int idx = type - 1;
+
+ struct list_head *idle_workspace = &comp_idle_workspace[idx];
+ spinlock_t *workspace_lock = &comp_workspace_lock[idx];
+ atomic_t *alloc_workspace = &comp_alloc_workspace[idx];
+ wait_queue_head_t *workspace_wait = &comp_workspace_wait[idx];
+ int *num_workspace = &comp_num_workspace[idx];
+again:
+ spin_lock(workspace_lock);
+ if (!list_empty(idle_workspace)) {
+ workspace = idle_workspace->next;
+ list_del(workspace);
+ (*num_workspace)--;
+ spin_unlock(workspace_lock);
+ return workspace;
+
+ }
+ if (atomic_read(alloc_workspace) > cpus) {
+ DEFINE_WAIT(wait);
+
+ spin_unlock(workspace_lock);
+ prepare_to_wait(workspace_wait, &wait, TASK_UNINTERRUPTIBLE);
+ if (atomic_read(alloc_workspace) > cpus && !*num_workspace)
+ schedule();
+ finish_wait(workspace_wait, &wait);
+ goto again;
+ }
+ atomic_inc(alloc_workspace);
+ spin_unlock(workspace_lock);
+
+ workspace = btrfs_compress_op[idx]->alloc_workspace();
+ if (IS_ERR(workspace)) {
+ atomic_dec(alloc_workspace);
+ wake_up(workspace_wait);
+ }
+ return workspace;
+}
+
+/*
+ * put a workspace struct back on the list or free it if we have enough
+ * idle ones sitting around
+ */
+static void free_workspace(int type, struct list_head *workspace)
+{
+ int idx = type - 1;
+ struct list_head *idle_workspace = &comp_idle_workspace[idx];
+ spinlock_t *workspace_lock = &comp_workspace_lock[idx];
+ atomic_t *alloc_workspace = &comp_alloc_workspace[idx];
+ wait_queue_head_t *workspace_wait = &comp_workspace_wait[idx];
+ int *num_workspace = &comp_num_workspace[idx];
+
+ spin_lock(workspace_lock);
+ if (*num_workspace < num_online_cpus()) {
+ list_add_tail(workspace, idle_workspace);
+ (*num_workspace)++;
+ spin_unlock(workspace_lock);
+ goto wake;
+ }
+ spin_unlock(workspace_lock);
+
+ btrfs_compress_op[idx]->free_workspace(workspace);
+ atomic_dec(alloc_workspace);
+wake:
+ if (waitqueue_active(workspace_wait))
+ wake_up(workspace_wait);
+}
+
+/*
+ * cleanup function for module exit
+ */
+static void free_workspaces(void)
+{
+ struct list_head *workspace;
+ int i;
+
+ for (i = 0; i < BTRFS_COMPRESS_TYPES; i++) {
+ while (!list_empty(&comp_idle_workspace[i])) {
+ workspace = comp_idle_workspace[i].next;
+ list_del(workspace);
+ btrfs_compress_op[i]->free_workspace(workspace);
+ atomic_dec(&comp_alloc_workspace[i]);
+ }
+ }
+}
+
+/*
+ * given an address space and start/len, compress the bytes.
+ *
+ * pages are allocated to hold the compressed result and stored
+ * in 'pages'
+ *
+ * out_pages is used to return the number of pages allocated. There
+ * may be pages allocated even if we return an error
+ *
+ * total_in is used to return the number of bytes actually read. It
+ * may be smaller then len if we had to exit early because we
+ * ran out of room in the pages array or because we cross the
+ * max_out threshold.
+ *
+ * total_out is used to return the total number of compressed bytes
+ *
+ * max_out tells us the max number of bytes that we're allowed to
+ * stuff into pages
+ */
+int btrfs_compress_pages(int type, struct address_space *mapping,
+ u64 start, unsigned long len,
+ struct page **pages,
+ unsigned long nr_dest_pages,
+ unsigned long *out_pages,
+ unsigned long *total_in,
+ unsigned long *total_out,
+ unsigned long max_out)
+{
+ struct list_head *workspace;
+ int ret;
+
+ workspace = find_workspace(type);
+ if (IS_ERR(workspace))
+ return -1;
+
+ ret = btrfs_compress_op[type-1]->compress_pages(workspace, mapping,
+ start, len, pages,
+ nr_dest_pages, out_pages,
+ total_in, total_out,
+ max_out);
+ free_workspace(type, workspace);
+ return ret;
+}
+
+/*
+ * pages_in is an array of pages with compressed data.
+ *
+ * disk_start is the starting logical offset of this array in the file
+ *
+ * bvec is a bio_vec of pages from the file that we want to decompress into
+ *
+ * vcnt is the count of pages in the biovec
+ *
+ * srclen is the number of bytes in pages_in
+ *
+ * The basic idea is that we have a bio that was created by readpages.
+ * The pages in the bio are for the uncompressed data, and they may not
+ * be contiguous. They all correspond to the range of bytes covered by
+ * the compressed extent.
+ */
+int btrfs_decompress_biovec(int type, struct page **pages_in, u64 disk_start,
+ struct bio_vec *bvec, int vcnt, size_t srclen)
+{
+ struct list_head *workspace;
+ int ret;
+
+ workspace = find_workspace(type);
+ if (IS_ERR(workspace))
+ return -ENOMEM;
+
+ ret = btrfs_compress_op[type-1]->decompress_biovec(workspace, pages_in,
+ disk_start,
+ bvec, vcnt, srclen);
+ free_workspace(type, workspace);
+ return ret;
+}
+
+/*
+ * a less complex decompression routine. Our compressed data fits in a
+ * single page, and we want to read a single page out of it.
+ * start_byte tells us the offset into the compressed data we're interested in
+ */
+int btrfs_decompress(int type, unsigned char *data_in, struct page *dest_page,
+ unsigned long start_byte, size_t srclen, size_t destlen)
+{
+ struct list_head *workspace;
+ int ret;
+
+ workspace = find_workspace(type);
+ if (IS_ERR(workspace))
+ return -ENOMEM;
+
+ ret = btrfs_compress_op[type-1]->decompress(workspace, data_in,
+ dest_page, start_byte,
+ srclen, destlen);
+
+ free_workspace(type, workspace);
+ return ret;
+}
+
+void __exit btrfs_exit_compress(void)
+{
+ free_workspaces();
+}
+
+/*
+ * Copy uncompressed data from working buffer to pages.
+ *
+ * buf_start is the byte offset we're of the start of our workspace buffer.
+ *
+ * total_out is the last byte of the buffer
+ */
+int btrfs_decompress_buf2page(char *buf, unsigned long buf_start,
+ unsigned long total_out, u64 disk_start,
+ struct bio_vec *bvec, int vcnt,
+ unsigned long *page_index,
+ unsigned long *pg_offset)
+{
+ unsigned long buf_offset;
+ unsigned long current_buf_start;
+ unsigned long start_byte;
+ unsigned long working_bytes = total_out - buf_start;
+ unsigned long bytes;
+ char *kaddr;
+ struct page *page_out = bvec[*page_index].bv_page;
+
+ /*
+ * start byte is the first byte of the page we're currently
+ * copying into relative to the start of the compressed data.
+ */
+ start_byte = page_offset(page_out) - disk_start;
+
+ /* we haven't yet hit data corresponding to this page */
+ if (total_out <= start_byte)
+ return 1;
+
+ /*
+ * the start of the data we care about is offset into
+ * the middle of our working buffer
+ */
+ if (total_out > start_byte && buf_start < start_byte) {
+ buf_offset = start_byte - buf_start;
+ working_bytes -= buf_offset;
+ } else {
+ buf_offset = 0;
+ }
+ current_buf_start = buf_start;
+
+ /* copy bytes from the working buffer into the pages */
+ while (working_bytes > 0) {
+ bytes = min(PAGE_CACHE_SIZE - *pg_offset,
+ PAGE_CACHE_SIZE - buf_offset);
+ bytes = min(bytes, working_bytes);
+ kaddr = kmap_atomic(page_out, KM_USER0);
+ memcpy(kaddr + *pg_offset, buf + buf_offset, bytes);
+ kunmap_atomic(kaddr, KM_USER0);
+ flush_dcache_page(page_out);
+
+ *pg_offset += bytes;
+ buf_offset += bytes;
+ working_bytes -= bytes;
+ current_buf_start += bytes;
+
+ /* check if we need to pick another page */
+ if (*pg_offset == PAGE_CACHE_SIZE) {
+ (*page_index)++;
+ if (*page_index >= vcnt)
+ return 0;
+
+ page_out = bvec[*page_index].bv_page;
+ *pg_offset = 0;
+ start_byte = page_offset(page_out) - disk_start;
+
+ /*
+ * make sure our new page is covered by this
+ * working buffer
+ */
+ if (total_out <= start_byte)
+ return 1;
+
+ /*
+ * the next page in the biovec might not be adjacent
+ * to the last page, but it might still be found
+ * inside this working buffer. bump our offset pointer
+ */
+ if (total_out > start_byte &&
+ current_buf_start < start_byte) {
+ buf_offset = start_byte - buf_start;
+ working_bytes = total_out - start_byte;
+ current_buf_start = buf_start + buf_offset;
+ }
+ }
+ }
+
+ return 1;
+}
diff --git a/fs/btrfs/compression.h b/fs/btrfs/compression.h
index 421f5b4..5100017 100644
--- a/fs/btrfs/compression.h
+++ b/fs/btrfs/compression.h
@@ -19,24 +19,27 @@
#ifndef __BTRFS_COMPRESSION_
#define __BTRFS_COMPRESSION_
-int btrfs_zlib_decompress(unsigned char *data_in,
- struct page *dest_page,
- unsigned long start_byte,
- size_t srclen, size_t destlen);
-int btrfs_zlib_compress_pages(struct address_space *mapping,
- u64 start, unsigned long len,
- struct page **pages,
- unsigned long nr_dest_pages,
- unsigned long *out_pages,
- unsigned long *total_in,
- unsigned long *total_out,
- unsigned long max_out);
-int btrfs_zlib_decompress_biovec(struct page **pages_in,
- u64 disk_start,
- struct bio_vec *bvec,
- int vcnt,
- size_t srclen);
-void btrfs_zlib_exit(void);
+int btrfs_init_compress(void);
+void btrfs_exit_compress(void);
+
+int btrfs_compress_pages(int type, struct address_space *mapping,
+ u64 start, unsigned long len,
+ struct page **pages,
+ unsigned long nr_dest_pages,
+ unsigned long *out_pages,
+ unsigned long *total_in,
+ unsigned long *total_out,
+ unsigned long max_out);
+int btrfs_decompress_biovec(int type, struct page **pages_in, u64 disk_start,
+ struct bio_vec *bvec, int vcnt, size_t srclen);
+int btrfs_decompress(int type, unsigned char *data_in, struct page *dest_page,
+ unsigned long start_byte, size_t srclen, size_t destlen);
+int btrfs_decompress_buf2page(char *buf, unsigned long buf_start,
+ unsigned long total_out, u64 disk_start,
+ struct bio_vec *bvec, int vcnt,
+ unsigned long *page_index,
+ unsigned long *pg_offset);
+
int btrfs_submit_compressed_write(struct inode *inode, u64 start,
unsigned long len, u64 disk_start,
unsigned long compressed_len,
@@ -44,4 +47,37 @@ int btrfs_submit_compressed_write(struct inode *inode, u64 start,
unsigned long nr_pages);
int btrfs_submit_compressed_read(struct inode *inode, struct bio *bio,
int mirror_num, unsigned long bio_flags);
+
+struct btrfs_compress_op {
+ struct list_head *(*alloc_workspace)(void);
+
+ void (*free_workspace)(struct list_head *workspace);
+
+ int (*compress_pages)(struct list_head *workspace,
+ struct address_space *mapping,
+ u64 start, unsigned long len,
+ struct page **pages,
+ unsigned long nr_dest_pages,
+ unsigned long *out_pages,
+ unsigned long *total_in,
+ unsigned long *total_out,
+ unsigned long max_out);
+
+ int (*decompress_biovec)(struct list_head *workspace,
+ struct page **pages_in,
+ u64 disk_start,
+ struct bio_vec *bvec,
+ int vcnt,
+ size_t srclen);
+
+ int (*decompress)(struct list_head *workspace,
+ unsigned char *data_in,
+ struct page *dest_page,
+ unsigned long start_byte,
+ size_t srclen, size_t destlen);
+};
+
+extern struct btrfs_compress_op btrfs_zlib_compress;
+extern struct btrfs_compress_op btrfs_lzo_compress;
+
#endif
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c
index 9ac1715..b5baff0 100644
--- a/fs/btrfs/ctree.c
+++ b/fs/btrfs/ctree.c
@@ -105,6 +105,8 @@ noinline void btrfs_clear_path_blocking(struct btrfs_path *p,
/* this also releases the path */
void btrfs_free_path(struct btrfs_path *p)
{
+ if (!p)
+ return;
btrfs_release_path(NULL, p);
kmem_cache_free(btrfs_path_cachep, p);
}
@@ -2514,6 +2516,9 @@ static int push_leaf_right(struct btrfs_trans_handle *trans, struct btrfs_root
btrfs_assert_tree_locked(path->nodes[1]);
right = read_node_slot(root, upper, slot + 1);
+ if (right == NULL)
+ return 1;
+
btrfs_tree_lock(right);
btrfs_set_lock_blocking(right);
@@ -2764,6 +2769,9 @@ static int push_leaf_left(struct btrfs_trans_handle *trans, struct btrfs_root
btrfs_assert_tree_locked(path->nodes[1]);
left = read_node_slot(root, path->nodes[1], slot - 1);
+ if (left == NULL)
+ return 1;
+
btrfs_tree_lock(left);
btrfs_set_lock_blocking(left);
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
index a142d20..2c98b3a 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -27,6 +27,7 @@
#include <linux/backing-dev.h>
#include <linux/wait.h>
#include <linux/slab.h>
+#include <linux/kobject.h>
#include <asm/kmap_types.h>
#include "extent_io.h"
#include "extent_map.h"
@@ -294,6 +295,14 @@ static inline unsigned long btrfs_chunk_item_size(int num_stripes)
#define BTRFS_FSID_SIZE 16
#define BTRFS_HEADER_FLAG_WRITTEN (1ULL << 0)
#define BTRFS_HEADER_FLAG_RELOC (1ULL << 1)
+
+/*
+ * File system states
+ */
+
+/* Errors detected */
+#define BTRFS_SUPER_FLAG_ERROR (1ULL << 2)
+
#define BTRFS_SUPER_FLAG_SEEDING (1ULL << 32)
#define BTRFS_SUPER_FLAG_METADUMP (1ULL << 33)
@@ -398,13 +407,15 @@ struct btrfs_super_block {
#define BTRFS_FEATURE_INCOMPAT_MIXED_BACKREF (1ULL << 0)
#define BTRFS_FEATURE_INCOMPAT_DEFAULT_SUBVOL (1ULL << 1)
#define BTRFS_FEATURE_INCOMPAT_MIXED_GROUPS (1ULL << 2)
+#define BTRFS_FEATURE_INCOMPAT_COMPRESS_LZO (1ULL << 3)
#define BTRFS_FEATURE_COMPAT_SUPP 0ULL
#define BTRFS_FEATURE_COMPAT_RO_SUPP 0ULL
#define BTRFS_FEATURE_INCOMPAT_SUPP \
(BTRFS_FEATURE_INCOMPAT_MIXED_BACKREF | \
BTRFS_FEATURE_INCOMPAT_DEFAULT_SUBVOL | \
- BTRFS_FEATURE_INCOMPAT_MIXED_GROUPS)
+ BTRFS_FEATURE_INCOMPAT_MIXED_GROUPS | \
+ BTRFS_FEATURE_INCOMPAT_COMPRESS_LZO)
/*
* A leaf is full of items. offset and size tell us where to find
@@ -551,9 +562,11 @@ struct btrfs_timespec {
} __attribute__ ((__packed__));
enum btrfs_compression_type {
- BTRFS_COMPRESS_NONE = 0,
- BTRFS_COMPRESS_ZLIB = 1,
- BTRFS_COMPRESS_LAST = 2,
+ BTRFS_COMPRESS_NONE = 0,
+ BTRFS_COMPRESS_ZLIB = 1,
+ BTRFS_COMPRESS_LZO = 2,
+ BTRFS_COMPRESS_TYPES = 2,
+ BTRFS_COMPRESS_LAST = 3,
};
struct btrfs_inode_item {
@@ -597,6 +610,8 @@ struct btrfs_dir_item {
u8 type;
} __attribute__ ((__packed__));
+#define BTRFS_ROOT_SUBVOL_RDONLY (1ULL << 0)
+
struct btrfs_root_item {
struct btrfs_inode_item inode;
__le64 generation;
@@ -895,7 +910,8 @@ struct btrfs_fs_info {
*/
u64 last_trans_log_full_commit;
u64 open_ioctl_trans;
- unsigned long mount_opt;
+ unsigned long mount_opt:20;
+ unsigned long compress_type:4;
u64 max_inline;
u64 alloc_start;
struct btrfs_transaction *running_transaction;
@@ -1050,6 +1066,9 @@ struct btrfs_fs_info {
unsigned metadata_ratio;
void *bdev_holder;
+
+ /* filesystem state */
+ u64 fs_state;
};
/*
@@ -1893,6 +1912,11 @@ BTRFS_SETGET_STACK_FUNCS(root_limit, struct btrfs_root_item, byte_limit, 64);
BTRFS_SETGET_STACK_FUNCS(root_last_snapshot, struct btrfs_root_item,
last_snapshot, 64);
+static inline bool btrfs_root_readonly(struct btrfs_root *root)
+{
+ return root->root_item.flags & BTRFS_ROOT_SUBVOL_RDONLY;
+}
+
/* struct btrfs_super_block */
BTRFS_SETGET_STACK_FUNCS(super_bytenr, struct btrfs_super_block, bytenr, 64);
@@ -2145,6 +2169,7 @@ int btrfs_make_block_group(struct btrfs_trans_handle *trans,
int btrfs_remove_block_group(struct btrfs_trans_handle *trans,
struct btrfs_root *root, u64 group_start);
u64 btrfs_reduce_alloc_profile(struct btrfs_root *root, u64 flags);
+u64 btrfs_get_alloc_profile(struct btrfs_root *root, int data);
void btrfs_set_inode_space_info(struct btrfs_root *root, struct inode *ionde);
void btrfs_clear_space_info_full(struct btrfs_fs_info *info);
int btrfs_check_data_free_space(struct inode *inode, u64 bytes);
@@ -2188,6 +2213,12 @@ int btrfs_set_block_group_ro(struct btrfs_root *root,
int btrfs_set_block_group_rw(struct btrfs_root *root,
struct btrfs_block_group_cache *cache);
void btrfs_put_block_group_cache(struct btrfs_fs_info *info);
+u64 btrfs_account_ro_block_groups_free_space(struct btrfs_space_info *sinfo);
+int btrfs_error_unpin_extent_range(struct btrfs_root *root,
+ u64 start, u64 end);
+int btrfs_error_discard_extent(struct btrfs_root *root, u64 bytenr,
+ u64 num_bytes);
+
/* ctree.c */
int btrfs_bin_search(struct extent_buffer *eb, struct btrfs_key *key,
int level, int *slot);
@@ -2541,6 +2572,14 @@ ssize_t btrfs_listxattr(struct dentry *dentry, char *buffer, size_t size);
/* super.c */
int btrfs_parse_options(struct btrfs_root *root, char *options);
int btrfs_sync_fs(struct super_block *sb, int wait);
+void __btrfs_std_error(struct btrfs_fs_info *fs_info, const char *function,
+ unsigned int line, int errno);
+
+#define btrfs_std_error(fs_info, errno) \
+do { \
+ if ((errno)) \
+ __btrfs_std_error((fs_info), __func__, __LINE__, (errno));\
+} while (0)
/* acl.c */
#ifdef CONFIG_BTRFS_FS_POSIX_ACL
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index 51d2e4d..b531c36 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -44,6 +44,20 @@
static struct extent_io_ops btree_extent_io_ops;
static void end_workqueue_fn(struct btrfs_work *work);
static void free_fs_root(struct btrfs_root *root);
+static void btrfs_check_super_valid(struct btrfs_fs_info *fs_info,
+ int read_only);
+static int btrfs_destroy_ordered_operations(struct btrfs_root *root);
+static int btrfs_destroy_ordered_extents(struct btrfs_root *root);
+static int btrfs_destroy_delayed_refs(struct btrfs_transaction *trans,
+ struct btrfs_root *root);
+static int btrfs_destroy_pending_snapshots(struct btrfs_transaction *t);
+static int btrfs_destroy_delalloc_inodes(struct btrfs_root *root);
+static int btrfs_destroy_marked_extents(struct btrfs_root *root,
+ struct extent_io_tree *dirty_pages,
+ int mark);
+static int btrfs_destroy_pinned_extent(struct btrfs_root *root,
+ struct extent_io_tree *pinned_extents);
+static int btrfs_cleanup_transaction(struct btrfs_root *root);
/*
* end_io_wq structs are used to do processing in task context when an IO is
@@ -353,6 +367,10 @@ static int csum_dirty_buffer(struct btrfs_root *root, struct page *page)
WARN_ON(len == 0);
eb = alloc_extent_buffer(tree, start, len, page, GFP_NOFS);
+ if (eb == NULL) {
+ WARN_ON(1);
+ goto out;
+ }
ret = btree_read_extent_buffer_pages(root, eb, start + PAGE_CACHE_SIZE,
btrfs_header_generation(eb));
BUG_ON(ret);
@@ -427,6 +445,10 @@ static int btree_readpage_end_io_hook(struct page *page, u64 start, u64 end,
WARN_ON(len == 0);
eb = alloc_extent_buffer(tree, start, len, page, GFP_NOFS);
+ if (eb == NULL) {
+ ret = -EIO;
+ goto out;
+ }
found_start = btrfs_header_bytenr(eb);
if (found_start != start) {
@@ -1145,6 +1167,7 @@ struct btrfs_root *btrfs_read_fs_root_no_radix(struct btrfs_root *tree_root,
}
btrfs_free_path(path);
if (ret) {
+ kfree(root);
if (ret > 0)
ret = -ENOENT;
return ERR_PTR(ret);
@@ -1713,8 +1736,10 @@ struct btrfs_root *open_ctree(struct super_block *sb,
fs_info, BTRFS_ROOT_TREE_OBJECTID);
bh = btrfs_read_dev_super(fs_devices->latest_bdev);
- if (!bh)
+ if (!bh) {
+ err = -EINVAL;
goto fail_iput;
+ }
memcpy(&fs_info->super_copy, bh->b_data, sizeof(fs_info->super_copy));
memcpy(&fs_info->super_for_commit, &fs_info->super_copy,
@@ -1727,6 +1752,11 @@ struct btrfs_root *open_ctree(struct super_block *sb,
if (!btrfs_super_root(disk_super))
goto fail_iput;
+ /* check FS state, whether FS is broken. */
+ fs_info->fs_state |= btrfs_super_flags(disk_super);
+
+ btrfs_check_super_valid(fs_info, sb->s_flags & MS_RDONLY);
+
ret = btrfs_parse_options(tree_root, options);
if (ret) {
err = ret;
@@ -1744,10 +1774,10 @@ struct btrfs_root *open_ctree(struct super_block *sb,
}
features = btrfs_super_incompat_flags(disk_super);
- if (!(features & BTRFS_FEATURE_INCOMPAT_MIXED_BACKREF)) {
- features |= BTRFS_FEATURE_INCOMPAT_MIXED_BACKREF;
- btrfs_set_super_incompat_flags(disk_super, features);
- }
+ features |= BTRFS_FEATURE_INCOMPAT_MIXED_BACKREF;
+ if (tree_root->fs_info->compress_type & BTRFS_COMPRESS_LZO)
+ features |= BTRFS_FEATURE_INCOMPAT_COMPRESS_LZO;
+ btrfs_set_super_incompat_flags(disk_super, features);
features = btrfs_super_compat_ro_flags(disk_super) &
~BTRFS_FEATURE_COMPAT_RO_SUPP;
@@ -1957,7 +1987,9 @@ struct btrfs_root *open_ctree(struct super_block *sb,
btrfs_set_opt(fs_info->mount_opt, SSD);
}
- if (btrfs_super_log_root(disk_super) != 0) {
+ /* do not make disk changes in broken FS */
+ if (btrfs_super_log_root(disk_super) != 0 &&
+ !(fs_info->fs_state & BTRFS_SUPER_FLAG_ERROR)) {
u64 bytenr = btrfs_super_log_root(disk_super);
if (fs_devices->rw_devices == 0) {
@@ -2442,8 +2474,28 @@ int close_ctree(struct btrfs_root *root)
smp_mb();
btrfs_put_block_group_cache(fs_info);
+
+ /*
+ * Here come 2 situations when btrfs is broken to flip readonly:
+ *
+ * 1. when btrfs flips readonly somewhere else before
+ * btrfs_commit_super, sb->s_flags has MS_RDONLY flag,
+ * and btrfs will skip to write sb directly to keep
+ * ERROR state on disk.
+ *
+ * 2. when btrfs flips readonly just in btrfs_commit_super,
+ * and in such case, btrfs cannnot write sb via btrfs_commit_super,
+ * and since fs_state has been set BTRFS_SUPER_FLAG_ERROR flag,
+ * btrfs will cleanup all FS resources first and write sb then.
+ */
if (!(fs_info->sb->s_flags & MS_RDONLY)) {
- ret = btrfs_commit_super(root);
+ ret = btrfs_commit_super(root);
+ if (ret)
+ printk(KERN_ERR "btrfs: commit super ret %d\n", ret);
+ }
+
+ if (fs_info->fs_state & BTRFS_SUPER_FLAG_ERROR) {
+ ret = btrfs_error_commit_super(root);
if (ret)
printk(KERN_ERR "btrfs: commit super ret %d\n", ret);
}
@@ -2619,6 +2671,352 @@ out:
return 0;
}
+static void btrfs_check_super_valid(struct btrfs_fs_info *fs_info,
+ int read_only)
+{
+ if (read_only)
+ return;
+
+ if (fs_info->fs_state & BTRFS_SUPER_FLAG_ERROR)
+ printk(KERN_WARNING "warning: mount fs with errors, "
+ "running btrfsck is recommended\n");
+}
+
+int btrfs_error_commit_super(struct btrfs_root *root)
+{
+ int ret;
+
+ mutex_lock(&root->fs_info->cleaner_mutex);
+ btrfs_run_delayed_iputs(root);
+ mutex_unlock(&root->fs_info->cleaner_mutex);
+
+ down_write(&root->fs_info->cleanup_work_sem);
+ up_write(&root->fs_info->cleanup_work_sem);
+
+ /* cleanup FS via transaction */
+ btrfs_cleanup_transaction(root);
+
+ ret = write_ctree_super(NULL, root, 0);
+
+ return ret;
+}
+
+static int btrfs_destroy_ordered_operations(struct btrfs_root *root)
+{
+ struct btrfs_inode *btrfs_inode;
+ struct list_head splice;
+
+ INIT_LIST_HEAD(&splice);
+
+ mutex_lock(&root->fs_info->ordered_operations_mutex);
+ spin_lock(&root->fs_info->ordered_extent_lock);
+
+ list_splice_init(&root->fs_info->ordered_operations, &splice);
+ while (!list_empty(&splice)) {
+ btrfs_inode = list_entry(splice.next, struct btrfs_inode,
+ ordered_operations);
+
+ list_del_init(&btrfs_inode->ordered_operations);
+
+ btrfs_invalidate_inodes(btrfs_inode->root);
+ }
+
+ spin_unlock(&root->fs_info->ordered_extent_lock);
+ mutex_unlock(&root->fs_info->ordered_operations_mutex);
+
+ return 0;
+}
+
+static int btrfs_destroy_ordered_extents(struct btrfs_root *root)
+{
+ struct list_head splice;
+ struct btrfs_ordered_extent *ordered;
+ struct inode *inode;
+
+ INIT_LIST_HEAD(&splice);
+
+ spin_lock(&root->fs_info->ordered_extent_lock);
+
+ list_splice_init(&root->fs_info->ordered_extents, &splice);
+ while (!list_empty(&splice)) {
+ ordered = list_entry(splice.next, struct btrfs_ordered_extent,
+ root_extent_list);
+
+ list_del_init(&ordered->root_extent_list);
+ atomic_inc(&ordered->refs);
+
+ /* the inode may be getting freed (in sys_unlink path). */
+ inode = igrab(ordered->inode);
+
+ spin_unlock(&root->fs_info->ordered_extent_lock);
+ if (inode)
+ iput(inode);
+
+ atomic_set(&ordered->refs, 1);
+ btrfs_put_ordered_extent(ordered);
+
+ spin_lock(&root->fs_info->ordered_extent_lock);
+ }
+
+ spin_unlock(&root->fs_info->ordered_extent_lock);
+
+ return 0;
+}
+
+static int btrfs_destroy_delayed_refs(struct btrfs_transaction *trans,
+ struct btrfs_root *root)
+{
+ struct rb_node *node;
+ struct btrfs_delayed_ref_root *delayed_refs;
+ struct btrfs_delayed_ref_node *ref;
+ int ret = 0;
+
+ delayed_refs = &trans->delayed_refs;
+
+ spin_lock(&delayed_refs->lock);
+ if (delayed_refs->num_entries == 0) {
+ printk(KERN_INFO "delayed_refs has NO entry\n");
+ return ret;
+ }
+
+ node = rb_first(&delayed_refs->root);
+ while (node) {
+ ref = rb_entry(node, struct btrfs_delayed_ref_node, rb_node);
+ node = rb_next(node);
+
+ ref->in_tree = 0;
+ rb_erase(&ref->rb_node, &delayed_refs->root);
+ delayed_refs->num_entries--;
+
+ atomic_set(&ref->refs, 1);
+ if (btrfs_delayed_ref_is_head(ref)) {
+ struct btrfs_delayed_ref_head *head;
+
+ head = btrfs_delayed_node_to_head(ref);
+ mutex_lock(&head->mutex);
+ kfree(head->extent_op);
+ delayed_refs->num_heads--;
+ if (list_empty(&head->cluster))
+ delayed_refs->num_heads_ready--;
+ list_del_init(&head->cluster);
+ mutex_unlock(&head->mutex);
+ }
+
+ spin_unlock(&delayed_refs->lock);
+ btrfs_put_delayed_ref(ref);
+
+ cond_resched();
+ spin_lock(&delayed_refs->lock);
+ }
+
+ spin_unlock(&delayed_refs->lock);
+
+ return ret;
+}
+
+static int btrfs_destroy_pending_snapshots(struct btrfs_transaction *t)
+{
+ struct btrfs_pending_snapshot *snapshot;
+ struct list_head splice;
+
+ INIT_LIST_HEAD(&splice);
+
+ list_splice_init(&t->pending_snapshots, &splice);
+
+ while (!list_empty(&splice)) {
+ snapshot = list_entry(splice.next,
+ struct btrfs_pending_snapshot,
+ list);
+
+ list_del_init(&snapshot->list);
+
+ kfree(snapshot);
+ }
+
+ return 0;
+}
+
+static int btrfs_destroy_delalloc_inodes(struct btrfs_root *root)
+{
+ struct btrfs_inode *btrfs_inode;
+ struct list_head splice;
+
+ INIT_LIST_HEAD(&splice);
+
+ list_splice_init(&root->fs_info->delalloc_inodes, &splice);
+
+ spin_lock(&root->fs_info->delalloc_lock);
+
+ while (!list_empty(&splice)) {
+ btrfs_inode = list_entry(splice.next, struct btrfs_inode,
+ delalloc_inodes);
+
+ list_del_init(&btrfs_inode->delalloc_inodes);
+
+ btrfs_invalidate_inodes(btrfs_inode->root);
+ }
+
+ spin_unlock(&root->fs_info->delalloc_lock);
+
+ return 0;
+}
+
+static int btrfs_destroy_marked_extents(struct btrfs_root *root,
+ struct extent_io_tree *dirty_pages,
+ int mark)
+{
+ int ret;
+ struct page *page;
+ struct inode *btree_inode = root->fs_info->btree_inode;
+ struct extent_buffer *eb;
+ u64 start = 0;
+ u64 end;
+ u64 offset;
+ unsigned long index;
+
+ while (1) {
+ ret = find_first_extent_bit(dirty_pages, start, &start, &end,
+ mark);
+ if (ret)
+ break;
+
+ clear_extent_bits(dirty_pages, start, end, mark, GFP_NOFS);
+ while (start <= end) {
+ index = start >> PAGE_CACHE_SHIFT;
+ start = (u64)(index + 1) << PAGE_CACHE_SHIFT;
+ page = find_get_page(btree_inode->i_mapping, index);
+ if (!page)
+ continue;
+ offset = page_offset(page);
+
+ spin_lock(&dirty_pages->buffer_lock);
+ eb = radix_tree_lookup(
+ &(&BTRFS_I(page->mapping->host)->io_tree)->buffer,
+ offset >> PAGE_CACHE_SHIFT);
+ spin_unlock(&dirty_pages->buffer_lock);
+ if (eb) {
+ ret = test_and_clear_bit(EXTENT_BUFFER_DIRTY,
+ &eb->bflags);
+ atomic_set(&eb->refs, 1);
+ }
+ if (PageWriteback(page))
+ end_page_writeback(page);
+
+ lock_page(page);
+ if (PageDirty(page)) {
+ clear_page_dirty_for_io(page);
+ spin_lock_irq(&page->mapping->tree_lock);
+ radix_tree_tag_clear(&page->mapping->page_tree,
+ page_index(page),
+ PAGECACHE_TAG_DIRTY);
+ spin_unlock_irq(&page->mapping->tree_lock);
+ }
+
+ page->mapping->a_ops->invalidatepage(page, 0);
+ unlock_page(page);
+ }
+ }
+
+ return ret;
+}
+
+static int btrfs_destroy_pinned_extent(struct btrfs_root *root,
+ struct extent_io_tree *pinned_extents)
+{
+ struct extent_io_tree *unpin;
+ u64 start;
+ u64 end;
+ int ret;
+
+ unpin = pinned_extents;
+ while (1) {
+ ret = find_first_extent_bit(unpin, 0, &start, &end,
+ EXTENT_DIRTY);
+ if (ret)
+ break;
+
+ /* opt_discard */
+ ret = btrfs_error_discard_extent(root, start, end + 1 - start);
+
+ clear_extent_dirty(unpin, start, end, GFP_NOFS);
+ btrfs_error_unpin_extent_range(root, start, end);
+ cond_resched();
+ }
+
+ return 0;
+}
+
+static int btrfs_cleanup_transaction(struct btrfs_root *root)
+{
+ struct btrfs_transaction *t;
+ LIST_HEAD(list);
+
+ WARN_ON(1);
+
+ mutex_lock(&root->fs_info->trans_mutex);
+ mutex_lock(&root->fs_info->transaction_kthread_mutex);
+
+ list_splice_init(&root->fs_info->trans_list, &list);
+ while (!list_empty(&list)) {
+ t = list_entry(list.next, struct btrfs_transaction, list);
+ if (!t)
+ break;
+
+ btrfs_destroy_ordered_operations(root);
+
+ btrfs_destroy_ordered_extents(root);
+
+ btrfs_destroy_delayed_refs(t, root);
+
+ btrfs_block_rsv_release(root,
+ &root->fs_info->trans_block_rsv,
+ t->dirty_pages.dirty_bytes);
+
+ /* FIXME: cleanup wait for commit */
+ t->in_commit = 1;
+ t->blocked = 1;
+ if (waitqueue_active(&root->fs_info->transaction_blocked_wait))
+ wake_up(&root->fs_info->transaction_blocked_wait);
+
+ t->blocked = 0;
+ if (waitqueue_active(&root->fs_info->transaction_wait))
+ wake_up(&root->fs_info->transaction_wait);
+ mutex_unlock(&root->fs_info->trans_mutex);
+
+ mutex_lock(&root->fs_info->trans_mutex);
+ t->commit_done = 1;
+ if (waitqueue_active(&t->commit_wait))
+ wake_up(&t->commit_wait);
+ mutex_unlock(&root->fs_info->trans_mutex);
+
+ mutex_lock(&root->fs_info->trans_mutex);
+
+ btrfs_destroy_pending_snapshots(t);
+
+ btrfs_destroy_delalloc_inodes(root);
+
+ spin_lock(&root->fs_info->new_trans_lock);
+ root->fs_info->running_transaction = NULL;
+ spin_unlock(&root->fs_info->new_trans_lock);
+
+ btrfs_destroy_marked_extents(root, &t->dirty_pages,
+ EXTENT_DIRTY);
+
+ btrfs_destroy_pinned_extent(root,
+ root->fs_info->pinned_extents);
+
+ t->use_count = 0;
+ list_del_init(&t->list);
+ memset(t, 0, sizeof(*t));
+ kmem_cache_free(btrfs_transaction_cachep, t);
+ }
+
+ mutex_unlock(&root->fs_info->transaction_kthread_mutex);
+ mutex_unlock(&root->fs_info->trans_mutex);
+
+ return 0;
+}
+
static struct extent_io_ops btree_extent_io_ops = {
.write_cache_pages_lock_hook = btree_lock_page_hook,
.readpage_end_io_hook = btree_readpage_end_io_hook,
diff --git a/fs/btrfs/disk-io.h b/fs/btrfs/disk-io.h
index 88e825a..07b20dc 100644
--- a/fs/btrfs/disk-io.h
+++ b/fs/btrfs/disk-io.h
@@ -52,6 +52,7 @@ int write_ctree_super(struct btrfs_trans_handle *trans,
struct btrfs_root *root, int max_mirrors);
struct buffer_head *btrfs_read_dev_super(struct block_device *bdev);
int btrfs_commit_super(struct btrfs_root *root);
+int btrfs_error_commit_super(struct btrfs_root *root);
struct extent_buffer *btrfs_find_tree_block(struct btrfs_root *root,
u64 bytenr, u32 blocksize);
struct btrfs_root *btrfs_lookup_fs_root(struct btrfs_fs_info *fs_info,
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index 227e581..b552693 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -3089,7 +3089,7 @@ static u64 get_alloc_profile(struct btrfs_root *root, u64 flags)
return btrfs_reduce_alloc_profile(root, flags);
}
-static u64 btrfs_get_alloc_profile(struct btrfs_root *root, int data)
+u64 btrfs_get_alloc_profile(struct btrfs_root *root, int data)
{
u64 flags;
@@ -3161,8 +3161,12 @@ alloc:
bytes + 2 * 1024 * 1024,
alloc_target, 0);
btrfs_end_transaction(trans, root);
- if (ret < 0)
- return ret;
+ if (ret < 0) {
+ if (ret != -ENOSPC)
+ return ret;
+ else
+ goto commit_trans;
+ }
if (!data_sinfo) {
btrfs_set_inode_space_info(root, inode);
@@ -3173,6 +3177,7 @@ alloc:
spin_unlock(&data_sinfo->lock);
/* commit the current transaction and try again */
+commit_trans:
if (!committed && !root->fs_info->open_ioctl_trans) {
committed = 1;
trans = btrfs_join_transaction(root, 1);
@@ -3721,11 +3726,6 @@ int btrfs_block_rsv_check(struct btrfs_trans_handle *trans,
return 0;
}
- WARN_ON(1);
- printk(KERN_INFO"block_rsv size %llu reserved %llu freed %llu %llu\n",
- block_rsv->size, block_rsv->reserved,
- block_rsv->freed[0], block_rsv->freed[1]);
-
return -ENOSPC;
}
@@ -7970,13 +7970,14 @@ static int set_block_group_ro(struct btrfs_block_group_cache *cache)
if (sinfo->bytes_used + sinfo->bytes_reserved + sinfo->bytes_pinned +
sinfo->bytes_may_use + sinfo->bytes_readonly +
- cache->reserved_pinned + num_bytes < sinfo->total_bytes) {
+ cache->reserved_pinned + num_bytes <= sinfo->total_bytes) {
sinfo->bytes_readonly += num_bytes;
sinfo->bytes_reserved += cache->reserved_pinned;
cache->reserved_pinned = 0;
cache->ro = 1;
ret = 0;
}
+
spin_unlock(&cache->lock);
spin_unlock(&sinfo->lock);
return ret;
@@ -8012,6 +8013,62 @@ out:
return ret;
}
+/*
+ * helper to account the unused space of all the readonly block group in the
+ * list. takes mirrors into account.
+ */
+static u64 __btrfs_get_ro_block_group_free_space(struct list_head *groups_list)
+{
+ struct btrfs_block_group_cache *block_group;
+ u64 free_bytes = 0;
+ int factor;
+
+ list_for_each_entry(block_group, groups_list, list) {
+ spin_lock(&block_group->lock);
+
+ if (!block_group->ro) {
+ spin_unlock(&block_group->lock);
+ continue;
+ }
+
+ if (block_group->flags & (BTRFS_BLOCK_GROUP_RAID1 |
+ BTRFS_BLOCK_GROUP_RAID10 |
+ BTRFS_BLOCK_GROUP_DUP))
+ factor = 2;
+ else
+ factor = 1;
+
+ free_bytes += (block_group->key.offset -
+ btrfs_block_group_used(&block_group->item)) *
+ factor;
+
+ spin_unlock(&block_group->lock);
+ }
+
+ return free_bytes;
+}
+
+/*
+ * helper to account the unused space of all the readonly block group in the
+ * space_info. takes mirrors into account.
+ */
+u64 btrfs_account_ro_block_groups_free_space(struct btrfs_space_info *sinfo)
+{
+ int i;
+ u64 free_bytes = 0;
+
+ spin_lock(&sinfo->lock);
+
+ for(i = 0; i < BTRFS_NR_RAID_TYPES; i++)
+ if (!list_empty(&sinfo->block_groups[i]))
+ free_bytes += __btrfs_get_ro_block_group_free_space(
+ &sinfo->block_groups[i]);
+
+ spin_unlock(&sinfo->lock);
+
+ return free_bytes;
+}
+
int btrfs_set_block_group_rw(struct btrfs_root *root,
struct btrfs_block_group_cache *cache)
{
@@ -8092,7 +8149,7 @@ int btrfs_can_relocate(struct btrfs_root *root, u64 bytenr)
mutex_lock(&root->fs_info->chunk_mutex);
list_for_each_entry(device, &fs_devices->alloc_list, dev_alloc_list) {
u64 min_free = btrfs_block_group_used(&block_group->item);
- u64 dev_offset, max_avail;
+ u64 dev_offset;
/*
* check to make sure we can actually find a chunk with enough
@@ -8100,7 +8157,7 @@ int btrfs_can_relocate(struct btrfs_root *root, u64 bytenr)
*/
if (device->total_bytes > device->bytes_used + min_free) {
ret = find_free_dev_extent(NULL, device, min_free,
- &dev_offset, &max_avail);
+ &dev_offset, NULL);
if (!ret)
break;
ret = -1;
@@ -8584,3 +8641,14 @@ out:
btrfs_free_path(path);
return ret;
}
+
+int btrfs_error_unpin_extent_range(struct btrfs_root *root, u64 start, u64 end)
+{
+ return unpin_extent_range(root, start, end);
+}
+
+int btrfs_error_discard_extent(struct btrfs_root *root, u64 bytenr,
+ u64 num_bytes)
+{
+ return btrfs_discard_extent(root, bytenr, num_bytes);
+}
diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c
index 3e86b9f..2e993cf 100644
--- a/fs/btrfs/extent_io.c
+++ b/fs/btrfs/extent_io.c
@@ -2028,8 +2028,11 @@ static int __extent_read_full_page(struct extent_io_tree *tree,
BUG_ON(extent_map_end(em) <= cur);
BUG_ON(end < cur);
- if (test_bit(EXTENT_FLAG_COMPRESSED, &em->flags))
+ if (test_bit(EXTENT_FLAG_COMPRESSED, &em->flags)) {
this_bio_flag = EXTENT_BIO_COMPRESSED;
+ extent_set_compress_type(&this_bio_flag,
+ em->compress_type);
+ }
iosize = min(extent_map_end(em) - cur, end - cur + 1);
cur_end = min(extent_map_end(em) - 1, end);
@@ -3072,6 +3075,8 @@ static struct extent_buffer *__alloc_extent_buffer(struct extent_io_tree *tree,
#endif
eb = kmem_cache_zalloc(extent_buffer_cache, mask);
+ if (eb == NULL)
+ return NULL;
eb->start = start;
eb->len = len;
spin_lock_init(&eb->lock);
diff --git a/fs/btrfs/extent_io.h b/fs/btrfs/extent_io.h
index 4183c81..7083cfa 100644
--- a/fs/btrfs/extent_io.h
+++ b/fs/btrfs/extent_io.h
@@ -20,8 +20,12 @@
#define EXTENT_IOBITS (EXTENT_LOCKED | EXTENT_WRITEBACK)
#define EXTENT_CTLBITS (EXTENT_DO_ACCOUNTING | EXTENT_FIRST_DELALLOC)
-/* flags for bio submission */
+/*
+ * flags for bio submission. The high bits indicate the compression
+ * type for this bio
+ */
#define EXTENT_BIO_COMPRESSED 1
+#define EXTENT_BIO_FLAG_SHIFT 16
/* these are bit numbers for test/set bit */
#define EXTENT_BUFFER_UPTODATE 0
@@ -135,6 +139,17 @@ struct extent_buffer {
wait_queue_head_t lock_wq;
};
+static inline void extent_set_compress_type(unsigned long *bio_flags,
+ int compress_type)
+{
+ *bio_flags |= compress_type << EXTENT_BIO_FLAG_SHIFT;
+}
+
+static inline int extent_compress_type(unsigned long bio_flags)
+{
+ return bio_flags >> EXTENT_BIO_FLAG_SHIFT;
+}
+
struct extent_map_tree;
static inline struct extent_state *extent_state_next(struct extent_state *state)
diff --git a/fs/btrfs/extent_map.c b/fs/btrfs/extent_map.c
index 23cb8da..b0e1fce 100644
--- a/fs/btrfs/extent_map.c
+++ b/fs/btrfs/extent_map.c
@@ -3,6 +3,7 @@
#include <linux/module.h>
#include <linux/spinlock.h>
#include <linux/hardirq.h>
+#include "ctree.h"
#include "extent_map.h"
@@ -54,6 +55,7 @@ struct extent_map *alloc_extent_map(gfp_t mask)
return em;
em->in_tree = 0;
em->flags = 0;
+ em->compress_type = BTRFS_COMPRESS_NONE;
atomic_set(&em->refs, 1);
return em;
}
diff --git a/fs/btrfs/extent_map.h b/fs/btrfs/extent_map.h
index ab6d74b..28b44db 100644
--- a/fs/btrfs/extent_map.h
+++ b/fs/btrfs/extent_map.h
@@ -26,7 +26,8 @@ struct extent_map {
unsigned long flags;
struct block_device *bdev;
atomic_t refs;
- int in_tree;
+ unsigned int in_tree:1;
+ unsigned int compress_type:4;
};
struct extent_map_tree {
diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c
index 66836d8..c800d58 100644
--- a/fs/btrfs/file.c
+++ b/fs/btrfs/file.c
@@ -24,6 +24,7 @@
#include <linux/string.h>
#include <linux/backing-dev.h>
#include <linux/mpage.h>
+#include <linux/falloc.h>
#include <linux/swap.h>
#include <linux/writeback.h>
#include <linux/statfs.h>
@@ -224,6 +225,7 @@ int btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end,
split->bdev = em->bdev;
split->flags = flags;
+ split->compress_type = em->compress_type;
ret = add_extent_mapping(em_tree, split);
BUG_ON(ret);
free_extent_map(split);
@@ -238,6 +240,7 @@ int btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end,
split->len = em->start + em->len - (start + len);
split->bdev = em->bdev;
split->flags = flags;
+ split->compress_type = em->compress_type;
if (compressed) {
split->block_len = em->block_len;
@@ -890,6 +893,17 @@ static ssize_t btrfs_file_aio_write(struct kiocb *iocb,
if (err)
goto out;
+ /*
+ * If BTRFS flips readonly due to some impossible error
+ * (fs_info->fs_state now has BTRFS_SUPER_FLAG_ERROR),
+ * although we have opened a file as writable, we have
+ * to stop this write operation to ensure FS consistency.
+ */
+ if (root->fs_info->fs_state & BTRFS_SUPER_FLAG_ERROR) {
+ err = -EROFS;
+ goto out;
+ }
+
file_update_time(file);
BTRFS_I(inode)->sequence++;
@@ -1237,6 +1251,117 @@ static int btrfs_file_mmap(struct file *filp, struct vm_area_struct *vma)
return 0;
}
+static long btrfs_fallocate(struct file *file, int mode,
+ loff_t offset, loff_t len)
+{
+ struct inode *inode = file->f_path.dentry->d_inode;
+ struct extent_state *cached_state = NULL;
+ u64 cur_offset;
+ u64 last_byte;
+ u64 alloc_start;
+ u64 alloc_end;
+ u64 alloc_hint = 0;
+ u64 locked_end;
+ u64 mask = BTRFS_I(inode)->root->sectorsize - 1;
+ struct extent_map *em;
+ int ret;
+
+ alloc_start = offset & ~mask;
+ alloc_end = (offset + len + mask) & ~mask;
+
+ /* We only support the FALLOC_FL_KEEP_SIZE mode */
+ if (mode & ~FALLOC_FL_KEEP_SIZE)
+ return -EOPNOTSUPP;
+
+ /*
+ * wait for ordered IO before we have any locks. We'll loop again
+ * below with the locks held.
+ */
+ btrfs_wait_ordered_range(inode, alloc_start, alloc_end - alloc_start);
+
+ mutex_lock(&inode->i_mutex);
+ ret = inode_newsize_ok(inode, alloc_end);
+ if (ret)
+ goto out;
+
+ if (alloc_start > inode->i_size) {
+ ret = btrfs_cont_expand(inode, alloc_start);
+ if (ret)
+ goto out;
+ }
+
+ ret = btrfs_check_data_free_space(inode, alloc_end - alloc_start);
+ if (ret)
+ goto out;
+
+ locked_end = alloc_end - 1;
+ while (1) {
+ struct btrfs_ordered_extent *ordered;
+
+ /* the extent lock is ordered inside the running
+ * transaction
+ */
+ lock_extent_bits(&BTRFS_I(inode)->io_tree, alloc_start,
+ locked_end, 0, &cached_state, GFP_NOFS);
+ ordered = btrfs_lookup_first_ordered_extent(inode,
+ alloc_end - 1);
+ if (ordered &&
+ ordered->file_offset + ordered->len > alloc_start &&
+ ordered->file_offset < alloc_end) {
+ btrfs_put_ordered_extent(ordered);
+ unlock_extent_cached(&BTRFS_I(inode)->io_tree,
+ alloc_start, locked_end,
+ &cached_state, GFP_NOFS);
+ /*
+ * we can't wait on the range with the transaction
+ * running or with the extent lock held
+ */
+ btrfs_wait_ordered_range(inode, alloc_start,
+ alloc_end - alloc_start);
+ } else {
+ if (ordered)
+ btrfs_put_ordered_extent(ordered);
+ break;
+ }
+ }
+
+ cur_offset = alloc_start;
+ while (1) {
+ em = btrfs_get_extent(inode, NULL, 0, cur_offset,
+ alloc_end - cur_offset, 0);
+ BUG_ON(IS_ERR(em) || !em);
+ last_byte = min(extent_map_end(em), alloc_end);
+ last_byte = (last_byte + mask) & ~mask;
+ if (em->block_start == EXTENT_MAP_HOLE ||
+ (cur_offset >= inode->i_size &&
+ !test_bit(EXTENT_FLAG_PREALLOC, &em->flags))) {
+ ret = btrfs_prealloc_file_range(inode, mode, cur_offset,
+ last_byte - cur_offset,
+ 1 << inode->i_blkbits,
+ offset + len,
+ &alloc_hint);
+ if (ret < 0) {
+ free_extent_map(em);
+ break;
+ }
+ }
+ free_extent_map(em);
+
+ cur_offset = last_byte;
+ if (cur_offset >= alloc_end) {
+ ret = 0;
+ break;
+ }
+ }
+ unlock_extent_cached(&BTRFS_I(inode)->io_tree, alloc_start, locked_end,
+ &cached_state, GFP_NOFS);
+
+ btrfs_free_reserved_data_space(inode, alloc_end - alloc_start);
+out:
+ mutex_unlock(&inode->i_mutex);
+ return ret;
+}
+
const struct file_operations btrfs_file_operations = {
.llseek = generic_file_llseek,
.read = do_sync_read,
@@ -1248,6 +1373,7 @@ const struct file_operations btrfs_file_operations = {
.open = generic_file_open,
.release = btrfs_release_file,
.fsync = btrfs_sync_file,
+ .fallocate = btrfs_fallocate,
.unlocked_ioctl = btrfs_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = btrfs_ioctl,
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index a3798a3..160b55b 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -122,10 +122,10 @@ static noinline int insert_inline_extent(struct btrfs_trans_handle *trans,
size_t cur_size = size;
size_t datasize;
unsigned long offset;
- int use_compress = 0;
+ int compress_type = BTRFS_COMPRESS_NONE;
if (compressed_size && compressed_pages) {
- use_compress = 1;
+ compress_type = root->fs_info->compress_type;
cur_size = compressed_size;
}
@@ -159,7 +159,7 @@ static noinline int insert_inline_extent(struct btrfs_trans_handle *trans,
btrfs_set_file_extent_ram_bytes(leaf, ei, size);
ptr = btrfs_file_extent_inline_start(ei);
- if (use_compress) {
+ if (compress_type != BTRFS_COMPRESS_NONE) {
struct page *cpage;
int i = 0;
while (compressed_size > 0) {
@@ -176,7 +176,7 @@ static noinline int insert_inline_extent(struct btrfs_trans_handle *trans,
compressed_size -= cur_size;
}
btrfs_set_file_extent_compression(leaf, ei,
- BTRFS_COMPRESS_ZLIB);
+ compress_type);
} else {
page = find_get_page(inode->i_mapping,
start >> PAGE_CACHE_SHIFT);
@@ -263,6 +263,7 @@ struct async_extent {
u64 compressed_size;
struct page **pages;
unsigned long nr_pages;
+ int compress_type;
struct list_head list;
};
@@ -280,7 +281,8 @@ static noinline int add_async_extent(struct async_cow *cow,
u64 start, u64 ram_size,
u64 compressed_size,
struct page **pages,
- unsigned long nr_pages)
+ unsigned long nr_pages,
+ int compress_type)
{
struct async_extent *async_extent;
@@ -290,6 +292,7 @@ static noinline int add_async_extent(struct async_cow *cow,
async_extent->compressed_size = compressed_size;
async_extent->pages = pages;
async_extent->nr_pages = nr_pages;
+ async_extent->compress_type = compress_type;
list_add_tail(&async_extent->list, &cow->extents);
return 0;
}
@@ -332,6 +335,7 @@ static noinline int compress_file_range(struct inode *inode,
unsigned long max_uncompressed = 128 * 1024;
int i;
int will_compress;
+ int compress_type = root->fs_info->compress_type;
actual_end = min_t(u64, isize, end + 1);
again:
@@ -381,12 +385,16 @@ again:
WARN_ON(pages);
pages = kzalloc(sizeof(struct page *) * nr_pages, GFP_NOFS);
- ret = btrfs_zlib_compress_pages(inode->i_mapping, start,
- total_compressed, pages,
- nr_pages, &nr_pages_ret,
- &total_in,
- &total_compressed,
- max_compressed);
+ if (BTRFS_I(inode)->force_compress)
+ compress_type = BTRFS_I(inode)->force_compress;
+
+ ret = btrfs_compress_pages(compress_type,
+ inode->i_mapping, start,
+ total_compressed, pages,
+ nr_pages, &nr_pages_ret,
+ &total_in,
+ &total_compressed,
+ max_compressed);
if (!ret) {
unsigned long offset = total_compressed &
@@ -493,7 +501,8 @@ again:
* and will submit them to the elevator.
*/
add_async_extent(async_cow, start, num_bytes,
- total_compressed, pages, nr_pages_ret);
+ total_compressed, pages, nr_pages_ret,
+ compress_type);
if (start + num_bytes < end) {
start += num_bytes;
@@ -515,7 +524,8 @@ cleanup_and_bail_uncompressed:
__set_page_dirty_nobuffers(locked_page);
/* unlocked later on in the async handlers */
}
- add_async_extent(async_cow, start, end - start + 1, 0, NULL, 0);
+ add_async_extent(async_cow, start, end - start + 1,
+ 0, NULL, 0, BTRFS_COMPRESS_NONE);
*num_added += 1;
}
@@ -640,6 +650,7 @@ retry:
em->block_start = ins.objectid;
em->block_len = ins.offset;
em->bdev = root->fs_info->fs_devices->latest_bdev;
+ em->compress_type = async_extent->compress_type;
set_bit(EXTENT_FLAG_PINNED, &em->flags);
set_bit(EXTENT_FLAG_COMPRESSED, &em->flags);
@@ -656,11 +667,13 @@ retry:
async_extent->ram_size - 1, 0);
}
- ret = btrfs_add_ordered_extent(inode, async_extent->start,
- ins.objectid,
- async_extent->ram_size,
- ins.offset,
- BTRFS_ORDERED_COMPRESSED);
+ ret = btrfs_add_ordered_extent_compress(inode,
+ async_extent->start,
+ ins.objectid,
+ async_extent->ram_size,
+ ins.offset,
+ BTRFS_ORDERED_COMPRESSED,
+ async_extent->compress_type);
BUG_ON(ret);
/*
@@ -1670,7 +1683,7 @@ static int btrfs_finish_ordered_io(struct inode *inode, u64 start, u64 end)
struct btrfs_ordered_extent *ordered_extent = NULL;
struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree;
struct extent_state *cached_state = NULL;
- int compressed = 0;
+ int compress_type = 0;
int ret;
bool nolock = false;
@@ -1711,9 +1724,9 @@ static int btrfs_finish_ordered_io(struct inode *inode, u64 start, u64 end)
trans->block_rsv = &root->fs_info->delalloc_block_rsv;
if (test_bit(BTRFS_ORDERED_COMPRESSED, &ordered_extent->flags))
- compressed = 1;
+ compress_type = ordered_extent->compress_type;
if (test_bit(BTRFS_ORDERED_PREALLOC, &ordered_extent->flags)) {
- BUG_ON(compressed);
+ BUG_ON(compress_type);
ret = btrfs_mark_extent_written(trans, inode,
ordered_extent->file_offset,
ordered_extent->file_offset +
@@ -1727,7 +1740,7 @@ static int btrfs_finish_ordered_io(struct inode *inode, u64 start, u64 end)
ordered_extent->disk_len,
ordered_extent->len,
ordered_extent->len,
- compressed, 0, 0,
+ compress_type, 0, 0,
BTRFS_FILE_EXTENT_REG);
unpin_extent_cache(&BTRFS_I(inode)->extent_tree,
ordered_extent->file_offset,
@@ -1829,6 +1842,8 @@ static int btrfs_io_failed_hook(struct bio *failed_bio,
if (test_bit(EXTENT_FLAG_COMPRESSED, &em->flags)) {
logical = em->block_start;
failrec->bio_flags = EXTENT_BIO_COMPRESSED;
+ extent_set_compress_type(&failrec->bio_flags,
+ em->compress_type);
}
failrec->logical = logical;
free_extent_map(em);
@@ -3671,8 +3686,12 @@ static int btrfs_setattr_size(struct inode *inode, struct iattr *attr)
static int btrfs_setattr(struct dentry *dentry, struct iattr *attr)
{
struct inode *inode = dentry->d_inode;
+ struct btrfs_root *root = BTRFS_I(inode)->root;
int err;
+ if (btrfs_root_readonly(root))
+ return -EROFS;
+
err = inode_change_ok(inode, attr);
if (err)
return err;
@@ -4928,8 +4947,10 @@ static noinline int uncompress_inline(struct btrfs_path *path,
size_t max_size;
unsigned long inline_size;
unsigned long ptr;
+ int compress_type;
WARN_ON(pg_offset != 0);
+ compress_type = btrfs_file_extent_compression(leaf, item);
max_size = btrfs_file_extent_ram_bytes(leaf, item);
inline_size = btrfs_file_extent_inline_item_len(leaf,
btrfs_item_nr(leaf, path->slots[0]));
@@ -4939,8 +4960,8 @@ static noinline int uncompress_inline(struct btrfs_path *path,
read_extent_buffer(leaf, tmp, ptr, inline_size);
max_size = min_t(unsigned long, PAGE_CACHE_SIZE, max_size);
- ret = btrfs_zlib_decompress(tmp, page, extent_offset,
- inline_size, max_size);
+ ret = btrfs_decompress(compress_type, tmp, page,
+ extent_offset, inline_size, max_size);
if (ret) {
char *kaddr = kmap_atomic(page, KM_USER0);
unsigned long copy_size = min_t(u64,
@@ -4982,7 +5003,7 @@ struct extent_map *btrfs_get_extent(struct inode *inode, struct page *page,
struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree;
struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree;
struct btrfs_trans_handle *trans = NULL;
- int compressed;
+ int compress_type;
again:
read_lock(&em_tree->lock);
@@ -5041,7 +5062,7 @@ again:
found_type = btrfs_file_extent_type(leaf, item);
extent_start = found_key.offset;
- compressed = btrfs_file_extent_compression(leaf, item);
+ compress_type = btrfs_file_extent_compression(leaf, item);
if (found_type == BTRFS_FILE_EXTENT_REG ||
found_type == BTRFS_FILE_EXTENT_PREALLOC) {
extent_end = extent_start +
@@ -5087,8 +5108,9 @@ again:
em->block_start = EXTENT_MAP_HOLE;
goto insert;
}
- if (compressed) {
+ if (compress_type != BTRFS_COMPRESS_NONE) {
set_bit(EXTENT_FLAG_COMPRESSED, &em->flags);
+ em->compress_type = compress_type;
em->block_start = bytenr;
em->block_len = btrfs_file_extent_disk_num_bytes(leaf,
item);
@@ -5122,12 +5144,14 @@ again:
em->len = (copy_size + root->sectorsize - 1) &
~((u64)root->sectorsize - 1);
em->orig_start = EXTENT_MAP_INLINE;
- if (compressed)
+ if (compress_type) {
set_bit(EXTENT_FLAG_COMPRESSED, &em->flags);
+ em->compress_type = compress_type;
+ }
ptr = btrfs_file_extent_inline_start(item) + extent_offset;
if (create == 0 && !PageUptodate(page)) {
- if (btrfs_file_extent_compression(leaf, item) ==
- BTRFS_COMPRESS_ZLIB) {
+ if (btrfs_file_extent_compression(leaf, item) !=
+ BTRFS_COMPRESS_NONE) {
ret = uncompress_inline(path, inode, page,
pg_offset,
extent_offset, item);
@@ -6477,7 +6501,7 @@ struct inode *btrfs_alloc_inode(struct super_block *sb)
ei->ordered_data_close = 0;
ei->orphan_meta_reserved = 0;
ei->dummy_inode = 0;
- ei->force_compress = 0;
+ ei->force_compress = BTRFS_COMPRESS_NONE;
inode = &ei->vfs_inode;
extent_map_tree_init(&ei->extent_tree, GFP_NOFS);
@@ -7098,116 +7122,6 @@ int btrfs_prealloc_file_range_trans(struct inode *inode,
min_size, actual_len, alloc_hint, trans);
}
-static long btrfs_fallocate(struct inode *inode, int mode,
- loff_t offset, loff_t len)
-{
- struct extent_state *cached_state = NULL;
- u64 cur_offset;
- u64 last_byte;
- u64 alloc_start;
- u64 alloc_end;
- u64 alloc_hint = 0;
- u64 locked_end;
- u64 mask = BTRFS_I(inode)->root->sectorsize - 1;
- struct extent_map *em;
- int ret;
-
- alloc_start = offset & ~mask;
- alloc_end = (offset + len + mask) & ~mask;
-
- /* We only support the FALLOC_FL_KEEP_SIZE mode */
- if (mode && (mode != FALLOC_FL_KEEP_SIZE))
- return -EOPNOTSUPP;
-
- /*
- * wait for ordered IO before we have any locks. We'll loop again
- * below with the locks held.
- */
- btrfs_wait_ordered_range(inode, alloc_start, alloc_end - alloc_start);
-
- mutex_lock(&inode->i_mutex);
- ret = inode_newsize_ok(inode, alloc_end);
- if (ret)
- goto out;
-
- if (alloc_start > inode->i_size) {
- ret = btrfs_cont_expand(inode, alloc_start);
- if (ret)
- goto out;
- }
-
- ret = btrfs_check_data_free_space(inode, alloc_end - alloc_start);
- if (ret)
- goto out;
-
- locked_end = alloc_end - 1;
- while (1) {
- struct btrfs_ordered_extent *ordered;
-
- /* the extent lock is ordered inside the running
- * transaction
- */
- lock_extent_bits(&BTRFS_I(inode)->io_tree, alloc_start,
- locked_end, 0, &cached_state, GFP_NOFS);
- ordered = btrfs_lookup_first_ordered_extent(inode,
- alloc_end - 1);
- if (ordered &&
- ordered->file_offset + ordered->len > alloc_start &&
- ordered->file_offset < alloc_end) {
- btrfs_put_ordered_extent(ordered);
- unlock_extent_cached(&BTRFS_I(inode)->io_tree,
- alloc_start, locked_end,
- &cached_state, GFP_NOFS);
- /*
- * we can't wait on the range with the transaction
- * running or with the extent lock held
- */
- btrfs_wait_ordered_range(inode, alloc_start,
- alloc_end - alloc_start);
- } else {
- if (ordered)
- btrfs_put_ordered_extent(ordered);
- break;
- }
- }
-
- cur_offset = alloc_start;
- while (1) {
- em = btrfs_get_extent(inode, NULL, 0, cur_offset,
- alloc_end - cur_offset, 0);
- BUG_ON(IS_ERR(em) || !em);
- last_byte = min(extent_map_end(em), alloc_end);
- last_byte = (last_byte + mask) & ~mask;
- if (em->block_start == EXTENT_MAP_HOLE ||
- (cur_offset >= inode->i_size &&
- !test_bit(EXTENT_FLAG_PREALLOC, &em->flags))) {
- ret = btrfs_prealloc_file_range(inode, mode, cur_offset,
- last_byte - cur_offset,
- 1 << inode->i_blkbits,
- offset + len,
- &alloc_hint);
- if (ret < 0) {
- free_extent_map(em);
- break;
- }
- }
- free_extent_map(em);
-
- cur_offset = last_byte;
- if (cur_offset >= alloc_end) {
- ret = 0;
- break;
- }
- }
- unlock_extent_cached(&BTRFS_I(inode)->io_tree, alloc_start, locked_end,
- &cached_state, GFP_NOFS);
-
- btrfs_free_reserved_data_space(inode, alloc_end - alloc_start);
-out:
- mutex_unlock(&inode->i_mutex);
- return ret;
-}
-
static int btrfs_set_page_dirty(struct page *page)
{
return __set_page_dirty_nobuffers(page);
@@ -7215,6 +7129,10 @@ static int btrfs_set_page_dirty(struct page *page)
static int btrfs_permission(struct inode *inode, int mask, unsigned int flags)
{
+ struct btrfs_root *root = BTRFS_I(inode)->root;
+
+ if (btrfs_root_readonly(root) && (mask & MAY_WRITE))
+ return -EROFS;
if ((BTRFS_I(inode)->flags & BTRFS_INODE_READONLY) && (mask & MAY_WRITE))
return -EACCES;
return generic_permission(inode, mask, flags, btrfs_check_acl);
@@ -7310,7 +7228,6 @@ static const struct inode_operations btrfs_file_inode_operations = {
.listxattr = btrfs_listxattr,
.removexattr = btrfs_removexattr,
.permission = btrfs_permission,
- .fallocate = btrfs_fallocate,
.fiemap = btrfs_fiemap,
};
static const struct inode_operations btrfs_special_inode_operations = {
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index f87552a..a506a22 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -147,6 +147,9 @@ static int btrfs_ioctl_setflags(struct file *file, void __user *arg)
unsigned int flags, oldflags;
int ret;
+ if (btrfs_root_readonly(root))
+ return -EROFS;
+
if (copy_from_user(&flags, arg, sizeof(flags)))
return -EFAULT;
@@ -360,7 +363,8 @@ fail:
}
static int create_snapshot(struct btrfs_root *root, struct dentry *dentry,
- char *name, int namelen, u64 *async_transid)
+ char *name, int namelen, u64 *async_transid,
+ bool readonly)
{
struct inode *inode;
struct dentry *parent;
@@ -378,6 +382,7 @@ static int create_snapshot(struct btrfs_root *root, struct dentry *dentry,
btrfs_init_block_rsv(&pending_snapshot->block_rsv);
pending_snapshot->dentry = dentry;
pending_snapshot->root = root;
+ pending_snapshot->readonly = readonly;
trans = btrfs_start_transaction(root->fs_info->extent_root, 5);
if (IS_ERR(trans)) {
@@ -509,7 +514,7 @@ static inline int btrfs_may_create(struct inode *dir, struct dentry *child)
static noinline int btrfs_mksubvol(struct path *parent,
char *name, int namelen,
struct btrfs_root *snap_src,
- u64 *async_transid)
+ u64 *async_transid, bool readonly)
{
struct inode *dir = parent->dentry->d_inode;
struct dentry *dentry;
@@ -541,7 +546,7 @@ static noinline int btrfs_mksubvol(struct path *parent,
if (snap_src) {
error = create_snapshot(snap_src, dentry,
- name, namelen, async_transid);
+ name, namelen, async_transid, readonly);
} else {
error = create_subvol(BTRFS_I(dir)->root, dentry,
name, namelen, async_transid);
@@ -638,9 +643,11 @@ static int btrfs_defrag_file(struct file *file,
struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree;
struct btrfs_ordered_extent *ordered;
struct page *page;
+ struct btrfs_super_block *disk_super;
unsigned long last_index;
unsigned long ra_pages = root->fs_info->bdi.ra_pages;
unsigned long total_read = 0;
+ u64 features;
u64 page_start;
u64 page_end;
u64 last_len = 0;
@@ -648,6 +655,14 @@ static int btrfs_defrag_file(struct file *file,
u64 defrag_end = 0;
unsigned long i;
int ret;
+ int compress_type = BTRFS_COMPRESS_ZLIB;
+
+ if (range->flags & BTRFS_DEFRAG_RANGE_COMPRESS) {
+ if (range->compress_type > BTRFS_COMPRESS_TYPES)
+ return -EINVAL;
+ if (range->compress_type)
+ compress_type = range->compress_type;
+ }
if (inode->i_size == 0)
return 0;
@@ -683,7 +698,7 @@ static int btrfs_defrag_file(struct file *file,
total_read++;
mutex_lock(&inode->i_mutex);
if (range->flags & BTRFS_DEFRAG_RANGE_COMPRESS)
- BTRFS_I(inode)->force_compress = 1;
+ BTRFS_I(inode)->force_compress = compress_type;
ret = btrfs_delalloc_reserve_space(inode, PAGE_CACHE_SIZE);
if (ret)
@@ -781,10 +796,17 @@ loop_unlock:
atomic_dec(&root->fs_info->async_submit_draining);
mutex_lock(&inode->i_mutex);
- BTRFS_I(inode)->force_compress = 0;
+ BTRFS_I(inode)->force_compress = BTRFS_COMPRESS_NONE;
mutex_unlock(&inode->i_mutex);
}
+ disk_super = &root->fs_info->super_copy;
+ features = btrfs_super_incompat_flags(disk_super);
+ if (range->compress_type == BTRFS_COMPRESS_LZO) {
+ features |= BTRFS_FEATURE_INCOMPAT_COMPRESS_LZO;
+ btrfs_set_super_incompat_flags(disk_super, features);
+ }
+
return 0;
err_reservations:
@@ -901,7 +923,8 @@ static noinline int btrfs_ioctl_snap_create_transid(struct file *file,
char *name,
unsigned long fd,
int subvol,
- u64 *transid)
+ u64 *transid,
+ bool readonly)
{
struct btrfs_root *root = BTRFS_I(fdentry(file)->d_inode)->root;
struct file *src_file;
@@ -919,7 +942,7 @@ static noinline int btrfs_ioctl_snap_create_transid(struct file *file,
if (subvol) {
ret = btrfs_mksubvol(&file->f_path, name, namelen,
- NULL, transid);
+ NULL, transid, readonly);
} else {
struct inode *src_inode;
src_file = fget(fd);
@@ -938,7 +961,7 @@ static noinline int btrfs_ioctl_snap_create_transid(struct file *file,
}
ret = btrfs_mksubvol(&file->f_path, name, namelen,
BTRFS_I(src_inode)->root,
- transid);
+ transid, readonly);
fput(src_file);
}
out:
@@ -946,58 +969,139 @@ out:
}
static noinline int btrfs_ioctl_snap_create(struct file *file,
- void __user *arg, int subvol,
- int v2)
+ void __user *arg, int subvol)
{
- struct btrfs_ioctl_vol_args *vol_args = NULL;
- struct btrfs_ioctl_vol_args_v2 *vol_args_v2 = NULL;
- char *name;
- u64 fd;
+ struct btrfs_ioctl_vol_args *vol_args;
int ret;
- if (v2) {
- u64 transid = 0;
- u64 *ptr = NULL;
+ vol_args = memdup_user(arg, sizeof(*vol_args));
+ if (IS_ERR(vol_args))
+ return PTR_ERR(vol_args);
+ vol_args->name[BTRFS_PATH_NAME_MAX] = '\0';
- vol_args_v2 = memdup_user(arg, sizeof(*vol_args_v2));
- if (IS_ERR(vol_args_v2))
- return PTR_ERR(vol_args_v2);
+ ret = btrfs_ioctl_snap_create_transid(file, vol_args->name,
+ vol_args->fd, subvol,
+ NULL, false);
- if (vol_args_v2->flags & ~BTRFS_SUBVOL_CREATE_ASYNC) {
- ret = -EINVAL;
- goto out;
- }
-
- name = vol_args_v2->name;
- fd = vol_args_v2->fd;
- vol_args_v2->name[BTRFS_SUBVOL_NAME_MAX] = '\0';
+ kfree(vol_args);
+ return ret;
+}
- if (vol_args_v2->flags & BTRFS_SUBVOL_CREATE_ASYNC)
- ptr = &transid;
+static noinline int btrfs_ioctl_snap_create_v2(struct file *file,
+ void __user *arg, int subvol)
+{
+ struct btrfs_ioctl_vol_args_v2 *vol_args;
+ int ret;
+ u64 transid = 0;
+ u64 *ptr = NULL;
+ bool readonly = false;
- ret = btrfs_ioctl_snap_create_transid(file, name, fd,
- subvol, ptr);
+ vol_args = memdup_user(arg, sizeof(*vol_args));
+ if (IS_ERR(vol_args))
+ return PTR_ERR(vol_args);
+ vol_args->name[BTRFS_SUBVOL_NAME_MAX] = '\0';
- if (ret == 0 && ptr &&
- copy_to_user(arg +
- offsetof(struct btrfs_ioctl_vol_args_v2,
- transid), ptr, sizeof(*ptr)))
- ret = -EFAULT;
- } else {
- vol_args = memdup_user(arg, sizeof(*vol_args));
- if (IS_ERR(vol_args))
- return PTR_ERR(vol_args);
- name = vol_args->name;
- fd = vol_args->fd;
- vol_args->name[BTRFS_PATH_NAME_MAX] = '\0';
-
- ret = btrfs_ioctl_snap_create_transid(file, name, fd,
- subvol, NULL);
+ if (vol_args->flags &
+ ~(BTRFS_SUBVOL_CREATE_ASYNC | BTRFS_SUBVOL_RDONLY)) {
+ ret = -EOPNOTSUPP;
+ goto out;
}
+
+ if (vol_args->flags & BTRFS_SUBVOL_CREATE_ASYNC)
+ ptr = &transid;
+ if (vol_args->flags & BTRFS_SUBVOL_RDONLY)
+ readonly = true;
+
+ ret = btrfs_ioctl_snap_create_transid(file, vol_args->name,
+ vol_args->fd, subvol,
+ ptr, readonly);
+
+ if (ret == 0 && ptr &&
+ copy_to_user(arg +
+ offsetof(struct btrfs_ioctl_vol_args_v2,
+ transid), ptr, sizeof(*ptr)))
+ ret = -EFAULT;
out:
kfree(vol_args);
- kfree(vol_args_v2);
+ return ret;
+}
+static noinline int btrfs_ioctl_subvol_getflags(struct file *file,
+ void __user *arg)
+{
+ struct inode *inode = fdentry(file)->d_inode;
+ struct btrfs_root *root = BTRFS_I(inode)->root;
+ int ret = 0;
+ u64 flags = 0;
+
+ if (inode->i_ino != BTRFS_FIRST_FREE_OBJECTID)
+ return -EINVAL;
+
+ down_read(&root->fs_info->subvol_sem);
+ if (btrfs_root_readonly(root))
+ flags |= BTRFS_SUBVOL_RDONLY;
+ up_read(&root->fs_info->subvol_sem);
+
+ if (copy_to_user(arg, &flags, sizeof(flags)))
+ ret = -EFAULT;
+
+ return ret;
+}
+
+static noinline int btrfs_ioctl_subvol_setflags(struct file *file,
+ void __user *arg)
+{
+ struct inode *inode = fdentry(file)->d_inode;
+ struct btrfs_root *root = BTRFS_I(inode)->root;
+ struct btrfs_trans_handle *trans;
+ u64 root_flags;
+ u64 flags;
+ int ret = 0;
+
+ if (root->fs_info->sb->s_flags & MS_RDONLY)
+ return -EROFS;
+
+ if (inode->i_ino != BTRFS_FIRST_FREE_OBJECTID)
+ return -EINVAL;
+
+ if (copy_from_user(&flags, arg, sizeof(flags)))
+ return -EFAULT;
+
+ if (flags & ~BTRFS_SUBVOL_CREATE_ASYNC)
+ return -EINVAL;
+
+ if (flags & ~BTRFS_SUBVOL_RDONLY)
+ return -EOPNOTSUPP;
+
+ down_write(&root->fs_info->subvol_sem);
+
+ /* nothing to do */
+ if (!!(flags & BTRFS_SUBVOL_RDONLY) == btrfs_root_readonly(root))
+ goto out;
+
+ root_flags = btrfs_root_flags(&root->root_item);
+ if (flags & BTRFS_SUBVOL_RDONLY)
+ btrfs_set_root_flags(&root->root_item,
+ root_flags | BTRFS_ROOT_SUBVOL_RDONLY);
+ else
+ btrfs_set_root_flags(&root->root_item,
+ root_flags & ~BTRFS_ROOT_SUBVOL_RDONLY);
+
+ trans = btrfs_start_transaction(root, 1);
+ if (IS_ERR(trans)) {
+ ret = PTR_ERR(trans);
+ goto out_reset;
+ }
+
+ ret = btrfs_update_root(trans, root,
+ &root->root_key, &root->root_item);
+
+ btrfs_commit_transaction(trans, root);
+out_reset:
+ if (ret)
+ btrfs_set_root_flags(&root->root_item, root_flags);
+out:
+ up_write(&root->fs_info->subvol_sem);
return ret;
}
@@ -1509,6 +1613,9 @@ static int btrfs_ioctl_defrag(struct file *file, void __user *argp)
struct btrfs_ioctl_defrag_range_args *range;
int ret;
+ if (btrfs_root_readonly(root))
+ return -EROFS;
+
ret = mnt_want_write(file->f_path.mnt);
if (ret)
return ret;
@@ -1637,6 +1744,9 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd,
if (!(file->f_mode & FMODE_WRITE) || (file->f_flags & O_APPEND))
return -EINVAL;
+ if (btrfs_root_readonly(root))
+ return -EROFS;
+
ret = mnt_want_write(file->f_path.mnt);
if (ret)
return ret;
@@ -1958,6 +2068,10 @@ static long btrfs_ioctl_trans_start(struct file *file)
if (file->private_data)
goto out;
+ ret = -EROFS;
+ if (btrfs_root_readonly(root))
+ goto out;
+
ret = mnt_want_write(file->f_path.mnt);
if (ret)
goto out;
@@ -2257,13 +2371,17 @@ long btrfs_ioctl(struct file *file, unsigned int
case FS_IOC_GETVERSION:
return btrfs_ioctl_getversion(file, argp);
case BTRFS_IOC_SNAP_CREATE:
- return btrfs_ioctl_snap_create(file, argp, 0, 0);
+ return btrfs_ioctl_snap_create(file, argp, 0);
case BTRFS_IOC_SNAP_CREATE_V2:
- return btrfs_ioctl_snap_create(file, argp, 0, 1);
+ return btrfs_ioctl_snap_create_v2(file, argp, 0);
case BTRFS_IOC_SUBVOL_CREATE:
- return btrfs_ioctl_snap_create(file, argp, 1, 0);
+ return btrfs_ioctl_snap_create(file, argp, 1);
case BTRFS_IOC_SNAP_DESTROY:
return btrfs_ioctl_snap_destroy(file, argp);
+ case BTRFS_IOC_SUBVOL_GETFLAGS:
+ return btrfs_ioctl_subvol_getflags(file, argp);
+ case BTRFS_IOC_SUBVOL_SETFLAGS:
+ return btrfs_ioctl_subvol_setflags(file, argp);
case BTRFS_IOC_DEFAULT_SUBVOL:
return btrfs_ioctl_default_subvol(file, argp);
case BTRFS_IOC_DEFRAG:
diff --git a/fs/btrfs/ioctl.h b/fs/btrfs/ioctl.h
index c344d12..8fb3821 100644
--- a/fs/btrfs/ioctl.h
+++ b/fs/btrfs/ioctl.h
@@ -31,6 +31,7 @@ struct btrfs_ioctl_vol_args {
};
#define BTRFS_SUBVOL_CREATE_ASYNC (1ULL << 0)
+#define BTRFS_SUBVOL_RDONLY (1ULL << 1)
#define BTRFS_SUBVOL_NAME_MAX 4039
struct btrfs_ioctl_vol_args_v2 {
@@ -133,8 +134,15 @@ struct btrfs_ioctl_defrag_range_args {
*/
__u32 extent_thresh;
+ /*
+ * which compression method to use if turning on compression
+ * for this defrag operation. If unspecified, zlib will
+ * be used
+ */
+ __u32 compress_type;
+
/* spare for later */
- __u32 unused[5];
+ __u32 unused[4];
};
struct btrfs_ioctl_space_info {
@@ -193,4 +201,6 @@ struct btrfs_ioctl_space_args {
#define BTRFS_IOC_WAIT_SYNC _IOW(BTRFS_IOCTL_MAGIC, 22, __u64)
#define BTRFS_IOC_SNAP_CREATE_V2 _IOW(BTRFS_IOCTL_MAGIC, 23, \
struct btrfs_ioctl_vol_args_v2)
+#define BTRFS_IOC_SUBVOL_GETFLAGS _IOW(BTRFS_IOCTL_MAGIC, 25, __u64)
+#define BTRFS_IOC_SUBVOL_SETFLAGS _IOW(BTRFS_IOCTL_MAGIC, 26, __u64)
#endif
diff --git a/fs/btrfs/lzo.c b/fs/btrfs/lzo.c
new file mode 100644
index 0000000..cc9b450
--- /dev/null
+++ b/fs/btrfs/lzo.c
@@ -0,0 +1,420 @@
+/*
+ * Copyright (C) 2008 Oracle. 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 v2 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 021110-1307, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/sched.h>
+#include <linux/pagemap.h>
+#include <linux/bio.h>
+#include <linux/lzo.h>
+#include "compression.h"
+
+#define LZO_LEN 4
+
+struct workspace {
+ void *mem;
+ void *buf; /* where compressed data goes */
+ void *cbuf; /* where decompressed data goes */
+ struct list_head list;
+};
+
+static void lzo_free_workspace(struct list_head *ws)
+{
+ struct workspace *workspace = list_entry(ws, struct workspace, list);
+
+ vfree(workspace->buf);
+ vfree(workspace->cbuf);
+ vfree(workspace->mem);
+ kfree(workspace);
+}
+
+static struct list_head *lzo_alloc_workspace(void)
+{
+ struct workspace *workspace;
+
+ workspace = kzalloc(sizeof(*workspace), GFP_NOFS);
+ if (!workspace)
+ return ERR_PTR(-ENOMEM);
+
+ workspace->mem = vmalloc(LZO1X_MEM_COMPRESS);
+ workspace->buf = vmalloc(lzo1x_worst_compress(PAGE_CACHE_SIZE));
+ workspace->cbuf = vmalloc(lzo1x_worst_compress(PAGE_CACHE_SIZE));
+ if (!workspace->mem || !workspace->buf || !workspace->cbuf)
+ goto fail;
+
+ INIT_LIST_HEAD(&workspace->list);
+
+ return &workspace->list;
+fail:
+ lzo_free_workspace(&workspace->list);
+ return ERR_PTR(-ENOMEM);
+}
+
+static inline void write_compress_length(char *buf, size_t len)
+{
+ __le32 dlen;
+
+ dlen = cpu_to_le32(len);
+ memcpy(buf, &dlen, LZO_LEN);
+}
+
+static inline size_t read_compress_length(char *buf)
+{
+ __le32 dlen;
+
+ memcpy(&dlen, buf, LZO_LEN);
+ return le32_to_cpu(dlen);
+}
+
+static int lzo_compress_pages(struct list_head *ws,
+ struct address_space *mapping,
+ u64 start, unsigned long len,
+ struct page **pages,
+ unsigned long nr_dest_pages,
+ unsigned long *out_pages,
+ unsigned long *total_in,
+ unsigned long *total_out,
+ unsigned long max_out)
+{
+ struct workspace *workspace = list_entry(ws, struct workspace, list);
+ int ret = 0;
+ char *data_in;
+ char *cpage_out;
+ int nr_pages = 0;
+ struct page *in_page = NULL;
+ struct page *out_page = NULL;
+ unsigned long bytes_left;
+
+ size_t in_len;
+ size_t out_len;
+ char *buf;
+ unsigned long tot_in = 0;
+ unsigned long tot_out = 0;
+ unsigned long pg_bytes_left;
+ unsigned long out_offset;
+ unsigned long bytes;
+
+ *out_pages = 0;
+ *total_out = 0;
+ *total_in = 0;
+
+ in_page = find_get_page(mapping, start >> PAGE_CACHE_SHIFT);
+ data_in = kmap(in_page);
+
+ /*
+ * store the size of all chunks of compressed data in
+ * the first 4 bytes
+ */
+ out_page = alloc_page(GFP_NOFS | __GFP_HIGHMEM);
+ if (out_page == NULL) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ cpage_out = kmap(out_page);
+ out_offset = LZO_LEN;
+ tot_out = LZO_LEN;
+ pages[0] = out_page;
+ nr_pages = 1;
+ pg_bytes_left = PAGE_CACHE_SIZE - LZO_LEN;
+
+ /* compress at most one page of data each time */
+ in_len = min(len, PAGE_CACHE_SIZE);
+ while (tot_in < len) {
+ ret = lzo1x_1_compress(data_in, in_len, workspace->cbuf,
+ &out_len, workspace->mem);
+ if (ret != LZO_E_OK) {
+ printk(KERN_DEBUG "btrfs deflate in loop returned %d\n",
+ ret);
+ ret = -1;
+ goto out;
+ }
+
+ /* store the size of this chunk of compressed data */
+ write_compress_length(cpage_out + out_offset, out_len);
+ tot_out += LZO_LEN;
+ out_offset += LZO_LEN;
+ pg_bytes_left -= LZO_LEN;
+
+ tot_in += in_len;
+ tot_out += out_len;
+
+ /* copy bytes from the working buffer into the pages */
+ buf = workspace->cbuf;
+ while (out_len) {
+ bytes = min_t(unsigned long, pg_bytes_left, out_len);
+
+ memcpy(cpage_out + out_offset, buf, bytes);
+
+ out_len -= bytes;
+ pg_bytes_left -= bytes;
+ buf += bytes;
+ out_offset += bytes;
+
+ /*
+ * we need another page for writing out.
+ *
+ * Note if there's less than 4 bytes left, we just
+ * skip to a new page.
+ */
+ if ((out_len == 0 && pg_bytes_left < LZO_LEN) ||
+ pg_bytes_left == 0) {
+ if (pg_bytes_left) {
+ memset(cpage_out + out_offset, 0,
+ pg_bytes_left);
+ tot_out += pg_bytes_left;
+ }
+
+ /* we're done, don't allocate new page */
+ if (out_len == 0 && tot_in >= len)
+ break;
+
+ kunmap(out_page);
+ if (nr_pages == nr_dest_pages) {
+ out_page = NULL;
+ ret = -1;
+ goto out;
+ }
+
+ out_page = alloc_page(GFP_NOFS | __GFP_HIGHMEM);
+ if (out_page == NULL) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ cpage_out = kmap(out_page);
+ pages[nr_pages++] = out_page;
+
+ pg_bytes_left = PAGE_CACHE_SIZE;
+ out_offset = 0;
+ }
+ }
+
+ /* we're making it bigger, give up */
+ if (tot_in > 8192 && tot_in < tot_out)
+ goto out;
+
+ /* we're all done */
+ if (tot_in >= len)
+ break;
+
+ if (tot_out > max_out)
+ break;
+
+ bytes_left = len - tot_in;
+ kunmap(in_page);
+ page_cache_release(in_page);
+
+ start += PAGE_CACHE_SIZE;
+ in_page = find_get_page(mapping, start >> PAGE_CACHE_SHIFT);
+ data_in = kmap(in_page);
+ in_len = min(bytes_left, PAGE_CACHE_SIZE);
+ }
+
+ if (tot_out > tot_in)
+ goto out;
+
+ /* store the size of all chunks of compressed data */
+ cpage_out = kmap(pages[0]);
+ write_compress_length(cpage_out, tot_out);
+
+ kunmap(pages[0]);
+
+ ret = 0;
+ *total_out = tot_out;
+ *total_in = tot_in;
+out:
+ *out_pages = nr_pages;
+ if (out_page)
+ kunmap(out_page);
+
+ if (in_page) {
+ kunmap(in_page);
+ page_cache_release(in_page);
+ }
+
+ return ret;
+}
+
+static int lzo_decompress_biovec(struct list_head *ws,
+ struct page **pages_in,
+ u64 disk_start,
+ struct bio_vec *bvec,
+ int vcnt,
+ size_t srclen)
+{
+ struct workspace *workspace = list_entry(ws, struct workspace, list);
+ int ret = 0, ret2;
+ char *data_in;
+ unsigned long page_in_index = 0;
+ unsigned long page_out_index = 0;
+ unsigned long total_pages_in = (srclen + PAGE_CACHE_SIZE - 1) /
+ PAGE_CACHE_SIZE;
+ unsigned long buf_start;
+ unsigned long buf_offset = 0;
+ unsigned long bytes;
+ unsigned long working_bytes;
+ unsigned long pg_offset;
+
+ size_t in_len;
+ size_t out_len;
+ unsigned long in_offset;
+ unsigned long in_page_bytes_left;
+ unsigned long tot_in;
+ unsigned long tot_out;
+ unsigned long tot_len;
+ char *buf;
+
+ data_in = kmap(pages_in[0]);
+ tot_len = read_compress_length(data_in);
+
+ tot_in = LZO_LEN;
+ in_offset = LZO_LEN;
+ tot_len = min_t(size_t, srclen, tot_len);
+ in_page_bytes_left = PAGE_CACHE_SIZE - LZO_LEN;
+
+ tot_out = 0;
+ pg_offset = 0;
+
+ while (tot_in < tot_len) {
+ in_len = read_compress_length(data_in + in_offset);
+ in_page_bytes_left -= LZO_LEN;
+ in_offset += LZO_LEN;
+ tot_in += LZO_LEN;
+
+ tot_in += in_len;
+ working_bytes = in_len;
+
+ /* fast path: avoid using the working buffer */
+ if (in_page_bytes_left >= in_len) {
+ buf = data_in + in_offset;
+ bytes = in_len;
+ goto cont;
+ }
+
+ /* copy bytes from the pages into the working buffer */
+ buf = workspace->cbuf;
+ buf_offset = 0;
+ while (working_bytes) {
+ bytes = min(working_bytes, in_page_bytes_left);
+
+ memcpy(buf + buf_offset, data_in + in_offset, bytes);
+ buf_offset += bytes;
+cont:
+ working_bytes -= bytes;
+ in_page_bytes_left -= bytes;
+ in_offset += bytes;
+
+ /* check if we need to pick another page */
+ if ((working_bytes == 0 && in_page_bytes_left < LZO_LEN)
+ || in_page_bytes_left == 0) {
+ tot_in += in_page_bytes_left;
+
+ if (working_bytes == 0 && tot_in >= tot_len)
+ break;
+
+ kunmap(pages_in[page_in_index]);
+ page_in_index++;
+ if (page_in_index >= total_pages_in) {
+ ret = -1;
+ data_in = NULL;
+ goto done;
+ }
+ data_in = kmap(pages_in[page_in_index]);
+
+ in_page_bytes_left = PAGE_CACHE_SIZE;
+ in_offset = 0;
+ }
+ }
+
+ out_len = lzo1x_worst_compress(PAGE_CACHE_SIZE);
+ ret = lzo1x_decompress_safe(buf, in_len, workspace->buf,
+ &out_len);
+ if (ret != LZO_E_OK) {
+ printk(KERN_WARNING "btrfs decompress failed\n");
+ ret = -1;
+ break;
+ }
+
+ buf_start = tot_out;
+ tot_out += out_len;
+
+ ret2 = btrfs_decompress_buf2page(workspace->buf, buf_start,
+ tot_out, disk_start,
+ bvec, vcnt,
+ &page_out_index, &pg_offset);
+ if (ret2 == 0)
+ break;
+ }
+done:
+ if (data_in)
+ kunmap(pages_in[page_in_index]);
+ return ret;
+}
+
+static int lzo_decompress(struct list_head *ws, unsigned char *data_in,
+ struct page *dest_page,
+ unsigned long start_byte,
+ size_t srclen, size_t destlen)
+{
+ struct workspace *workspace = list_entry(ws, struct workspace, list);
+ size_t in_len;
+ size_t out_len;
+ size_t tot_len;
+ int ret = 0;
+ char *kaddr;
+ unsigned long bytes;
+
+ BUG_ON(srclen < LZO_LEN);
+
+ tot_len = read_compress_length(data_in);
+ data_in += LZO_LEN;
+
+ in_len = read_compress_length(data_in);
+ data_in += LZO_LEN;
+
+ out_len = PAGE_CACHE_SIZE;
+ ret = lzo1x_decompress_safe(data_in, in_len, workspace->buf, &out_len);
+ if (ret != LZO_E_OK) {
+ printk(KERN_WARNING "btrfs decompress failed!\n");
+ ret = -1;
+ goto out;
+ }
+
+ if (out_len < start_byte) {
+ ret = -1;
+ goto out;
+ }
+
+ bytes = min_t(unsigned long, destlen, out_len - start_byte);
+
+ kaddr = kmap_atomic(dest_page, KM_USER0);
+ memcpy(kaddr, workspace->buf + start_byte, bytes);
+ kunmap_atomic(kaddr, KM_USER0);
+out:
+ return ret;
+}
+
+struct btrfs_compress_op btrfs_lzo_compress = {
+ .alloc_workspace = lzo_alloc_workspace,
+ .free_workspace = lzo_free_workspace,
+ .compress_pages = lzo_compress_pages,
+ .decompress_biovec = lzo_decompress_biovec,
+ .decompress = lzo_decompress,
+};
diff --git a/fs/btrfs/ordered-data.c b/fs/btrfs/ordered-data.c
index ae7737e..2b61e1d 100644
--- a/fs/btrfs/ordered-data.c
+++ b/fs/btrfs/ordered-data.c
@@ -172,7 +172,7 @@ static inline struct rb_node *tree_search(struct btrfs_ordered_inode_tree *tree,
*/
static int __btrfs_add_ordered_extent(struct inode *inode, u64 file_offset,
u64 start, u64 len, u64 disk_len,
- int type, int dio)
+ int type, int dio, int compress_type)
{
struct btrfs_ordered_inode_tree *tree;
struct rb_node *node;
@@ -189,6 +189,7 @@ static int __btrfs_add_ordered_extent(struct inode *inode, u64 file_offset,
entry->disk_len = disk_len;
entry->bytes_left = len;
entry->inode = inode;
+ entry->compress_type = compress_type;
if (type != BTRFS_ORDERED_IO_DONE && type != BTRFS_ORDERED_COMPLETE)
set_bit(type, &entry->flags);
@@ -220,14 +221,25 @@ int btrfs_add_ordered_extent(struct inode *inode, u64 file_offset,
u64 start, u64 len, u64 disk_len, int type)
{
return __btrfs_add_ordered_extent(inode, file_offset, start, len,
- disk_len, type, 0);
+ disk_len, type, 0,
+ BTRFS_COMPRESS_NONE);
}
int btrfs_add_ordered_extent_dio(struct inode *inode, u64 file_offset,
u64 start, u64 len, u64 disk_len, int type)
{
return __btrfs_add_ordered_extent(inode, file_offset, start, len,
- disk_len, type, 1);
+ disk_len, type, 1,
+ BTRFS_COMPRESS_NONE);
+}
+
+int btrfs_add_ordered_extent_compress(struct inode *inode, u64 file_offset,
+ u64 start, u64 len, u64 disk_len,
+ int type, int compress_type)
+{
+ return __btrfs_add_ordered_extent(inode, file_offset, start, len,
+ disk_len, type, 0,
+ compress_type);
}
/*
diff --git a/fs/btrfs/ordered-data.h b/fs/btrfs/ordered-data.h
index 61dca83..ff1f69a 100644
--- a/fs/btrfs/ordered-data.h
+++ b/fs/btrfs/ordered-data.h
@@ -68,7 +68,7 @@ struct btrfs_ordered_sum {
#define BTRFS_ORDERED_NOCOW 2 /* set when we want to write in place */
-#define BTRFS_ORDERED_COMPRESSED 3 /* writing a compressed extent */
+#define BTRFS_ORDERED_COMPRESSED 3 /* writing a zlib compressed extent */
#define BTRFS_ORDERED_PREALLOC 4 /* set when writing to prealloced extent */
@@ -93,6 +93,9 @@ struct btrfs_ordered_extent {
/* flags (described above) */
unsigned long flags;
+ /* compression algorithm */
+ int compress_type;
+
/* reference count */
atomic_t refs;
@@ -148,6 +151,9 @@ int btrfs_add_ordered_extent(struct inode *inode, u64 file_offset,
u64 start, u64 len, u64 disk_len, int type);
int btrfs_add_ordered_extent_dio(struct inode *inode, u64 file_offset,
u64 start, u64 len, u64 disk_len, int type);
+int btrfs_add_ordered_extent_compress(struct inode *inode, u64 file_offset,
+ u64 start, u64 len, u64 disk_len,
+ int type, int compress_type);
int btrfs_add_ordered_sum(struct inode *inode,
struct btrfs_ordered_extent *entry,
struct btrfs_ordered_sum *sum);
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
index 22acdaa..b2130c4 100644
--- a/fs/btrfs/super.c
+++ b/fs/btrfs/super.c
@@ -54,6 +54,90 @@
static const struct super_operations btrfs_super_ops;
+static const char *btrfs_decode_error(struct btrfs_fs_info *fs_info, int errno,
+ char nbuf[16])
+{
+ char *errstr = NULL;
+
+ switch (errno) {
+ case -EIO:
+ errstr = "IO failure";
+ break;
+ case -ENOMEM:
+ errstr = "Out of memory";
+ break;
+ case -EROFS:
+ errstr = "Readonly filesystem";
+ break;
+ default:
+ if (nbuf) {
+ if (snprintf(nbuf, 16, "error %d", -errno) >= 0)
+ errstr = nbuf;
+ }
+ break;
+ }
+
+ return errstr;
+}
+
+static void __save_error_info(struct btrfs_fs_info *fs_info)
+{
+ /*
+ * today we only save the error info into ram. Long term we'll
+ * also send it down to the disk
+ */
+ fs_info->fs_state = BTRFS_SUPER_FLAG_ERROR;
+}
+
+/* NOTE:
+ * We move write_super stuff at umount in order to avoid deadlock
+ * for umount hold all lock.
+ */
+static void save_error_info(struct btrfs_fs_info *fs_info)
+{
+ __save_error_info(fs_info);
+}
+
+/* btrfs handle error by forcing the filesystem readonly */
+static void btrfs_handle_error(struct btrfs_fs_info *fs_info)
+{
+ struct super_block *sb = fs_info->sb;
+
+ if (sb->s_flags & MS_RDONLY)
+ return;
+
+ if (fs_info->fs_state & BTRFS_SUPER_FLAG_ERROR) {
+ sb->s_flags |= MS_RDONLY;
+ printk(KERN_INFO "btrfs is forced readonly\n");
+ }
+}
+
+/*
+ * __btrfs_std_error decodes expected errors from the caller and
+ * invokes the approciate error response.
+ */
+void __btrfs_std_error(struct btrfs_fs_info *fs_info, const char *function,
+ unsigned int line, int errno)
+{
+ struct super_block *sb = fs_info->sb;
+ char nbuf[16];
+ const char *errstr;
+
+ /*
+ * Special case: if the error is EROFS, and we're already
+ * under MS_RDONLY, then it is safe here.
+ */
+ if (errno == -EROFS && (sb->s_flags & MS_RDONLY))
+ return;
+
+ errstr = btrfs_decode_error(fs_info, errno, nbuf);
+ printk(KERN_CRIT "BTRFS error (device %s) in %s:%d: %s\n",
+ sb->s_id, function, line, errstr);
+ save_error_info(fs_info);
+
+ btrfs_handle_error(fs_info);
+}
+
static void btrfs_put_super(struct super_block *sb)
{
struct btrfs_root *root = btrfs_sb(sb);
@@ -69,9 +153,9 @@ enum {
Opt_degraded, Opt_subvol, Opt_subvolid, Opt_device, Opt_nodatasum,
Opt_nodatacow, Opt_max_inline, Opt_alloc_start, Opt_nobarrier, Opt_ssd,
Opt_nossd, Opt_ssd_spread, Opt_thread_pool, Opt_noacl, Opt_compress,
- Opt_compress_force, Opt_notreelog, Opt_ratio, Opt_flushoncommit,
- Opt_discard, Opt_space_cache, Opt_clear_cache, Opt_err,
- Opt_user_subvol_rm_allowed,
+ Opt_compress_type, Opt_compress_force, Opt_compress_force_type,
+ Opt_notreelog, Opt_ratio, Opt_flushoncommit, Opt_discard,
+ Opt_space_cache, Opt_clear_cache, Opt_user_subvol_rm_allowed, Opt_err,
};
static match_table_t tokens = {
@@ -86,7 +170,9 @@ static match_table_t tokens = {
{Opt_alloc_start, "alloc_start=%s"},
{Opt_thread_pool, "thread_pool=%d"},
{Opt_compress, "compress"},
+ {Opt_compress_type, "compress=%s"},
{Opt_compress_force, "compress-force"},
+ {Opt_compress_force_type, "compress-force=%s"},
{Opt_ssd, "ssd"},
{Opt_ssd_spread, "ssd_spread"},
{Opt_nossd, "nossd"},
@@ -112,6 +198,8 @@ int btrfs_parse_options(struct btrfs_root *root, char *options)
char *p, *num, *orig;
int intarg;
int ret = 0;
+ char *compress_type;
+ bool compress_force = false;
if (!options)
return 0;
@@ -154,14 +242,32 @@ int btrfs_parse_options(struct btrfs_root *root, char *options)
btrfs_set_opt(info->mount_opt, NODATACOW);
btrfs_set_opt(info->mount_opt, NODATASUM);
break;
- case Opt_compress:
- printk(KERN_INFO "btrfs: use compression\n");
- btrfs_set_opt(info->mount_opt, COMPRESS);
- break;
case Opt_compress_force:
- printk(KERN_INFO "btrfs: forcing compression\n");
- btrfs_set_opt(info->mount_opt, FORCE_COMPRESS);
+ case Opt_compress_force_type:
+ compress_force = true;
+ case Opt_compress:
+ case Opt_compress_type:
+ if (token == Opt_compress ||
+ token == Opt_compress_force ||
+ strcmp(args[0].from, "zlib") == 0) {
+ compress_type = "zlib";
+ info->compress_type = BTRFS_COMPRESS_ZLIB;
+ } else if (strcmp(args[0].from, "lzo") == 0) {
+ compress_type = "lzo";
+ info->compress_type = BTRFS_COMPRESS_LZO;
+ } else {
+ ret = -EINVAL;
+ goto out;
+ }
+
btrfs_set_opt(info->mount_opt, COMPRESS);
+ if (compress_force) {
+ btrfs_set_opt(info->mount_opt, FORCE_COMPRESS);
+ pr_info("btrfs: force %s compression\n",
+ compress_type);
+ } else
+ pr_info("btrfs: use %s compression\n",
+ compress_type);
break;
case Opt_ssd:
printk(KERN_INFO "btrfs: use ssd allocation scheme\n");
@@ -753,6 +859,127 @@ static int btrfs_remount(struct super_block *sb, int *flags, char *data)
return 0;
}
+/*
+ * The helper to calc the free space on the devices that can be used to store
+ * file data.
+ */
+static int btrfs_calc_avail_data_space(struct btrfs_root *root, u64 *free_bytes)
+{
+ struct btrfs_fs_info *fs_info = root->fs_info;
+ struct btrfs_device_info *devices_info;
+ struct btrfs_fs_devices *fs_devices = fs_info->fs_devices;
+ struct btrfs_device *device;
+ u64 skip_space;
+ u64 type;
+ u64 avail_space;
+ u64 used_space;
+ u64 min_stripe_size;
+ int min_stripes = 1;
+ int i = 0, nr_devices;
+ int ret;
+
+ nr_devices = fs_info->fs_devices->rw_devices;
+ BUG_ON(!nr_devices);
+
+ devices_info = kmalloc(sizeof(*devices_info) * nr_devices,
+ GFP_NOFS);
+ if (!devices_info)
+ return -ENOMEM;
+
+ /* calc min stripe number for data space alloction */
+ type = btrfs_get_alloc_profile(root, 1);
+ if (type & BTRFS_BLOCK_GROUP_RAID0)
+ min_stripes = 2;
+ else if (type & BTRFS_BLOCK_GROUP_RAID1)
+ min_stripes = 2;
+ else if (type & BTRFS_BLOCK_GROUP_RAID10)
+ min_stripes = 4;
+
+ if (type & BTRFS_BLOCK_GROUP_DUP)
+ min_stripe_size = 2 * BTRFS_STRIPE_LEN;
+ else
+ min_stripe_size = BTRFS_STRIPE_LEN;
+
+ list_for_each_entry(device, &fs_devices->alloc_list, dev_alloc_list) {
+ if (!device->in_fs_metadata)
+ continue;
+
+ avail_space = device->total_bytes - device->bytes_used;
+
+ /* align with stripe_len */
+ do_div(avail_space, BTRFS_STRIPE_LEN);
+ avail_space *= BTRFS_STRIPE_LEN;
+
+ /*
+ * In order to avoid overwritting the superblock on the drive,
+ * btrfs starts at an offset of at least 1MB when doing chunk
+ * allocation.
+ */
+ skip_space = 1024 * 1024;
+
+ /* user can set the offset in fs_info->alloc_start. */
+ if (fs_info->alloc_start + BTRFS_STRIPE_LEN <=
+ device->total_bytes)
+ skip_space = max(fs_info->alloc_start, skip_space);
+
+ /*
+ * btrfs can not use the free space in [0, skip_space - 1],
+ * we must subtract it from the total. In order to implement
+ * it, we account the used space in this range first.
+ */
+ ret = btrfs_account_dev_extents_size(device, 0, skip_space - 1,
+ &used_space);
+ if (ret) {
+ kfree(devices_info);
+ return ret;
+ }
+
+ /* calc the free space in [0, skip_space - 1] */
+ skip_space -= used_space;
+
+ /*
+ * we can use the free space in [0, skip_space - 1], subtract
+ * it from the total.
+ */
+ if (avail_space && avail_space >= skip_space)
+ avail_space -= skip_space;
+ else
+ avail_space = 0;
+
+ if (avail_space < min_stripe_size)
+ continue;
+
+ devices_info[i].dev = device;
+ devices_info[i].max_avail = avail_space;
+
+ i++;
+ }
+
+ nr_devices = i;
+
+ btrfs_descending_sort_devices(devices_info, nr_devices);
+
+ i = nr_devices - 1;
+ avail_space = 0;
+ while (nr_devices >= min_stripes) {
+ if (devices_info[i].max_avail >= min_stripe_size) {
+ int j;
+ u64 alloc_size;
+
+ avail_space += devices_info[i].max_avail * min_stripes;
+ alloc_size = devices_info[i].max_avail;
+ for (j = i + 1 - min_stripes; j <= i; j++)
+ devices_info[j].max_avail -= alloc_size;
+ }
+ i--;
+ nr_devices--;
+ }
+
+ kfree(devices_info);
+ *free_bytes = avail_space;
+ return 0;
+}
+
static int btrfs_statfs(struct dentry *dentry, struct kstatfs *buf)
{
struct btrfs_root *root = btrfs_sb(dentry->d_sb);
@@ -760,17 +987,21 @@ static int btrfs_statfs(struct dentry *dentry, struct kstatfs *buf)
struct list_head *head = &root->fs_info->space_info;
struct btrfs_space_info *found;
u64 total_used = 0;
- u64 total_used_data = 0;
+ u64 total_free_data = 0;
int bits = dentry->d_sb->s_blocksize_bits;
__be32 *fsid = (__be32 *)root->fs_info->fsid;
+ int ret;
+ /* holding chunk_muext to avoid allocating new chunks */
+ mutex_lock(&root->fs_info->chunk_mutex);
rcu_read_lock();
list_for_each_entry_rcu(found, head, list) {
- if (found->flags & (BTRFS_BLOCK_GROUP_METADATA |
- BTRFS_BLOCK_GROUP_SYSTEM))
- total_used_data += found->disk_total;
- else
- total_used_data += found->disk_used;
+ if (found->flags & BTRFS_BLOCK_GROUP_DATA) {
+ total_free_data += found->disk_total - found->disk_used;
+ total_free_data -=
+ btrfs_account_ro_block_groups_free_space(found);
+ }
+
total_used += found->disk_used;
}
rcu_read_unlock();
@@ -778,9 +1009,17 @@ static int btrfs_statfs(struct dentry *dentry, struct kstatfs *buf)
buf->f_namelen = BTRFS_NAME_LEN;
buf->f_blocks = btrfs_super_total_bytes(disk_super) >> bits;
buf->f_bfree = buf->f_blocks - (total_used >> bits);
- buf->f_bavail = buf->f_blocks - (total_used_data >> bits);
buf->f_bsize = dentry->d_sb->s_blocksize;
buf->f_type = BTRFS_SUPER_MAGIC;
+ buf->f_bavail = total_free_data;
+ ret = btrfs_calc_avail_data_space(root, &total_free_data);
+ if (ret) {
+ mutex_unlock(&root->fs_info->chunk_mutex);
+ return ret;
+ }
+ buf->f_bavail += total_free_data;
+ buf->f_bavail = buf->f_bavail >> bits;
+ mutex_unlock(&root->fs_info->chunk_mutex);
/* We treat it as constant endianness (it doesn't matter _which_)
because we want the fsid to come out the same whether mounted
@@ -897,10 +1136,14 @@ static int __init init_btrfs_fs(void)
if (err)
return err;
- err = btrfs_init_cachep();
+ err = btrfs_init_compress();
if (err)
goto free_sysfs;
+ err = btrfs_init_cachep();
+ if (err)
+ goto free_compress;
+
err = extent_io_init();
if (err)
goto free_cachep;
@@ -928,6 +1171,8 @@ free_extent_io:
extent_io_exit();
free_cachep:
btrfs_destroy_cachep();
+free_compress:
+ btrfs_exit_compress();
free_sysfs:
btrfs_exit_sysfs();
return err;
@@ -942,7 +1187,7 @@ static void __exit exit_btrfs_fs(void)
unregister_filesystem(&btrfs_fs_type);
btrfs_exit_sysfs();
btrfs_cleanup_fs_uuids();
- btrfs_zlib_exit();
+ btrfs_exit_compress();
}
module_init(init_btrfs_fs)
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c
index f50e931..bae5c7b 100644
--- a/fs/btrfs/transaction.c
+++ b/fs/btrfs/transaction.c
@@ -181,6 +181,9 @@ static struct btrfs_trans_handle *start_transaction(struct btrfs_root *root,
struct btrfs_trans_handle *h;
struct btrfs_transaction *cur_trans;
int ret;
+
+ if (root->fs_info->fs_state & BTRFS_SUPER_FLAG_ERROR)
+ return ERR_PTR(-EROFS);
again:
h = kmem_cache_alloc(btrfs_trans_handle_cachep, GFP_NOFS);
if (!h)
@@ -910,6 +913,7 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
u64 to_reserve = 0;
u64 index = 0;
u64 objectid;
+ u64 root_flags;
new_root_item = kmalloc(sizeof(*new_root_item), GFP_NOFS);
if (!new_root_item) {
@@ -967,6 +971,13 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
btrfs_set_root_last_snapshot(&root->root_item, trans->transid);
memcpy(new_root_item, &root->root_item, sizeof(*new_root_item));
+ root_flags = btrfs_root_flags(new_root_item);
+ if (pending->readonly)
+ root_flags |= BTRFS_ROOT_SUBVOL_RDONLY;
+ else
+ root_flags &= ~BTRFS_ROOT_SUBVOL_RDONLY;
+ btrfs_set_root_flags(new_root_item, root_flags);
+
old = btrfs_lock_root_node(root);
btrfs_cow_block(trans, root, old, NULL, 0, &old);
btrfs_set_lock_blocking(old);
diff --git a/fs/btrfs/transaction.h b/fs/btrfs/transaction.h
index f104b57..229a594 100644
--- a/fs/btrfs/transaction.h
+++ b/fs/btrfs/transaction.h
@@ -62,6 +62,7 @@ struct btrfs_pending_snapshot {
struct btrfs_block_rsv block_rsv;
/* extra metadata reseration for relocation */
int error;
+ bool readonly;
struct list_head list;
};
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index 1718e1a..d158530 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -22,6 +22,7 @@
#include <linux/blkdev.h>
#include <linux/random.h>
#include <linux/iocontext.h>
+#include <linux/capability.h>
#include <asm/div64.h>
#include "compat.h"
#include "ctree.h"
@@ -600,8 +601,10 @@ static int __btrfs_open_devices(struct btrfs_fs_devices *fs_devices,
set_blocksize(bdev, 4096);
bh = btrfs_read_dev_super(bdev);
- if (!bh)
+ if (!bh) {
+ ret = -EINVAL;
goto error_close;
+ }
disk_super = (struct btrfs_super_block *)bh->b_data;
devid = btrfs_stack_device_id(&disk_super->dev_item);
@@ -703,7 +706,7 @@ int btrfs_scan_one_device(const char *path, fmode_t flags, void *holder,
goto error_close;
bh = btrfs_read_dev_super(bdev);
if (!bh) {
- ret = -EIO;
+ ret = -EINVAL;
goto error_close;
}
disk_super = (struct btrfs_super_block *)bh->b_data;
@@ -729,59 +732,167 @@ error:
return ret;
}
+/* helper to account the used device space in the range */
+int btrfs_account_dev_extents_size(struct btrfs_device *device, u64 start,
+ u64 end, u64 *length)
+{
+ struct btrfs_key key;
+ struct btrfs_root *root = device->dev_root;
+ struct btrfs_dev_extent *dev_extent;
+ struct btrfs_path *path;
+ u64 extent_end;
+ int ret;
+ int slot;
+ struct extent_buffer *l;
+
+ *length = 0;
+
+ if (start >= device->total_bytes)
+ return 0;
+
+ path = btrfs_alloc_path();
+ if (!path)
+ return -ENOMEM;
+ path->reada = 2;
+
+ key.objectid = device->devid;
+ key.offset = start;
+ key.type = BTRFS_DEV_EXTENT_KEY;
+
+ ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
+ if (ret < 0)
+ goto out;
+ if (ret > 0) {
+ ret = btrfs_previous_item(root, path, key.objectid, key.type);
+ if (ret < 0)
+ goto out;
+ }
+
+ while (1) {
+ l = path->nodes[0];
+ slot = path->slots[0];
+ if (slot >= btrfs_header_nritems(l)) {
+ ret = btrfs_next_leaf(root, path);
+ if (ret == 0)
+ continue;
+ if (ret < 0)
+ goto out;
+
+ break;
+ }
+ btrfs_item_key_to_cpu(l, &key, slot);
+
+ if (key.objectid < device->devid)
+ goto next;
+
+ if (key.objectid > device->devid)
+ break;
+
+ if (btrfs_key_type(&key) != BTRFS_DEV_EXTENT_KEY)
+ goto next;
+
+ dev_extent = btrfs_item_ptr(l, slot, struct btrfs_dev_extent);
+ extent_end = key.offset + btrfs_dev_extent_length(l,
+ dev_extent);
+ if (key.offset <= start && extent_end > end) {
+ *length = end - start + 1;
+ break;
+ } else if (key.offset <= start && extent_end > start)
+ *length += extent_end - start;
+ else if (key.offset > start && extent_end <= end)
+ *length += extent_end - key.offset;
+ else if (key.offset > start && key.offset <= end) {
+ *length += end - key.offset + 1;
+ break;
+ } else if (key.offset > end)
+ break;
+
+next:
+ path->slots[0]++;
+ }
+ ret = 0;
+out:
+ btrfs_free_path(path);
+ return ret;
+}
+
/*
+ * find_free_dev_extent - find free space in the specified device
+ * @trans: transaction handler
+ * @device: the device which we search the free space in
+ * @num_bytes: the size of the free space that we need
+ * @start: store the start of the free space.
+ * @len: the size of the free space. that we find, or the size of the max
+ * free space if we don't find suitable free space
+ *
* this uses a pretty simple search, the expectation is that it is
* called very infrequently and that a given device has a small number
* of extents
+ *
+ * @start is used to store the start of the free space if we find. But if we
+ * don't find suitable free space, it will be used to store the start position
+ * of the max free space.
+ *
+ * @len is used to store the size of the free space that we find.
+ * But if we don't find suitable free space, it is used to store the size of
+ * the max free space.
*/
int find_free_dev_extent(struct btrfs_trans_handle *trans,
struct btrfs_device *device, u64 num_bytes,
- u64 *start, u64 *max_avail)
+ u64 *start, u64 *len)
{
struct btrfs_key key;
struct btrfs_root *root = device->dev_root;
- struct btrfs_dev_extent *dev_extent = NULL;
+ struct btrfs_dev_extent *dev_extent;
struct btrfs_path *path;
- u64 hole_size = 0;
- u64 last_byte = 0;
- u64 search_start = 0;
+ u64 hole_size;
+ u64 max_hole_start;
+ u64 max_hole_size;
+ u64 extent_end;
+ u64 search_start;
u64 search_end = device->total_bytes;
int ret;
- int slot = 0;
- int start_found;
+ int slot;
struct extent_buffer *l;
- path = btrfs_alloc_path();
- if (!path)
- return -ENOMEM;
- path->reada = 2;
- start_found = 0;
-
/* FIXME use last free of some kind */
/* we don't want to overwrite the superblock on the drive,
* so we make sure to start at an offset of at least 1MB
*/
- search_start = max((u64)1024 * 1024, search_start);
+ search_start = 1024 * 1024;
- if (root->fs_info->alloc_start + num_bytes <= device->total_bytes)
+ if (root->fs_info->alloc_start + num_bytes <= search_end)
search_start = max(root->fs_info->alloc_start, search_start);
+ max_hole_start = search_start;
+ max_hole_size = 0;
+
+ if (search_start >= search_end) {
+ ret = -ENOSPC;
+ goto error;
+ }
+
+ path = btrfs_alloc_path();
+ if (!path) {
+ ret = -ENOMEM;
+ goto error;
+ }
+ path->reada = 2;
+
key.objectid = device->devid;
key.offset = search_start;
key.type = BTRFS_DEV_EXTENT_KEY;
+
ret = btrfs_search_slot(trans, root, &key, path, 0, 0);
if (ret < 0)
- goto error;
+ goto out;
if (ret > 0) {
ret = btrfs_previous_item(root, path, key.objectid, key.type);
if (ret < 0)
- goto error;
- if (ret > 0)
- start_found = 1;
+ goto out;
}
- l = path->nodes[0];
- btrfs_item_key_to_cpu(l, &key, path->slots[0]);
+
while (1) {
l = path->nodes[0];
slot = path->slots[0];
@@ -790,24 +901,9 @@ int find_free_dev_extent(struct btrfs_trans_handle *trans,
if (ret == 0)
continue;
if (ret < 0)
- goto error;
-no_more_items:
- if (!start_found) {
- if (search_start >= search_end) {
- ret = -ENOSPC;
- goto error;
- }
- *start = search_start;
- start_found = 1;
- goto check_pending;
- }
- *start = last_byte > search_start ?
- last_byte : search_start;
- if (search_end <= *start) {
- ret = -ENOSPC;
- goto error;
- }
- goto check_pending;
+ goto out;
+
+ break;
}
btrfs_item_key_to_cpu(l, &key, slot);
@@ -815,48 +911,62 @@ no_more_items:
goto next;
if (key.objectid > device->devid)
- goto no_more_items;
+ break;
- if (key.offset >= search_start && key.offset > last_byte &&
- start_found) {
- if (last_byte < search_start)
- last_byte = search_start;
- hole_size = key.offset - last_byte;
+ if (btrfs_key_type(&key) != BTRFS_DEV_EXTENT_KEY)
+ goto next;
- if (hole_size > *max_avail)
- *max_avail = hole_size;
+ if (key.offset > search_start) {
+ hole_size = key.offset - search_start;
- if (key.offset > last_byte &&
- hole_size >= num_bytes) {
- *start = last_byte;
- goto check_pending;
+ if (hole_size > max_hole_size) {
+ max_hole_start = search_start;
+ max_hole_size = hole_size;
+ }
+
+ /*
+ * If this free space is greater than which we need,
+ * it must be the max free space that we have found
+ * until now, so max_hole_start must point to the start
+ * of this free space and the length of this free space
+ * is stored in max_hole_size. Thus, we return
+ * max_hole_start and max_hole_size and go back to the
+ * caller.
+ */
+ if (hole_size >= num_bytes) {
+ ret = 0;
+ goto out;
}
}
- if (btrfs_key_type(&key) != BTRFS_DEV_EXTENT_KEY)
- goto next;
- start_found = 1;
dev_extent = btrfs_item_ptr(l, slot, struct btrfs_dev_extent);
- last_byte = key.offset + btrfs_dev_extent_length(l, dev_extent);
+ extent_end = key.offset + btrfs_dev_extent_length(l,
+ dev_extent);
+ if (extent_end > search_start)
+ search_start = extent_end;
next:
path->slots[0]++;
cond_resched();
}
-check_pending:
- /* we have to make sure we didn't find an extent that has already
- * been allocated by the map tree or the original allocation
- */
- BUG_ON(*start < search_start);
- if (*start + num_bytes > search_end) {
- ret = -ENOSPC;
- goto error;
+ hole_size = search_end- search_start;
+ if (hole_size > max_hole_size) {
+ max_hole_start = search_start;
+ max_hole_size = hole_size;
}
- /* check for pending inserts here */
- ret = 0;
-error:
+ /* See above. */
+ if (hole_size < num_bytes)
+ ret = -ENOSPC;
+ else
+ ret = 0;
+
+out:
btrfs_free_path(path);
+error:
+ *start = max_hole_start;
+ if (len)
+ *len = max_hole_size;
return ret;
}
@@ -1196,7 +1306,7 @@ int btrfs_rm_device(struct btrfs_root *root, char *device_path)
set_blocksize(bdev, 4096);
bh = btrfs_read_dev_super(bdev);
if (!bh) {
- ret = -EIO;
+ ret = -EINVAL;
goto error_close;
}
disk_super = (struct btrfs_super_block *)bh->b_data;
@@ -1916,6 +2026,9 @@ int btrfs_balance(struct btrfs_root *dev_root)
if (dev_root->fs_info->sb->s_flags & MS_RDONLY)
return -EROFS;
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+
mutex_lock(&dev_root->fs_info->volume_mutex);
dev_root = dev_root->fs_info->dev_root;
@@ -2154,66 +2267,67 @@ static noinline u64 chunk_bytes_by_type(u64 type, u64 calc_size,
return calc_size * num_stripes;
}
-static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
- struct btrfs_root *extent_root,
- struct map_lookup **map_ret,
- u64 *num_bytes, u64 *stripe_size,
- u64 start, u64 type)
+/* Used to sort the devices by max_avail(descending sort) */
+int btrfs_cmp_device_free_bytes(const void *dev_info1, const void *dev_info2)
{
- struct btrfs_fs_info *info = extent_root->fs_info;
- struct btrfs_device *device = NULL;
- struct btrfs_fs_devices *fs_devices = info->fs_devices;
- struct list_head *cur;
- struct map_lookup *map = NULL;
- struct extent_map_tree *em_tree;
- struct extent_map *em;
- struct list_head private_devs;
- int min_stripe_size = 1 * 1024 * 1024;
- u64 calc_size = 1024 * 1024 * 1024;
- u64 max_chunk_size = calc_size;
- u64 min_free;
- u64 avail;
- u64 max_avail = 0;
- u64 dev_offset;
- int num_stripes = 1;
- int min_stripes = 1;
- int sub_stripes = 0;
- int looped = 0;
- int ret;
- int index;
- int stripe_len = 64 * 1024;
+ if (((struct btrfs_device_info *)dev_info1)->max_avail >
+ ((struct btrfs_device_info *)dev_info2)->max_avail)
+ return -1;
+ else if (((struct btrfs_device_info *)dev_info1)->max_avail <
+ ((struct btrfs_device_info *)dev_info2)->max_avail)
+ return 1;
+ else
+ return 0;
+}
- if ((type & BTRFS_BLOCK_GROUP_RAID1) &&
- (type & BTRFS_BLOCK_GROUP_DUP)) {
- WARN_ON(1);
- type &= ~BTRFS_BLOCK_GROUP_DUP;
- }
- if (list_empty(&fs_devices->alloc_list))
- return -ENOSPC;
+static int __btrfs_calc_nstripes(struct btrfs_fs_devices *fs_devices, u64 type,
+ int *num_stripes, int *min_stripes,
+ int *sub_stripes)
+{
+ *num_stripes = 1;
+ *min_stripes = 1;
+ *sub_stripes = 0;
if (type & (BTRFS_BLOCK_GROUP_RAID0)) {
- num_stripes = fs_devices->rw_devices;
- min_stripes = 2;
+ *num_stripes = fs_devices->rw_devices;
+ *min_stripes = 2;
}
if (type & (BTRFS_BLOCK_GROUP_DUP)) {
- num_stripes = 2;
- min_stripes = 2;
+ *num_stripes = 2;
+ *min_stripes = 2;
}
if (type & (BTRFS_BLOCK_GROUP_RAID1)) {
if (fs_devices->rw_devices < 2)
return -ENOSPC;
- num_stripes = 2;
- min_stripes = 2;
+ *num_stripes = 2;
+ *min_stripes = 2;
}
if (type & (BTRFS_BLOCK_GROUP_RAID10)) {
- num_stripes = fs_devices->rw_devices;
- if (num_stripes < 4)
+ *num_stripes = fs_devices->rw_devices;
+ if (*num_stripes < 4)
return -ENOSPC;
- num_stripes &= ~(u32)1;
- sub_stripes = 2;
- min_stripes = 4;
+ *num_stripes &= ~(u32)1;
+ *sub_stripes = 2;
+ *min_stripes = 4;
}
+ return 0;
+}
+
+static u64 __btrfs_calc_stripe_size(struct btrfs_fs_devices *fs_devices,
+ u64 proposed_size, u64 type,
+ int num_stripes, int small_stripe)
+{
+ int min_stripe_size = 1 * 1024 * 1024;
+ u64 calc_size = proposed_size;
+ u64 max_chunk_size = calc_size;
+ int ncopies = 1;
+
+ if (type & (BTRFS_BLOCK_GROUP_RAID1 |
+ BTRFS_BLOCK_GROUP_DUP |
+ BTRFS_BLOCK_GROUP_RAID10))
+ ncopies = 2;
+
if (type & BTRFS_BLOCK_GROUP_DATA) {
max_chunk_size = 10 * calc_size;
min_stripe_size = 64 * 1024 * 1024;
@@ -2230,51 +2344,209 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
max_chunk_size = min(div_factor(fs_devices->total_rw_bytes, 1),
max_chunk_size);
-again:
- max_avail = 0;
- if (!map || map->num_stripes != num_stripes) {
- kfree(map);
- map = kmalloc(map_lookup_size(num_stripes), GFP_NOFS);
- if (!map)
- return -ENOMEM;
- map->num_stripes = num_stripes;
- }
-
- if (calc_size * num_stripes > max_chunk_size) {
- calc_size = max_chunk_size;
+ if (calc_size * num_stripes > max_chunk_size * ncopies) {
+ calc_size = max_chunk_size * ncopies;
do_div(calc_size, num_stripes);
- do_div(calc_size, stripe_len);
- calc_size *= stripe_len;
+ do_div(calc_size, BTRFS_STRIPE_LEN);
+ calc_size *= BTRFS_STRIPE_LEN;
}
/* we don't want tiny stripes */
- if (!looped)
+ if (!small_stripe)
calc_size = max_t(u64, min_stripe_size, calc_size);
/*
- * we're about to do_div by the stripe_len so lets make sure
+ * we're about to do_div by the BTRFS_STRIPE_LEN so lets make sure
* we end up with something bigger than a stripe
*/
- calc_size = max_t(u64, calc_size, stripe_len * 4);
+ calc_size = max_t(u64, calc_size, BTRFS_STRIPE_LEN);
+
+ do_div(calc_size, BTRFS_STRIPE_LEN);
+ calc_size *= BTRFS_STRIPE_LEN;
+
+ return calc_size;
+}
+
+static struct map_lookup *__shrink_map_lookup_stripes(struct map_lookup *map,
+ int num_stripes)
+{
+ struct map_lookup *new;
+ size_t len = map_lookup_size(num_stripes);
+
+ BUG_ON(map->num_stripes < num_stripes);
+
+ if (map->num_stripes == num_stripes)
+ return map;
+
+ new = kmalloc(len, GFP_NOFS);
+ if (!new) {
+ /* just change map->num_stripes */
+ map->num_stripes = num_stripes;
+ return map;
+ }
+
+ memcpy(new, map, len);
+ new->num_stripes = num_stripes;
+ kfree(map);
+ return new;
+}
+
+/*
+ * helper to allocate device space from btrfs_device_info, in which we stored
+ * max free space information of every device. It is used when we can not
+ * allocate chunks by default size.
+ *
+ * By this helper, we can allocate a new chunk as larger as possible.
+ */
+static int __btrfs_alloc_tiny_space(struct btrfs_trans_handle *trans,
+ struct btrfs_fs_devices *fs_devices,
+ struct btrfs_device_info *devices,
+ int nr_device, u64 type,
+ struct map_lookup **map_lookup,
+ int min_stripes, u64 *stripe_size)
+{
+ int i, index, sort_again = 0;
+ int min_devices = min_stripes;
+ u64 max_avail, min_free;
+ struct map_lookup *map = *map_lookup;
+ int ret;
+
+ if (nr_device < min_stripes)
+ return -ENOSPC;
+
+ btrfs_descending_sort_devices(devices, nr_device);
+
+ max_avail = devices[0].max_avail;
+ if (!max_avail)
+ return -ENOSPC;
+
+ for (i = 0; i < nr_device; i++) {
+ /*
+ * if dev_offset = 0, it means the free space of this device
+ * is less than what we need, and we didn't search max avail
+ * extent on this device, so do it now.
+ */
+ if (!devices[i].dev_offset) {
+ ret = find_free_dev_extent(trans, devices[i].dev,
+ max_avail,
+ &devices[i].dev_offset,
+ &devices[i].max_avail);
+ if (ret != 0 && ret != -ENOSPC)
+ return ret;
+ sort_again = 1;
+ }
+ }
+
+ /* we update the max avail free extent of each devices, sort again */
+ if (sort_again)
+ btrfs_descending_sort_devices(devices, nr_device);
+
+ if (type & BTRFS_BLOCK_GROUP_DUP)
+ min_devices = 1;
+
+ if (!devices[min_devices - 1].max_avail)
+ return -ENOSPC;
+
+ max_avail = devices[min_devices - 1].max_avail;
+ if (type & BTRFS_BLOCK_GROUP_DUP)
+ do_div(max_avail, 2);
+
+ max_avail = __btrfs_calc_stripe_size(fs_devices, max_avail, type,
+ min_stripes, 1);
+ if (type & BTRFS_BLOCK_GROUP_DUP)
+ min_free = max_avail * 2;
+ else
+ min_free = max_avail;
+
+ if (min_free > devices[min_devices - 1].max_avail)
+ return -ENOSPC;
+
+ map = __shrink_map_lookup_stripes(map, min_stripes);
+ *stripe_size = max_avail;
+
+ index = 0;
+ for (i = 0; i < min_stripes; i++) {
+ map->stripes[i].dev = devices[index].dev;
+ map->stripes[i].physical = devices[index].dev_offset;
+ if (type & BTRFS_BLOCK_GROUP_DUP) {
+ i++;
+ map->stripes[i].dev = devices[index].dev;
+ map->stripes[i].physical = devices[index].dev_offset +
+ max_avail;
+ }
+ index++;
+ }
+ *map_lookup = map;
+
+ return 0;
+}
- do_div(calc_size, stripe_len);
- calc_size *= stripe_len;
+static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
+ struct btrfs_root *extent_root,
+ struct map_lookup **map_ret,
+ u64 *num_bytes, u64 *stripe_size,
+ u64 start, u64 type)
+{
+ struct btrfs_fs_info *info = extent_root->fs_info;
+ struct btrfs_device *device = NULL;
+ struct btrfs_fs_devices *fs_devices = info->fs_devices;
+ struct list_head *cur;
+ struct map_lookup *map;
+ struct extent_map_tree *em_tree;
+ struct extent_map *em;
+ struct btrfs_device_info *devices_info;
+ struct list_head private_devs;
+ u64 calc_size = 1024 * 1024 * 1024;
+ u64 min_free;
+ u64 avail;
+ u64 dev_offset;
+ int num_stripes;
+ int min_stripes;
+ int sub_stripes;
+ int min_devices; /* the min number of devices we need */
+ int i;
+ int ret;
+ int index;
+
+ if ((type & BTRFS_BLOCK_GROUP_RAID1) &&
+ (type & BTRFS_BLOCK_GROUP_DUP)) {
+ WARN_ON(1);
+ type &= ~BTRFS_BLOCK_GROUP_DUP;
+ }
+ if (list_empty(&fs_devices->alloc_list))
+ return -ENOSPC;
+
+ ret = __btrfs_calc_nstripes(fs_devices, type, &num_stripes,
+ &min_stripes, &sub_stripes);
+ if (ret)
+ return ret;
+
+ devices_info = kzalloc(sizeof(*devices_info) * fs_devices->rw_devices,
+ GFP_NOFS);
+ if (!devices_info)
+ return -ENOMEM;
+
+ map = kmalloc(map_lookup_size(num_stripes), GFP_NOFS);
+ if (!map) {
+ ret = -ENOMEM;
+ goto error;
+ }
+ map->num_stripes = num_stripes;
cur = fs_devices->alloc_list.next;
index = 0;
+ i = 0;
- if (type & BTRFS_BLOCK_GROUP_DUP)
+ calc_size = __btrfs_calc_stripe_size(fs_devices, calc_size, type,
+ num_stripes, 0);
+
+ if (type & BTRFS_BLOCK_GROUP_DUP) {
min_free = calc_size * 2;
- else
+ min_devices = 1;
+ } else {
min_free = calc_size;
-
- /*
- * we add 1MB because we never use the first 1MB of the device, unless
- * we've looped, then we are likely allocating the maximum amount of
- * space left already
- */
- if (!looped)
- min_free += 1024 * 1024;
+ min_devices = min_stripes;
+ }
INIT_LIST_HEAD(&private_devs);
while (index < num_stripes) {
@@ -2287,27 +2559,39 @@ again:
cur = cur->next;
if (device->in_fs_metadata && avail >= min_free) {
- ret = find_free_dev_extent(trans, device,
- min_free, &dev_offset,
- &max_avail);
+ ret = find_free_dev_extent(trans, device, min_free,
+ &devices_info[i].dev_offset,
+ &devices_info[i].max_avail);
if (ret == 0) {
list_move_tail(&device->dev_alloc_list,
&private_devs);
map->stripes[index].dev = device;
- map->stripes[index].physical = dev_offset;
+ map->stripes[index].physical =
+ devices_info[i].dev_offset;
index++;
if (type & BTRFS_BLOCK_GROUP_DUP) {
map->stripes[index].dev = device;
map->stripes[index].physical =
- dev_offset + calc_size;
+ devices_info[i].dev_offset +
+ calc_size;
index++;
}
- }
- } else if (device->in_fs_metadata && avail > max_avail)
- max_avail = avail;
+ } else if (ret != -ENOSPC)
+ goto error;
+
+ devices_info[i].dev = device;
+ i++;
+ } else if (device->in_fs_metadata &&
+ avail >= BTRFS_STRIPE_LEN) {
+ devices_info[i].dev = device;
+ devices_info[i].max_avail = avail;
+ i++;
+ }
+
if (cur == &fs_devices->alloc_list)
break;
}
+
list_splice(&private_devs, &fs_devices->alloc_list);
if (index < num_stripes) {
if (index >= min_stripes) {
@@ -2316,34 +2600,36 @@ again:
num_stripes /= sub_stripes;
num_stripes *= sub_stripes;
}
- looped = 1;
- goto again;
- }
- if (!looped && max_avail > 0) {
- looped = 1;
- calc_size = max_avail;
- goto again;
+
+ map = __shrink_map_lookup_stripes(map, num_stripes);
+ } else if (i >= min_devices) {
+ ret = __btrfs_alloc_tiny_space(trans, fs_devices,
+ devices_info, i, type,
+ &map, min_stripes,
+ &calc_size);
+ if (ret)
+ goto error;
+ } else {
+ ret = -ENOSPC;
+ goto error;
}
- kfree(map);
- return -ENOSPC;
}
map->sector_size = extent_root->sectorsize;
- map->stripe_len = stripe_len;
- map->io_align = stripe_len;
- map->io_width = stripe_len;
+ map->stripe_len = BTRFS_STRIPE_LEN;
+ map->io_align = BTRFS_STRIPE_LEN;
+ map->io_width = BTRFS_STRIPE_LEN;
map->type = type;
- map->num_stripes = num_stripes;
map->sub_stripes = sub_stripes;
*map_ret = map;
*stripe_size = calc_size;
*num_bytes = chunk_bytes_by_type(type, calc_size,
- num_stripes, sub_stripes);
+ map->num_stripes, sub_stripes);
em = alloc_extent_map(GFP_NOFS);
if (!em) {
- kfree(map);
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto error;
}
em->bdev = (struct block_device *)map;
em->start = start;
@@ -2376,7 +2662,13 @@ again:
index++;
}
+ kfree(devices_info);
return 0;
+
+error:
+ kfree(map);
+ kfree(devices_info);
+ return ret;
}
static int __finish_chunk_alloc(struct btrfs_trans_handle *trans,
diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h
index 1be7810..7fb59d4 100644
--- a/fs/btrfs/volumes.h
+++ b/fs/btrfs/volumes.h
@@ -20,8 +20,11 @@
#define __BTRFS_VOLUMES_
#include <linux/bio.h>
+#include <linux/sort.h>
#include "async-thread.h"
+#define BTRFS_STRIPE_LEN (64 * 1024)
+
struct buffer_head;
struct btrfs_pending_bios {
struct bio *head;
@@ -136,6 +139,30 @@ struct btrfs_multi_bio {
struct btrfs_bio_stripe stripes[];
};
+struct btrfs_device_info {
+ struct btrfs_device *dev;
+ u64 dev_offset;
+ u64 max_avail;
+};
+
+/* Used to sort the devices by max_avail(descending sort) */
+int btrfs_cmp_device_free_bytes(const void *dev_info1, const void *dev_info2);
+
+/*
+ * sort the devices by max_avail, in which max free extent size of each device
+ * is stored.(Descending Sort)
+ */
+static inline void btrfs_descending_sort_devices(
+ struct btrfs_device_info *devices,
+ size_t nr_devices)
+{
+ sort(devices, nr_devices, sizeof(struct btrfs_device_info),
+ btrfs_cmp_device_free_bytes, NULL);
+}
+
+int btrfs_account_dev_extents_size(struct btrfs_device *device, u64 start,
+ u64 end, u64 *length);
+
#define btrfs_multi_bio_size(n) (sizeof(struct btrfs_multi_bio) + \
(sizeof(struct btrfs_bio_stripe) * (n)))
diff --git a/fs/btrfs/xattr.c b/fs/btrfs/xattr.c
index 698fdd2..a577653 100644
--- a/fs/btrfs/xattr.c
+++ b/fs/btrfs/xattr.c
@@ -316,6 +316,15 @@ ssize_t btrfs_getxattr(struct dentry *dentry, const char *name,
int btrfs_setxattr(struct dentry *dentry, const char *name, const void *value,
size_t size, int flags)
{
+ struct btrfs_root *root = BTRFS_I(dentry->d_inode)->root;
+
+ /*
+ * The permission on security.* and system.* is not checked
+ * in permission().
+ */
+ if (btrfs_root_readonly(root))
+ return -EROFS;
+
/*
* If this is a request for a synthetic attribute in the system.*
* namespace use the generic infrastructure to resolve a handler
@@ -336,6 +345,15 @@ int btrfs_setxattr(struct dentry *dentry, const char *name, const void *value,
int btrfs_removexattr(struct dentry *dentry, const char *name)
{
+ struct btrfs_root *root = BTRFS_I(dentry->d_inode)->root;
+
+ /*
+ * The permission on security.* and system.* is not checked
+ * in permission().
+ */
+ if (btrfs_root_readonly(root))
+ return -EROFS;
+
/*
* If this is a request for a synthetic attribute in the system.*
* namespace use the generic infrastructure to resolve a handler
diff --git a/fs/btrfs/zlib.c b/fs/btrfs/zlib.c
index b9cd544..f5ec2d4 100644
--- a/fs/btrfs/zlib.c
+++ b/fs/btrfs/zlib.c
@@ -32,15 +32,6 @@
#include <linux/bio.h>
#include "compression.h"
-/* Plan: call deflate() with avail_in == *sourcelen,
- avail_out = *dstlen - 12 and flush == Z_FINISH.
- If it doesn't manage to finish, call it again with
- avail_in == 0 and avail_out set to the remaining 12
- bytes for it to clean up.
- Q: Is 12 bytes sufficient?
-*/
-#define STREAM_END_SPACE 12
-
struct workspace {
z_stream inf_strm;
z_stream def_strm;
@@ -48,152 +39,51 @@ struct workspace {
struct list_head list;
};
-static LIST_HEAD(idle_workspace);
-static DEFINE_SPINLOCK(workspace_lock);
-static unsigned long num_workspace;
-static atomic_t alloc_workspace = ATOMIC_INIT(0);
-static DECLARE_WAIT_QUEUE_HEAD(workspace_wait);
+static void zlib_free_workspace(struct list_head *ws)
+{
+ struct workspace *workspace = list_entry(ws, struct workspace, list);
-/*
- * this finds an available zlib workspace or allocates a new one
- * NULL or an ERR_PTR is returned if things go bad.
- */
-static struct workspace *find_zlib_workspace(void)
+ vfree(workspace->def_strm.workspace);
+ vfree(workspace->inf_strm.workspace);
+ kfree(workspace->buf);
+ kfree(workspace);
+}
+
+static struct list_head *zlib_alloc_workspace(void)
{
struct workspace *workspace;
- int ret;
- int cpus = num_online_cpus();
-
-again:
- spin_lock(&workspace_lock);
- if (!list_empty(&idle_workspace)) {
- workspace = list_entry(idle_workspace.next, struct workspace,
- list);
- list_del(&workspace->list);
- num_workspace--;
- spin_unlock(&workspace_lock);
- return workspace;
- }
- spin_unlock(&workspace_lock);
- if (atomic_read(&alloc_workspace) > cpus) {
- DEFINE_WAIT(wait);
- prepare_to_wait(&workspace_wait, &wait, TASK_UNINTERRUPTIBLE);
- if (atomic_read(&alloc_workspace) > cpus)
- schedule();
- finish_wait(&workspace_wait, &wait);
- goto again;
- }
- atomic_inc(&alloc_workspace);
workspace = kzalloc(sizeof(*workspace), GFP_NOFS);
- if (!workspace) {
- ret = -ENOMEM;
- goto fail;
- }
+ if (!workspace)
+ return ERR_PTR(-ENOMEM);
workspace->def_strm.workspace = vmalloc(zlib_deflate_workspacesize());
- if (!workspace->def_strm.workspace) {
- ret = -ENOMEM;
- goto fail;
- }
workspace->inf_strm.workspace = vmalloc(zlib_inflate_workspacesize());
- if (!workspace->inf_strm.workspace) {
- ret = -ENOMEM;
- goto fail_inflate;
- }
workspace->buf = kmalloc(PAGE_CACHE_SIZE, GFP_NOFS);
- if (!workspace->buf) {
- ret = -ENOMEM;
- goto fail_kmalloc;
- }
- return workspace;
-
-fail_kmalloc:
- vfree(workspace->inf_strm.workspace);
-fail_inflate:
- vfree(workspace->def_strm.workspace);
-fail:
- kfree(workspace);
- atomic_dec(&alloc_workspace);
- wake_up(&workspace_wait);
- return ERR_PTR(ret);
-}
-
-/*
- * put a workspace struct back on the list or free it if we have enough
- * idle ones sitting around
- */
-static int free_workspace(struct workspace *workspace)
-{
- spin_lock(&workspace_lock);
- if (num_workspace < num_online_cpus()) {
- list_add_tail(&workspace->list, &idle_workspace);
- num_workspace++;
- spin_unlock(&workspace_lock);
- if (waitqueue_active(&workspace_wait))
- wake_up(&workspace_wait);
- return 0;
- }
- spin_unlock(&workspace_lock);
- vfree(workspace->def_strm.workspace);
- vfree(workspace->inf_strm.workspace);
- kfree(workspace->buf);
- kfree(workspace);
+ if (!workspace->def_strm.workspace ||
+ !workspace->inf_strm.workspace || !workspace->buf)
+ goto fail;
- atomic_dec(&alloc_workspace);
- if (waitqueue_active(&workspace_wait))
- wake_up(&workspace_wait);
- return 0;
-}
+ INIT_LIST_HEAD(&workspace->list);
-/*
- * cleanup function for module exit
- */
-static void free_workspaces(void)
-{
- struct workspace *workspace;
- while (!list_empty(&idle_workspace)) {
- workspace = list_entry(idle_workspace.next, struct workspace,
- list);
- list_del(&workspace->list);
- vfree(workspace->def_strm.workspace);
- vfree(workspace->inf_strm.workspace);
- kfree(workspace->buf);
- kfree(workspace);
- atomic_dec(&alloc_workspace);
- }
+ return &workspace->list;
+fail:
+ zlib_free_workspace(&workspace->list);
+ return ERR_PTR(-ENOMEM);
}
-/*
- * given an address space and start/len, compress the bytes.
- *
- * pages are allocated to hold the compressed result and stored
- * in 'pages'
- *
- * out_pages is used to return the number of pages allocated. There
- * may be pages allocated even if we return an error
- *
- * total_in is used to return the number of bytes actually read. It
- * may be smaller then len if we had to exit early because we
- * ran out of room in the pages array or because we cross the
- * max_out threshold.
- *
- * total_out is used to return the total number of compressed bytes
- *
- * max_out tells us the max number of bytes that we're allowed to
- * stuff into pages
- */
-int btrfs_zlib_compress_pages(struct address_space *mapping,
- u64 start, unsigned long len,
- struct page **pages,
- unsigned long nr_dest_pages,
- unsigned long *out_pages,
- unsigned long *total_in,
- unsigned long *total_out,
- unsigned long max_out)
+static int zlib_compress_pages(struct list_head *ws,
+ struct address_space *mapping,
+ u64 start, unsigned long len,
+ struct page **pages,
+ unsigned long nr_dest_pages,
+ unsigned long *out_pages,
+ unsigned long *total_in,
+ unsigned long *total_out,
+ unsigned long max_out)
{
+ struct workspace *workspace = list_entry(ws, struct workspace, list);
int ret;
- struct workspace *workspace;
char *data_in;
char *cpage_out;
int nr_pages = 0;
@@ -205,10 +95,6 @@ int btrfs_zlib_compress_pages(struct address_space *mapping,
*total_out = 0;
*total_in = 0;
- workspace = find_zlib_workspace();
- if (IS_ERR(workspace))
- return -1;
-
if (Z_OK != zlib_deflateInit(&workspace->def_strm, 3)) {
printk(KERN_WARNING "deflateInit failed\n");
ret = -1;
@@ -222,6 +108,10 @@ int btrfs_zlib_compress_pages(struct address_space *mapping,
data_in = kmap(in_page);
out_page = alloc_page(GFP_NOFS | __GFP_HIGHMEM);
+ if (out_page == NULL) {
+ ret = -1;
+ goto out;
+ }
cpage_out = kmap(out_page);
pages[0] = out_page;
nr_pages = 1;
@@ -260,6 +150,10 @@ int btrfs_zlib_compress_pages(struct address_space *mapping,
goto out;
}
out_page = alloc_page(GFP_NOFS | __GFP_HIGHMEM);
+ if (out_page == NULL) {
+ ret = -1;
+ goto out;
+ }
cpage_out = kmap(out_page);
pages[nr_pages] = out_page;
nr_pages++;
@@ -314,55 +208,26 @@ out:
kunmap(in_page);
page_cache_release(in_page);
}
- free_workspace(workspace);
return ret;
}
-/*
- * pages_in is an array of pages with compressed data.
- *
- * disk_start is the starting logical offset of this array in the file
- *
- * bvec is a bio_vec of pages from the file that we want to decompress into
- *
- * vcnt is the count of pages in the biovec
- *
- * srclen is the number of bytes in pages_in
- *
- * The basic idea is that we have a bio that was created by readpages.
- * The pages in the bio are for the uncompressed data, and they may not
- * be contiguous. They all correspond to the range of bytes covered by
- * the compressed extent.
- */
-int btrfs_zlib_decompress_biovec(struct page **pages_in,
- u64 disk_start,
- struct bio_vec *bvec,
- int vcnt,
- size_t srclen)
+static int zlib_decompress_biovec(struct list_head *ws, struct page **pages_in,
+ u64 disk_start,
+ struct bio_vec *bvec,
+ int vcnt,
+ size_t srclen)
{
- int ret = 0;
+ struct workspace *workspace = list_entry(ws, struct workspace, list);
+ int ret = 0, ret2;
int wbits = MAX_WBITS;
- struct workspace *workspace;
char *data_in;
size_t total_out = 0;
- unsigned long page_bytes_left;
unsigned long page_in_index = 0;
unsigned long page_out_index = 0;
- struct page *page_out;
unsigned long total_pages_in = (srclen + PAGE_CACHE_SIZE - 1) /
PAGE_CACHE_SIZE;
unsigned long buf_start;
- unsigned long buf_offset;
- unsigned long bytes;
- unsigned long working_bytes;
unsigned long pg_offset;
- unsigned long start_byte;
- unsigned long current_buf_start;
- char *kaddr;
-
- workspace = find_zlib_workspace();
- if (IS_ERR(workspace))
- return -ENOMEM;
data_in = kmap(pages_in[page_in_index]);
workspace->inf_strm.next_in = data_in;
@@ -372,8 +237,6 @@ int btrfs_zlib_decompress_biovec(struct page **pages_in,
workspace->inf_strm.total_out = 0;
workspace->inf_strm.next_out = workspace->buf;
workspace->inf_strm.avail_out = PAGE_CACHE_SIZE;
- page_out = bvec[page_out_index].bv_page;
- page_bytes_left = PAGE_CACHE_SIZE;
pg_offset = 0;
/* If it's deflate, and it's got no preset dictionary, then
@@ -389,107 +252,29 @@ int btrfs_zlib_decompress_biovec(struct page **pages_in,
if (Z_OK != zlib_inflateInit2(&workspace->inf_strm, wbits)) {
printk(KERN_WARNING "inflateInit failed\n");
- ret = -1;
- goto out;
+ return -1;
}
while (workspace->inf_strm.total_in < srclen) {
ret = zlib_inflate(&workspace->inf_strm, Z_NO_FLUSH);
if (ret != Z_OK && ret != Z_STREAM_END)
break;
- /*
- * buf start is the byte offset we're of the start of
- * our workspace buffer
- */
- buf_start = total_out;
- /* total_out is the last byte of the workspace buffer */
+ buf_start = total_out;
total_out = workspace->inf_strm.total_out;
- working_bytes = total_out - buf_start;
-
- /*
- * start byte is the first byte of the page we're currently
- * copying into relative to the start of the compressed data.
- */
- start_byte = page_offset(page_out) - disk_start;
-
- if (working_bytes == 0) {
- /* we didn't make progress in this inflate
- * call, we're done
- */
- if (ret != Z_STREAM_END)
- ret = -1;
+ /* we didn't make progress in this inflate call, we're done */
+ if (buf_start == total_out)
break;
- }
- /* we haven't yet hit data corresponding to this page */
- if (total_out <= start_byte)
- goto next;
-
- /*
- * the start of the data we care about is offset into
- * the middle of our working buffer
- */
- if (total_out > start_byte && buf_start < start_byte) {
- buf_offset = start_byte - buf_start;
- working_bytes -= buf_offset;
- } else {
- buf_offset = 0;
- }
- current_buf_start = buf_start;
-
- /* copy bytes from the working buffer into the pages */
- while (working_bytes > 0) {
- bytes = min(PAGE_CACHE_SIZE - pg_offset,
- PAGE_CACHE_SIZE - buf_offset);
- bytes = min(bytes, working_bytes);
- kaddr = kmap_atomic(page_out, KM_USER0);
- memcpy(kaddr + pg_offset, workspace->buf + buf_offset,
- bytes);
- kunmap_atomic(kaddr, KM_USER0);
- flush_dcache_page(page_out);
-
- pg_offset += bytes;
- page_bytes_left -= bytes;
- buf_offset += bytes;
- working_bytes -= bytes;
- current_buf_start += bytes;
-
- /* check if we need to pick another page */
- if (page_bytes_left == 0) {
- page_out_index++;
- if (page_out_index >= vcnt) {
- ret = 0;
- goto done;
- }
-
- page_out = bvec[page_out_index].bv_page;
- pg_offset = 0;
- page_bytes_left = PAGE_CACHE_SIZE;
- start_byte = page_offset(page_out) - disk_start;
-
- /*
- * make sure our new page is covered by this
- * working buffer
- */
- if (total_out <= start_byte)
- goto next;
-
- /* the next page in the biovec might not
- * be adjacent to the last page, but it
- * might still be found inside this working
- * buffer. bump our offset pointer
- */
- if (total_out > start_byte &&
- current_buf_start < start_byte) {
- buf_offset = start_byte - buf_start;
- working_bytes = total_out - start_byte;
- current_buf_start = buf_start +
- buf_offset;
- }
- }
+ ret2 = btrfs_decompress_buf2page(workspace->buf, buf_start,
+ total_out, disk_start,
+ bvec, vcnt,
+ &page_out_index, &pg_offset);
+ if (ret2 == 0) {
+ ret = 0;
+ goto done;
}
-next:
+
workspace->inf_strm.next_out = workspace->buf;
workspace->inf_strm.avail_out = PAGE_CACHE_SIZE;
@@ -516,35 +301,21 @@ done:
zlib_inflateEnd(&workspace->inf_strm);
if (data_in)
kunmap(pages_in[page_in_index]);
-out:
- free_workspace(workspace);
return ret;
}
-/*
- * a less complex decompression routine. Our compressed data fits in a
- * single page, and we want to read a single page out of it.
- * start_byte tells us the offset into the compressed data we're interested in
- */
-int btrfs_zlib_decompress(unsigned char *data_in,
- struct page *dest_page,
- unsigned long start_byte,
- size_t srclen, size_t destlen)
+static int zlib_decompress(struct list_head *ws, unsigned char *data_in,
+ struct page *dest_page,
+ unsigned long start_byte,
+ size_t srclen, size_t destlen)
{
+ struct workspace *workspace = list_entry(ws, struct workspace, list);
int ret = 0;
int wbits = MAX_WBITS;
- struct workspace *workspace;
unsigned long bytes_left = destlen;
unsigned long total_out = 0;
char *kaddr;
- if (destlen > PAGE_CACHE_SIZE)
- return -ENOMEM;
-
- workspace = find_zlib_workspace();
- if (IS_ERR(workspace))
- return -ENOMEM;
-
workspace->inf_strm.next_in = data_in;
workspace->inf_strm.avail_in = srclen;
workspace->inf_strm.total_in = 0;
@@ -565,8 +336,7 @@ int btrfs_zlib_decompress(unsigned char *data_in,
if (Z_OK != zlib_inflateInit2(&workspace->inf_strm, wbits)) {
printk(KERN_WARNING "inflateInit failed\n");
- ret = -1;
- goto out;
+ return -1;
}
while (bytes_left > 0) {
@@ -616,12 +386,13 @@ next:
ret = 0;
zlib_inflateEnd(&workspace->inf_strm);
-out:
- free_workspace(workspace);
return ret;
}
-void btrfs_zlib_exit(void)
-{
- free_workspaces();
-}
+struct btrfs_compress_op btrfs_zlib_compress = {
+ .alloc_workspace = zlib_alloc_workspace,
+ .free_workspace = zlib_free_workspace,
+ .compress_pages = zlib_compress_pages,
+ .decompress_biovec = zlib_decompress_biovec,
+ .decompress = zlib_decompress,
+};
diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c
index ede9830..65829d3 100644
--- a/fs/cifs/cifs_debug.c
+++ b/fs/cifs/cifs_debug.c
@@ -79,11 +79,11 @@ void cifs_dump_mids(struct TCP_Server_Info *server)
spin_lock(&GlobalMid_Lock);
list_for_each(tmp, &server->pending_mid_q) {
mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
- cERROR(1, "State: %d Cmd: %d Pid: %d Tsk: %p Mid %d",
+ cERROR(1, "State: %d Cmd: %d Pid: %d Cbdata: %p Mid %d",
mid_entry->midState,
(int)mid_entry->command,
mid_entry->pid,
- mid_entry->tsk,
+ mid_entry->callback_data,
mid_entry->mid);
#ifdef CONFIG_CIFS_STATS2
cERROR(1, "IsLarge: %d buf: %p time rcv: %ld now: %ld",
@@ -218,11 +218,11 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
mid_entry = list_entry(tmp3, struct mid_q_entry,
qhead);
seq_printf(m, "\tState: %d com: %d pid:"
- " %d tsk: %p mid %d\n",
+ " %d cbdata: %p mid %d\n",
mid_entry->midState,
(int)mid_entry->command,
mid_entry->pid,
- mid_entry->tsk,
+ mid_entry->callback_data,
mid_entry->mid);
}
spin_unlock(&GlobalMid_Lock);
@@ -331,7 +331,7 @@ static int cifs_stats_proc_show(struct seq_file *m, void *v)
atomic_read(&totSmBufAllocCount));
#endif /* CONFIG_CIFS_STATS2 */
- seq_printf(m, "Operations (MIDs): %d\n", midCount.counter);
+ seq_printf(m, "Operations (MIDs): %d\n", atomic_read(&midCount));
seq_printf(m,
"\n%d session %d share reconnects\n",
tcpSesReconnectCount.counter, tconInfoReconnectCount.counter);
diff --git a/fs/cifs/cifs_dfs_ref.c b/fs/cifs/cifs_dfs_ref.c
index c68a056..f1c6862 100644
--- a/fs/cifs/cifs_dfs_ref.c
+++ b/fs/cifs/cifs_dfs_ref.c
@@ -255,35 +255,6 @@ static struct vfsmount *cifs_dfs_do_refmount(struct cifs_sb_info *cifs_sb,
}
-static int add_mount_helper(struct vfsmount *newmnt, struct nameidata *nd,
- struct list_head *mntlist)
-{
- /* stolen from afs code */
- int err;
-
- mntget(newmnt);
- err = do_add_mount(newmnt, &nd->path, nd->path.mnt->mnt_flags | MNT_SHRINKABLE, mntlist);
- switch (err) {
- case 0:
- path_put(&nd->path);
- nd->path.mnt = newmnt;
- nd->path.dentry = dget(newmnt->mnt_root);
- schedule_delayed_work(&cifs_dfs_automount_task,
- cifs_dfs_mountpoint_expiry_timeout);
- break;
- case -EBUSY:
- /* someone else made a mount here whilst we were busy */
- while (d_mountpoint(nd->path.dentry) &&
- follow_down(&nd->path))
- ;
- err = 0;
- default:
- mntput(newmnt);
- break;
- }
- return err;
-}
-
static void dump_referral(const struct dfs_info3_param *ref)
{
cFYI(1, "DFS: ref path: %s", ref->path_name);
@@ -293,45 +264,42 @@ static void dump_referral(const struct dfs_info3_param *ref)
ref->path_consumed);
}
-
-static void*
-cifs_dfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd)
+/*
+ * Create a vfsmount that we can automount
+ */
+static struct vfsmount *cifs_dfs_do_automount(struct dentry *mntpt)
{
struct dfs_info3_param *referrals = NULL;
unsigned int num_referrals = 0;
struct cifs_sb_info *cifs_sb;
struct cifsSesInfo *ses;
- char *full_path = NULL;
+ char *full_path;
int xid, i;
- int rc = 0;
- struct vfsmount *mnt = ERR_PTR(-ENOENT);
+ int rc;
+ struct vfsmount *mnt;
struct tcon_link *tlink;
cFYI(1, "in %s", __func__);
- BUG_ON(IS_ROOT(dentry));
+ BUG_ON(IS_ROOT(mntpt));
xid = GetXid();
- dput(nd->path.dentry);
- nd->path.dentry = dget(dentry);
-
/*
* The MSDFS spec states that paths in DFS referral requests and
* responses must be prefixed by a single '\' character instead of
* the double backslashes usually used in the UNC. This function
* gives us the latter, so we must adjust the result.
*/
- full_path = build_path_from_dentry(dentry);
- if (full_path == NULL) {
- rc = -ENOMEM;
- goto out_err;
- }
+ mnt = ERR_PTR(-ENOMEM);
+ full_path = build_path_from_dentry(mntpt);
+ if (full_path == NULL)
+ goto free_xid;
- cifs_sb = CIFS_SB(dentry->d_inode->i_sb);
+ cifs_sb = CIFS_SB(mntpt->d_inode->i_sb);
tlink = cifs_sb_tlink(cifs_sb);
if (IS_ERR(tlink)) {
- rc = PTR_ERR(tlink);
- goto out_err;
+ mnt = ERR_CAST(tlink);
+ goto free_full_path;
}
ses = tlink_tcon(tlink)->ses;
@@ -341,46 +309,63 @@ cifs_dfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd)
cifs_put_tlink(tlink);
+ mnt = ERR_PTR(-ENOENT);
for (i = 0; i < num_referrals; i++) {
int len;
- dump_referral(referrals+i);
+ dump_referral(referrals + i);
/* connect to a node */
len = strlen(referrals[i].node_name);
if (len < 2) {
cERROR(1, "%s: Net Address path too short: %s",
__func__, referrals[i].node_name);
- rc = -EINVAL;
- goto out_err;
+ mnt = ERR_PTR(-EINVAL);
+ break;
}
mnt = cifs_dfs_do_refmount(cifs_sb,
full_path, referrals + i);
cFYI(1, "%s: cifs_dfs_do_refmount:%s , mnt:%p", __func__,
referrals[i].node_name, mnt);
-
- /* complete mount procedure if we accured submount */
if (!IS_ERR(mnt))
- break;
+ goto success;
}
- /* we need it cause for() above could exit without valid submount */
- rc = PTR_ERR(mnt);
- if (IS_ERR(mnt))
- goto out_err;
-
- rc = add_mount_helper(mnt, nd, &cifs_dfs_automount_list);
+ /* no valid submounts were found; return error from get_dfs_path() by
+ * preference */
+ if (rc != 0)
+ mnt = ERR_PTR(rc);
-out:
- FreeXid(xid);
+success:
free_dfs_info_array(referrals, num_referrals);
+free_full_path:
kfree(full_path);
+free_xid:
+ FreeXid(xid);
cFYI(1, "leaving %s" , __func__);
- return ERR_PTR(rc);
-out_err:
- path_put(&nd->path);
- goto out;
+ return mnt;
+}
+
+/*
+ * Attempt to automount the referral
+ */
+struct vfsmount *cifs_dfs_d_automount(struct path *path)
+{
+ struct vfsmount *newmnt;
+
+ cFYI(1, "in %s", __func__);
+
+ newmnt = cifs_dfs_do_automount(path->dentry);
+ if (IS_ERR(newmnt)) {
+ cFYI(1, "leaving %s [automount failed]" , __func__);
+ return newmnt;
+ }
+
+ mntget(newmnt); /* prevent immediate expiration */
+ mnt_set_expiry(newmnt, &cifs_dfs_automount_list);
+ schedule_delayed_work(&cifs_dfs_automount_task,
+ cifs_dfs_mountpoint_expiry_timeout);
+ cFYI(1, "leaving %s [ok]" , __func__);
+ return newmnt;
}
const struct inode_operations cifs_dfs_referral_inode_operations = {
- .follow_link = cifs_dfs_follow_mountpoint,
};
-
diff --git a/fs/cifs/cifs_fs_sb.h b/fs/cifs/cifs_fs_sb.h
index 7852cd6..ac51cd2 100644
--- a/fs/cifs/cifs_fs_sb.h
+++ b/fs/cifs/cifs_fs_sb.h
@@ -40,6 +40,7 @@
#define CIFS_MOUNT_FSCACHE 0x8000 /* local caching enabled */
#define CIFS_MOUNT_MF_SYMLINKS 0x10000 /* Minshall+French Symlinks enabled */
#define CIFS_MOUNT_MULTIUSER 0x20000 /* multiuser mount */
+#define CIFS_MOUNT_STRICT_IO 0x40000 /* strict cache mode */
struct cifs_sb_info {
struct rb_root tlink_tree;
diff --git a/fs/cifs/cifs_unicode.c b/fs/cifs/cifs_unicode.c
index 430f510..fc0fd4f 100644
--- a/fs/cifs/cifs_unicode.c
+++ b/fs/cifs/cifs_unicode.c
@@ -44,10 +44,14 @@ cifs_ucs2_bytes(const __le16 *from, int maxbytes,
int charlen, outlen = 0;
int maxwords = maxbytes / 2;
char tmp[NLS_MAX_CHARSET_SIZE];
+ __u16 ftmp;
- for (i = 0; i < maxwords && from[i]; i++) {
- charlen = codepage->uni2char(le16_to_cpu(from[i]), tmp,
- NLS_MAX_CHARSET_SIZE);
+ for (i = 0; i < maxwords; i++) {
+ ftmp = get_unaligned_le16(&from[i]);
+ if (ftmp == 0)
+ break;
+
+ charlen = codepage->uni2char(ftmp, tmp, NLS_MAX_CHARSET_SIZE);
if (charlen > 0)
outlen += charlen;
else
@@ -58,9 +62,9 @@ cifs_ucs2_bytes(const __le16 *from, int maxbytes,
}
/*
- * cifs_mapchar - convert a little-endian char to proper char in codepage
+ * cifs_mapchar - convert a host-endian char to proper char in codepage
* @target - where converted character should be copied
- * @src_char - 2 byte little-endian source character
+ * @src_char - 2 byte host-endian source character
* @cp - codepage to which character should be converted
* @mapchar - should character be mapped according to mapchars mount option?
*
@@ -69,7 +73,7 @@ cifs_ucs2_bytes(const __le16 *from, int maxbytes,
* enough to hold the result of the conversion (at least NLS_MAX_CHARSET_SIZE).
*/
static int
-cifs_mapchar(char *target, const __le16 src_char, const struct nls_table *cp,
+cifs_mapchar(char *target, const __u16 src_char, const struct nls_table *cp,
bool mapchar)
{
int len = 1;
@@ -82,7 +86,7 @@ cifs_mapchar(char *target, const __le16 src_char, const struct nls_table *cp,
* build_path_from_dentry are modified, as they use slash as
* separator.
*/
- switch (le16_to_cpu(src_char)) {
+ switch (src_char) {
case UNI_COLON:
*target = ':';
break;
@@ -109,8 +113,7 @@ out:
return len;
cp_convert:
- len = cp->uni2char(le16_to_cpu(src_char), target,
- NLS_MAX_CHARSET_SIZE);
+ len = cp->uni2char(src_char, target, NLS_MAX_CHARSET_SIZE);
if (len <= 0) {
*target = '?';
len = 1;
@@ -149,6 +152,7 @@ cifs_from_ucs2(char *to, const __le16 *from, int tolen, int fromlen,
int nullsize = nls_nullsize(codepage);
int fromwords = fromlen / 2;
char tmp[NLS_MAX_CHARSET_SIZE];
+ __u16 ftmp;
/*
* because the chars can be of varying widths, we need to take care
@@ -158,19 +162,23 @@ cifs_from_ucs2(char *to, const __le16 *from, int tolen, int fromlen,
*/
safelen = tolen - (NLS_MAX_CHARSET_SIZE + nullsize);
- for (i = 0; i < fromwords && from[i]; i++) {
+ for (i = 0; i < fromwords; i++) {
+ ftmp = get_unaligned_le16(&from[i]);
+ if (ftmp == 0)
+ break;
+
/*
* check to see if converting this character might make the
* conversion bleed into the null terminator
*/
if (outlen >= safelen) {
- charlen = cifs_mapchar(tmp, from[i], codepage, mapchar);
+ charlen = cifs_mapchar(tmp, ftmp, codepage, mapchar);
if ((outlen + charlen) > (tolen - nullsize))
break;
}
/* put converted char into 'to' buffer */
- charlen = cifs_mapchar(&to[outlen], from[i], codepage, mapchar);
+ charlen = cifs_mapchar(&to[outlen], ftmp, codepage, mapchar);
outlen += charlen;
}
@@ -193,24 +201,21 @@ cifs_strtoUCS(__le16 *to, const char *from, int len,
{
int charlen;
int i;
- wchar_t *wchar_to = (wchar_t *)to; /* needed to quiet sparse */
+ wchar_t wchar_to; /* needed to quiet sparse */
for (i = 0; len && *from; i++, from += charlen, len -= charlen) {
-
- /* works for 2.4.0 kernel or later */
- charlen = codepage->char2uni(from, len, &wchar_to[i]);
+ charlen = codepage->char2uni(from, len, &wchar_to);
if (charlen < 1) {
- cERROR(1, "strtoUCS: char2uni of %d returned %d",
- (int)*from, charlen);
+ cERROR(1, "strtoUCS: char2uni of 0x%x returned %d",
+ *from, charlen);
/* A question mark */
- to[i] = cpu_to_le16(0x003f);
+ wchar_to = 0x003f;
charlen = 1;
- } else
- to[i] = cpu_to_le16(wchar_to[i]);
-
+ }
+ put_unaligned_le16(wchar_to, &to[i]);
}
- to[i] = 0;
+ put_unaligned_le16(0, &to[i]);
return i;
}
@@ -252,3 +257,79 @@ cifs_strndup_from_ucs(const char *src, const int maxlen, const bool is_unicode,
return dst;
}
+/*
+ * Convert 16 bit Unicode pathname to wire format from string in current code
+ * page. Conversion may involve remapping up the six characters that are
+ * only legal in POSIX-like OS (if they are present in the string). Path
+ * names are little endian 16 bit Unicode on the wire
+ */
+int
+cifsConvertToUCS(__le16 *target, const char *source, int maxlen,
+ const struct nls_table *cp, int mapChars)
+{
+ int i, j, charlen;
+ int len_remaining = maxlen;
+ char src_char;
+ __u16 temp;
+
+ if (!mapChars)
+ return cifs_strtoUCS(target, source, PATH_MAX, cp);
+
+ for (i = 0, j = 0; i < maxlen; j++) {
+ src_char = source[i];
+ switch (src_char) {
+ case 0:
+ put_unaligned_le16(0, &target[j]);
+ goto ctoUCS_out;
+ case ':':
+ temp = UNI_COLON;
+ break;
+ case '*':
+ temp = UNI_ASTERIK;
+ break;
+ case '?':
+ temp = UNI_QUESTION;
+ break;
+ case '<':
+ temp = UNI_LESSTHAN;
+ break;
+ case '>':
+ temp = UNI_GRTRTHAN;
+ break;
+ case '|':
+ temp = UNI_PIPE;
+ break;
+ /*
+ * FIXME: We can not handle remapping backslash (UNI_SLASH)
+ * until all the calls to build_path_from_dentry are modified,
+ * as they use backslash as separator.
+ */
+ default:
+ charlen = cp->char2uni(source+i, len_remaining,
+ &temp);
+ /*
+ * if no match, use question mark, which at least in
+ * some cases serves as wild card
+ */
+ if (charlen < 1) {
+ temp = 0x003f;
+ charlen = 1;
+ }
+ len_remaining -= charlen;
+ /*
+ * character may take more than one byte in the source
+ * string, but will take exactly two bytes in the
+ * target string
+ */
+ i += charlen;
+ continue;
+ }
+ put_unaligned_le16(temp, &target[j]);
+ i++; /* move to next char in source string */
+ len_remaining--;
+ }
+
+ctoUCS_out:
+ return i;
+}
+
diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c
index a437ec3..1e7636b 100644
--- a/fs/cifs/cifsacl.c
+++ b/fs/cifs/cifsacl.c
@@ -41,9 +41,12 @@ static struct cifs_wksid wksidarr[NUM_WK_SIDS] = {
;
-/* security id for everyone */
+/* security id for everyone/world system group */
static const struct cifs_sid sid_everyone = {
1, 1, {0, 0, 0, 0, 0, 1}, {0} };
+/* security id for Authenticated Users system group */
+static const struct cifs_sid sid_authusers = {
+ 1, 1, {0, 0, 0, 0, 0, 5}, {11} };
/* group users */
static const struct cifs_sid sid_user = {1, 2 , {0, 0, 0, 0, 0, 5}, {} };
@@ -365,7 +368,7 @@ static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl,
if (num_aces > 0) {
umode_t user_mask = S_IRWXU;
umode_t group_mask = S_IRWXG;
- umode_t other_mask = S_IRWXO;
+ umode_t other_mask = S_IRWXU | S_IRWXG | S_IRWXO;
ppace = kmalloc(num_aces * sizeof(struct cifs_ace *),
GFP_KERNEL);
@@ -390,6 +393,12 @@ static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl,
ppace[i]->type,
&fattr->cf_mode,
&other_mask);
+ if (compare_sids(&(ppace[i]->sid), &sid_authusers))
+ access_flags_to_mode(ppace[i]->access_req,
+ ppace[i]->type,
+ &fattr->cf_mode,
+ &other_mask);
+
/* memcpy((void *)(&(cifscred->aces[i])),
(void *)ppace[i],
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index d9f652a..a8323f1 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -77,7 +77,11 @@ unsigned int cifs_max_pending = CIFS_MAX_REQ;
module_param(cifs_max_pending, int, 0);
MODULE_PARM_DESC(cifs_max_pending, "Simultaneous requests to server. "
"Default: 50 Range: 2 to 256");
-
+unsigned short echo_retries = 5;
+module_param(echo_retries, ushort, 0644);
+MODULE_PARM_DESC(echo_retries, "Number of echo attempts before giving up and "
+ "reconnecting server. Default: 5. 0 means "
+ "never reconnect.");
extern mempool_t *cifs_sm_req_poolp;
extern mempool_t *cifs_req_poolp;
extern mempool_t *cifs_mid_poolp;
@@ -729,6 +733,25 @@ const struct file_operations cifs_file_ops = {
.setlease = cifs_setlease,
};
+const struct file_operations cifs_file_strict_ops = {
+ .read = do_sync_read,
+ .write = do_sync_write,
+ .aio_read = cifs_strict_readv,
+ .aio_write = cifs_file_aio_write,
+ .open = cifs_open,
+ .release = cifs_close,
+ .lock = cifs_lock,
+ .fsync = cifs_strict_fsync,
+ .flush = cifs_flush,
+ .mmap = cifs_file_strict_mmap,
+ .splice_read = generic_file_splice_read,
+ .llseek = cifs_llseek,
+#ifdef CONFIG_CIFS_POSIX
+ .unlocked_ioctl = cifs_ioctl,
+#endif /* CONFIG_CIFS_POSIX */
+ .setlease = cifs_setlease,
+};
+
const struct file_operations cifs_file_direct_ops = {
/* no aio, no readv -
BB reevaluate whether they can be done with directio, no cache */
@@ -747,6 +770,7 @@ const struct file_operations cifs_file_direct_ops = {
.llseek = cifs_llseek,
.setlease = cifs_setlease,
};
+
const struct file_operations cifs_file_nobrl_ops = {
.read = do_sync_read,
.write = do_sync_write,
@@ -765,6 +789,24 @@ const struct file_operations cifs_file_nobrl_ops = {
.setlease = cifs_setlease,
};
+const struct file_operations cifs_file_strict_nobrl_ops = {
+ .read = do_sync_read,
+ .write = do_sync_write,
+ .aio_read = cifs_strict_readv,
+ .aio_write = cifs_file_aio_write,
+ .open = cifs_open,
+ .release = cifs_close,
+ .fsync = cifs_strict_fsync,
+ .flush = cifs_flush,
+ .mmap = cifs_file_strict_mmap,
+ .splice_read = generic_file_splice_read,
+ .llseek = cifs_llseek,
+#ifdef CONFIG_CIFS_POSIX
+ .unlocked_ioctl = cifs_ioctl,
+#endif /* CONFIG_CIFS_POSIX */
+ .setlease = cifs_setlease,
+};
+
const struct file_operations cifs_file_direct_nobrl_ops = {
/* no mmap, no aio, no readv -
BB reevaluate whether they can be done with directio, no cache */
diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h
index 897b2b2..f23206d 100644
--- a/fs/cifs/cifsfs.h
+++ b/fs/cifs/cifsfs.h
@@ -61,6 +61,7 @@ extern int cifs_rename(struct inode *, struct dentry *, struct inode *,
struct dentry *);
extern int cifs_revalidate_file(struct file *filp);
extern int cifs_revalidate_dentry(struct dentry *);
+extern void cifs_invalidate_mapping(struct inode *inode);
extern int cifs_getattr(struct vfsmount *, struct dentry *, struct kstat *);
extern int cifs_setattr(struct dentry *, struct iattr *);
@@ -72,19 +73,25 @@ extern const struct inode_operations cifs_dfs_referral_inode_operations;
/* Functions related to files and directories */
extern const struct file_operations cifs_file_ops;
extern const struct file_operations cifs_file_direct_ops; /* if directio mnt */
-extern const struct file_operations cifs_file_nobrl_ops;
-extern const struct file_operations cifs_file_direct_nobrl_ops; /* no brlocks */
+extern const struct file_operations cifs_file_strict_ops; /* if strictio mnt */
+extern const struct file_operations cifs_file_nobrl_ops; /* no brlocks */
+extern const struct file_operations cifs_file_direct_nobrl_ops;
+extern const struct file_operations cifs_file_strict_nobrl_ops;
extern int cifs_open(struct inode *inode, struct file *file);
extern int cifs_close(struct inode *inode, struct file *file);
extern int cifs_closedir(struct inode *inode, struct file *file);
extern ssize_t cifs_user_read(struct file *file, char __user *read_data,
- size_t read_size, loff_t *poffset);
+ size_t read_size, loff_t *poffset);
+extern ssize_t cifs_strict_readv(struct kiocb *iocb, const struct iovec *iov,
+ unsigned long nr_segs, loff_t pos);
extern ssize_t cifs_user_write(struct file *file, const char __user *write_data,
size_t write_size, loff_t *poffset);
extern int cifs_lock(struct file *, int, struct file_lock *);
extern int cifs_fsync(struct file *, int);
+extern int cifs_strict_fsync(struct file *, int);
extern int cifs_flush(struct file *, fl_owner_t id);
extern int cifs_file_mmap(struct file * , struct vm_area_struct *);
+extern int cifs_file_strict_mmap(struct file * , struct vm_area_struct *);
extern const struct file_operations cifs_dir_ops;
extern int cifs_dir_open(struct inode *inode, struct file *file);
extern int cifs_readdir(struct file *file, void *direntry, filldir_t filldir);
@@ -93,6 +100,12 @@ extern int cifs_readdir(struct file *file, void *direntry, filldir_t filldir);
extern const struct dentry_operations cifs_dentry_ops;
extern const struct dentry_operations cifs_ci_dentry_ops;
+#ifdef CONFIG_CIFS_DFS_UPCALL
+extern struct vfsmount *cifs_dfs_d_automount(struct path *path);
+#else
+#define cifs_dfs_d_automount NULL
+#endif
+
/* Functions related to symlinks */
extern void *cifs_follow_link(struct dentry *direntry, struct nameidata *nd);
extern void cifs_put_link(struct dentry *direntry,
@@ -112,5 +125,5 @@ extern long cifs_ioctl(struct file *filep, unsigned int cmd, unsigned long arg);
extern const struct export_operations cifs_export_ops;
#endif /* EXPERIMENTAL */
-#define CIFS_VERSION "1.68"
+#define CIFS_VERSION "1.69"
#endif /* _CIFSFS_H */
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 606ca8b..edd5b29 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -161,32 +161,27 @@ struct TCP_Server_Info {
int srv_count; /* reference counter */
/* 15 character server name + 0x20 16th byte indicating type = srv */
char server_RFC1001_name[RFC1001_NAME_LEN_WITH_NULL];
+ enum statusEnum tcpStatus; /* what we think the status is */
char *hostname; /* hostname portion of UNC string */
struct socket *ssocket;
struct sockaddr_storage dstaddr;
struct sockaddr_storage srcaddr; /* locally bind to this IP */
+#ifdef CONFIG_NET_NS
+ struct net *net;
+#endif
wait_queue_head_t response_q;
wait_queue_head_t request_q; /* if more than maxmpx to srvr must block*/
struct list_head pending_mid_q;
- void *Server_NlsInfo; /* BB - placeholder for future NLS info */
- unsigned short server_codepage; /* codepage for the server */
- enum protocolEnum protocolType;
- char versionMajor;
- char versionMinor;
- bool svlocal:1; /* local server or remote */
bool noblocksnd; /* use blocking sendmsg */
bool noautotune; /* do not autotune send buf sizes */
bool tcp_nodelay;
atomic_t inFlight; /* number of requests on the wire to server */
-#ifdef CONFIG_CIFS_STATS2
- atomic_t inSend; /* requests trying to send */
- atomic_t num_waiters; /* blocked waiting to get in sendrecv */
-#endif
- enum statusEnum tcpStatus; /* what we think the status is */
struct mutex srv_mutex;
struct task_struct *tsk;
char server_GUID[16];
char secMode;
+ bool session_estab; /* mark when very first sess is established */
+ u16 dialect; /* dialect index that server chose */
enum securityEnum secType;
unsigned int maxReq; /* Clients should submit no more */
/* than maxReq distinct unanswered SMBs to the server when using */
@@ -199,8 +194,6 @@ struct TCP_Server_Info {
unsigned int max_vcs; /* maximum number of smb sessions, at least
those that can be specified uniquely with
vcnumbers */
- char sessid[4]; /* unique token id for this session */
- /* (returned on Negotiate */
int capabilities; /* allow selective disabling of caps by smb sess */
int timeAdj; /* Adjust for difference in server time zone in sec */
__u16 CurrentMid; /* multiplex id - rotating counter */
@@ -210,20 +203,53 @@ struct TCP_Server_Info {
__u32 sequence_number; /* for signing, protected by srv_mutex */
struct session_key session_key;
unsigned long lstrp; /* when we got last response from this server */
- u16 dialect; /* dialect index that server chose */
struct cifs_secmech secmech; /* crypto sec mech functs, descriptors */
/* extended security flavors that server supports */
+ bool sec_ntlmssp; /* supports NTLMSSP */
+ bool sec_kerberosu2u; /* supports U2U Kerberos */
bool sec_kerberos; /* supports plain Kerberos */
bool sec_mskerberos; /* supports legacy MS Kerberos */
- bool sec_kerberosu2u; /* supports U2U Kerberos */
- bool sec_ntlmssp; /* supports NTLMSSP */
- bool session_estab; /* mark when very first sess is established */
+ struct delayed_work echo; /* echo ping workqueue job */
#ifdef CONFIG_CIFS_FSCACHE
struct fscache_cookie *fscache; /* client index cache cookie */
#endif
+#ifdef CONFIG_CIFS_STATS2
+ atomic_t inSend; /* requests trying to send */
+ atomic_t num_waiters; /* blocked waiting to get in sendrecv */
+#endif
};
/*
+ * Macros to allow the TCP_Server_Info->net field and related code to drop out
+ * when CONFIG_NET_NS isn't set.
+ */
+
+#ifdef CONFIG_NET_NS
+
+static inline struct net *cifs_net_ns(struct TCP_Server_Info *srv)
+{
+ return srv->net;
+}
+
+static inline void cifs_set_net_ns(struct TCP_Server_Info *srv, struct net *net)
+{
+ srv->net = net;
+}
+
+#else
+
+static inline struct net *cifs_net_ns(struct TCP_Server_Info *srv)
+{
+ return &init_net;
+}
+
+static inline void cifs_set_net_ns(struct TCP_Server_Info *srv, struct net *net)
+{
+}
+
+#endif
+
+/*
* Session structure. One of these for each uid session with a particular host
*/
struct cifsSesInfo {
@@ -446,11 +472,11 @@ struct cifsInodeInfo {
/* BB add in lists for dirty pages i.e. write caching info for oplock */
struct list_head openFileList;
__u32 cifsAttrs; /* e.g. DOS archive bit, sparse, compressed, system */
- unsigned long time; /* jiffies of last update/check of inode */
- bool clientCanCacheRead:1; /* read oplock */
- bool clientCanCacheAll:1; /* read and writebehind oplock */
- bool delete_pending:1; /* DELETE_ON_CLOSE is set */
- bool invalid_mapping:1; /* pagecache is invalid */
+ bool clientCanCacheRead; /* read oplock */
+ bool clientCanCacheAll; /* read and writebehind oplock */
+ bool delete_pending; /* DELETE_ON_CLOSE is set */
+ bool invalid_mapping; /* pagecache is invalid */
+ unsigned long time; /* jiffies of last update of inode */
u64 server_eof; /* current file size on server */
u64 uniqueid; /* server inode number */
u64 createtime; /* creation time on server */
@@ -508,6 +534,18 @@ static inline void cifs_stats_bytes_read(struct cifsTconInfo *tcon,
#endif
+struct mid_q_entry;
+
+/*
+ * This is the prototype for the mid callback function. When creating one,
+ * take special care to avoid deadlocks. Things to bear in mind:
+ *
+ * - it will be called by cifsd
+ * - the GlobalMid_Lock will be held
+ * - the mid will be removed from the pending_mid_q list
+ */
+typedef void (mid_callback_t)(struct mid_q_entry *mid);
+
/* one of these for every pending CIFS request to the server */
struct mid_q_entry {
struct list_head qhead; /* mids waiting on reply from this server */
@@ -519,7 +557,8 @@ struct mid_q_entry {
unsigned long when_sent; /* time when smb send finished */
unsigned long when_received; /* when demux complete (taken off wire) */
#endif
- struct task_struct *tsk; /* task waiting for response */
+ mid_callback_t *callback; /* call completion callback */
+ void *callback_data; /* general purpose pointer for callback */
struct smb_hdr *resp_buf; /* response buffer */
int midState; /* wish this were enum but can not pass to wait_event */
__u8 command; /* smb command code */
@@ -622,12 +661,9 @@ static inline void free_dfs_info_array(struct dfs_info3_param *param,
#define CIFS_IOVEC 4 /* array of response buffers */
/* Type of Request to SendReceive2 */
-#define CIFS_STD_OP 0 /* normal request timeout */
-#define CIFS_LONG_OP 1 /* long op (up to 45 sec, oplock time) */
-#define CIFS_VLONG_OP 2 /* sloow op - can take up to 180 seconds */
-#define CIFS_BLOCKING_OP 4 /* operation can block */
-#define CIFS_ASYNC_OP 8 /* do not wait for response */
-#define CIFS_TIMEOUT_MASK 0x00F /* only one of 5 above set in req */
+#define CIFS_BLOCKING_OP 1 /* operation can block */
+#define CIFS_ASYNC_OP 2 /* do not wait for response */
+#define CIFS_TIMEOUT_MASK 0x003 /* only one of above set in req */
#define CIFS_LOG_ERROR 0x010 /* log NT STATUS if non-zero */
#define CIFS_LARGE_BUF_OP 0x020 /* large request buffer */
#define CIFS_NO_RESP 0x040 /* no response buffer required */
@@ -790,6 +826,9 @@ GLOBAL_EXTERN unsigned int cifs_min_rcv; /* min size of big ntwrk buf pool */
GLOBAL_EXTERN unsigned int cifs_min_small; /* min size of small buf pool */
GLOBAL_EXTERN unsigned int cifs_max_pending; /* MAX requests at once to server*/
+/* reconnect after this many failed echo attempts */
+GLOBAL_EXTERN unsigned short echo_retries;
+
void cifs_oplock_break(struct work_struct *work);
void cifs_oplock_break_get(struct cifsFileInfo *cfile);
void cifs_oplock_break_put(struct cifsFileInfo *cfile);
diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h
index de36b09..b5c8cc5 100644
--- a/fs/cifs/cifspdu.h
+++ b/fs/cifs/cifspdu.h
@@ -23,6 +23,7 @@
#define _CIFSPDU_H
#include <net/sock.h>
+#include <asm/unaligned.h>
#include "smbfsctl.h"
#ifdef CONFIG_CIFS_WEAK_PW_HASH
@@ -50,6 +51,7 @@
#define SMB_COM_SETATTR 0x09 /* trivial response */
#define SMB_COM_LOCKING_ANDX 0x24 /* trivial response */
#define SMB_COM_COPY 0x29 /* trivial rsp, fail filename ignrd*/
+#define SMB_COM_ECHO 0x2B /* echo request */
#define SMB_COM_OPEN_ANDX 0x2D /* Legacy open for old servers */
#define SMB_COM_READ_ANDX 0x2E
#define SMB_COM_WRITE_ANDX 0x2F
@@ -425,11 +427,49 @@ struct smb_hdr {
__u16 Mid;
__u8 WordCount;
} __attribute__((packed));
-/* given a pointer to an smb_hdr retrieve the value of byte count */
-#define BCC(smb_var) (*(__u16 *)((char *)(smb_var) + sizeof(struct smb_hdr) + (2 * (smb_var)->WordCount)))
-#define BCC_LE(smb_var) (*(__le16 *)((char *)(smb_var) + sizeof(struct smb_hdr) + (2 * (smb_var)->WordCount)))
+
+/* given a pointer to an smb_hdr retrieve a char pointer to the byte count */
+#define BCC(smb_var) ((unsigned char *)(smb_var) + sizeof(struct smb_hdr) + \
+ (2 * (smb_var)->WordCount))
+
/* given a pointer to an smb_hdr retrieve the pointer to the byte area */
-#define pByteArea(smb_var) ((unsigned char *)(smb_var) + sizeof(struct smb_hdr) + (2 * (smb_var)->WordCount) + 2)
+#define pByteArea(smb_var) (BCC(smb_var) + 2)
+
+/* get the converted ByteCount for a SMB packet and return it */
+static inline __u16
+get_bcc(struct smb_hdr *hdr)
+{
+ __u16 *bc_ptr = (__u16 *)BCC(hdr);
+
+ return get_unaligned(bc_ptr);
+}
+
+/* get the unconverted ByteCount for a SMB packet and return it */
+static inline __u16
+get_bcc_le(struct smb_hdr *hdr)
+{
+ __le16 *bc_ptr = (__le16 *)BCC(hdr);
+
+ return get_unaligned_le16(bc_ptr);
+}
+
+/* set the ByteCount for a SMB packet in host-byte order */
+static inline void
+put_bcc(__u16 count, struct smb_hdr *hdr)
+{
+ __u16 *bc_ptr = (__u16 *)BCC(hdr);
+
+ put_unaligned(count, bc_ptr);
+}
+
+/* set the ByteCount for a SMB packet in little-endian */
+static inline void
+put_bcc_le(__u16 count, struct smb_hdr *hdr)
+{
+ __le16 *bc_ptr = (__le16 *)BCC(hdr);
+
+ put_unaligned_le16(count, bc_ptr);
+}
/*
* Computer Name Length (since Netbios name was length 16 with last byte 0x20)
@@ -760,6 +800,20 @@ typedef struct smb_com_tconx_rsp_ext {
*
*/
+typedef struct smb_com_echo_req {
+ struct smb_hdr hdr;
+ __le16 EchoCount;
+ __le16 ByteCount;
+ char Data[1];
+} __attribute__((packed)) ECHO_REQ;
+
+typedef struct smb_com_echo_rsp {
+ struct smb_hdr hdr;
+ __le16 SequenceNumber;
+ __le16 ByteCount;
+ char Data[1];
+} __attribute__((packed)) ECHO_RSP;
+
typedef struct smb_com_logoff_andx_req {
struct smb_hdr hdr; /* wct = 2 */
__u8 AndXCommand;
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index e6d1481..982895f 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -61,6 +61,12 @@ extern char *cifs_compose_mount_options(const char *sb_mountdata,
const char *fullpath, const struct dfs_info3_param *ref,
char **devname);
/* extern void renew_parental_timestamps(struct dentry *direntry);*/
+extern struct mid_q_entry *AllocMidQEntry(const struct smb_hdr *smb_buffer,
+ struct TCP_Server_Info *server);
+extern void DeleteMidQEntry(struct mid_q_entry *midEntry);
+extern int cifs_call_async(struct TCP_Server_Info *server,
+ struct smb_hdr *in_buf, mid_callback_t *callback,
+ void *cbdata);
extern int SendReceive(const unsigned int /* xid */ , struct cifsSesInfo *,
struct smb_hdr * /* input */ ,
struct smb_hdr * /* out */ ,
@@ -347,12 +353,13 @@ extern int CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
const __u16 netfid, const __u64 len,
const __u64 offset, const __u32 numUnlock,
const __u32 numLock, const __u8 lockType,
- const bool waitFlag);
+ const bool waitFlag, const __u8 oplock_level);
extern int CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
const __u16 smb_file_id, const int get_flag,
const __u64 len, struct file_lock *,
const __u16 lock_type, const bool waitFlag);
extern int CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon);
+extern int CIFSSMBEcho(struct TCP_Server_Info *server);
extern int CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses);
extern struct cifsSesInfo *sesInfoAlloc(void);
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index 2f6795e..3106f5e 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -331,37 +331,35 @@ smb_init_no_reconnect(int smb_command, int wct, struct cifsTconInfo *tcon,
static int validate_t2(struct smb_t2_rsp *pSMB)
{
- int rc = -EINVAL;
- int total_size;
- char *pBCC;
+ unsigned int total_size;
+
+ /* check for plausible wct */
+ if (pSMB->hdr.WordCount < 10)
+ goto vt2_err;
- /* check for plausible wct, bcc and t2 data and parm sizes */
/* check for parm and data offset going beyond end of smb */
- if (pSMB->hdr.WordCount >= 10) {
- if ((le16_to_cpu(pSMB->t2_rsp.ParameterOffset) <= 1024) &&
- (le16_to_cpu(pSMB->t2_rsp.DataOffset) <= 1024)) {
- /* check that bcc is at least as big as parms + data */
- /* check that bcc is less than negotiated smb buffer */
- total_size = le16_to_cpu(pSMB->t2_rsp.ParameterCount);
- if (total_size < 512) {
- total_size +=
- le16_to_cpu(pSMB->t2_rsp.DataCount);
- /* BCC le converted in SendReceive */
- pBCC = (pSMB->hdr.WordCount * 2) +
- sizeof(struct smb_hdr) +
- (char *)pSMB;
- if ((total_size <= (*(u16 *)pBCC)) &&
- (total_size <
- CIFSMaxBufSize+MAX_CIFS_HDR_SIZE)) {
- return 0;
- }
- }
- }
- }
+ if (get_unaligned_le16(&pSMB->t2_rsp.ParameterOffset) > 1024 ||
+ get_unaligned_le16(&pSMB->t2_rsp.DataOffset) > 1024)
+ goto vt2_err;
+
+ /* check that bcc is at least as big as parms + data */
+ /* check that bcc is less than negotiated smb buffer */
+ total_size = get_unaligned_le16(&pSMB->t2_rsp.ParameterCount);
+ if (total_size >= 512)
+ goto vt2_err;
+
+ total_size += get_unaligned_le16(&pSMB->t2_rsp.DataCount);
+ if (total_size > get_bcc(&pSMB->hdr) ||
+ total_size >= CIFSMaxBufSize + MAX_CIFS_HDR_SIZE)
+ goto vt2_err;
+
+ return 0;
+vt2_err:
cifs_dump_mem("Invalid transact2 SMB: ", (char *)pSMB,
sizeof(struct smb_t2_rsp) + 16);
- return rc;
+ return -EINVAL;
}
+
int
CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
{
@@ -452,7 +450,6 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
server->maxBuf = min((__u32)le16_to_cpu(rsp->MaxBufSize),
(__u32)CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
server->max_vcs = le16_to_cpu(rsp->MaxNumberVcs);
- GETU32(server->sessid) = le32_to_cpu(rsp->SessionKey);
/* even though we do not use raw we might as well set this
accurately, in case we ever find a need for it */
if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
@@ -566,7 +563,6 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
(__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
server->max_rw = le32_to_cpu(pSMBr->MaxRawSize);
cFYI(DBG2, "Max buf = %d", ses->server->maxBuf);
- GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey);
server->capabilities = le32_to_cpu(pSMBr->Capabilities);
server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
server->timeAdj *= 60;
@@ -706,6 +702,53 @@ CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
return rc;
}
+/*
+ * This is a no-op for now. We're not really interested in the reply, but
+ * rather in the fact that the server sent one and that server->lstrp
+ * gets updated.
+ *
+ * FIXME: maybe we should consider checking that the reply matches request?
+ */
+static void
+cifs_echo_callback(struct mid_q_entry *mid)
+{
+ struct TCP_Server_Info *server = mid->callback_data;
+
+ DeleteMidQEntry(mid);
+ atomic_dec(&server->inFlight);
+ wake_up(&server->request_q);
+}
+
+int
+CIFSSMBEcho(struct TCP_Server_Info *server)
+{
+ ECHO_REQ *smb;
+ int rc = 0;
+
+ cFYI(1, "In echo request");
+
+ rc = small_smb_init(SMB_COM_ECHO, 0, NULL, (void **)&smb);
+ if (rc)
+ return rc;
+
+ /* set up echo request */
+ smb->hdr.Tid = cpu_to_le16(0xffff);
+ smb->hdr.WordCount = 1;
+ put_unaligned_le16(1, &smb->EchoCount);
+ put_bcc_le(1, &smb->hdr);
+ smb->Data[0] = 'a';
+ smb->hdr.smb_buf_length += 3;
+
+ rc = cifs_call_async(server, (struct smb_hdr *)smb,
+ cifs_echo_callback, server);
+ if (rc)
+ cFYI(1, "Echo request failed: %d", rc);
+
+ cifs_small_buf_release(smb);
+
+ return rc;
+}
+
int
CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
{
@@ -1193,7 +1236,7 @@ OldOpenRetry:
pSMB->ByteCount = cpu_to_le16(count);
/* long_op set to 1 to allow for oplock break timeouts */
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
- (struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP);
+ (struct smb_hdr *)pSMBr, &bytes_returned, 0);
cifs_stats_inc(&tcon->num_opens);
if (rc) {
cFYI(1, "Error in Open = %d", rc);
@@ -1306,7 +1349,7 @@ openRetry:
pSMB->ByteCount = cpu_to_le16(count);
/* long_op set to 1 to allow for oplock break timeouts */
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
- (struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP);
+ (struct smb_hdr *)pSMBr, &bytes_returned, 0);
cifs_stats_inc(&tcon->num_opens);
if (rc) {
cFYI(1, "Error in Open = %d", rc);
@@ -1388,7 +1431,7 @@ CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, const int netfid,
iov[0].iov_base = (char *)pSMB;
iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
- &resp_buf_type, CIFS_STD_OP | CIFS_LOG_ERROR);
+ &resp_buf_type, CIFS_LOG_ERROR);
cifs_stats_inc(&tcon->num_reads);
pSMBr = (READ_RSP *)iov[0].iov_base;
if (rc) {
@@ -1663,7 +1706,8 @@ int
CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
const __u16 smb_file_id, const __u64 len,
const __u64 offset, const __u32 numUnlock,
- const __u32 numLock, const __u8 lockType, const bool waitFlag)
+ const __u32 numLock, const __u8 lockType,
+ const bool waitFlag, const __u8 oplock_level)
{
int rc = 0;
LOCK_REQ *pSMB = NULL;
@@ -1691,6 +1735,7 @@ CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
pSMB->NumberOfLocks = cpu_to_le16(numLock);
pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
pSMB->LockType = lockType;
+ pSMB->OplockLevel = oplock_level;
pSMB->AndXCommand = 0xFF; /* none */
pSMB->Fid = smb_file_id; /* netfid stays le */
@@ -3087,7 +3132,7 @@ CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
- CIFS_STD_OP);
+ 0);
cifs_stats_inc(&tcon->num_acl_get);
if (rc) {
cFYI(1, "Send error in QuerySecDesc = %d", rc);
@@ -5562,7 +5607,7 @@ QAllEAsRetry:
}
/* make sure list_len doesn't go past end of SMB */
- end_of_smb = (char *)pByteArea(&pSMBr->hdr) + BCC(&pSMBr->hdr);
+ end_of_smb = (char *)pByteArea(&pSMBr->hdr) + get_bcc(&pSMBr->hdr);
if ((char *)ea_response_data + list_len > end_of_smb) {
cFYI(1, "EA list appears to go beyond SMB");
rc = -EIO;
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index a65d311..0cc3b81 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -52,6 +52,9 @@
#define CIFS_PORT 445
#define RFC1001_PORT 139
+/* SMB echo "timeout" -- FIXME: tunable? */
+#define SMB_ECHO_INTERVAL (60 * HZ)
+
extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8,
unsigned char *p24);
@@ -152,6 +155,7 @@ cifs_reconnect(struct TCP_Server_Info *server)
/* before reconnecting the tcp session, mark the smb session (uid)
and the tid bad so they are not used until reconnected */
+ cFYI(1, "%s: marking sessions and tcons for reconnect", __func__);
spin_lock(&cifs_tcp_ses_lock);
list_for_each(tmp, &server->smb_ses_list) {
ses = list_entry(tmp, struct cifsSesInfo, smb_ses_list);
@@ -163,7 +167,9 @@ cifs_reconnect(struct TCP_Server_Info *server)
}
}
spin_unlock(&cifs_tcp_ses_lock);
+
/* do not want to be sending data on a socket we are freeing */
+ cFYI(1, "%s: tearing down socket", __func__);
mutex_lock(&server->srv_mutex);
if (server->ssocket) {
cFYI(1, "State: 0x%x Flags: 0x%lx", server->ssocket->state,
@@ -180,22 +186,20 @@ cifs_reconnect(struct TCP_Server_Info *server)
kfree(server->session_key.response);
server->session_key.response = NULL;
server->session_key.len = 0;
+ server->lstrp = jiffies;
+ mutex_unlock(&server->srv_mutex);
+ /* mark submitted MIDs for retry and issue callback */
+ cFYI(1, "%s: issuing mid callbacks", __func__);
spin_lock(&GlobalMid_Lock);
- list_for_each(tmp, &server->pending_mid_q) {
- mid_entry = list_entry(tmp, struct
- mid_q_entry,
- qhead);
- if (mid_entry->midState == MID_REQUEST_SUBMITTED) {
- /* Mark other intransit requests as needing
- retry so we do not immediately mark the
- session bad again (ie after we reconnect
- below) as they timeout too */
+ list_for_each_safe(tmp, tmp2, &server->pending_mid_q) {
+ mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
+ if (mid_entry->midState == MID_REQUEST_SUBMITTED)
mid_entry->midState = MID_RETRY_NEEDED;
- }
+ list_del_init(&mid_entry->qhead);
+ mid_entry->callback(mid_entry);
}
spin_unlock(&GlobalMid_Lock);
- mutex_unlock(&server->srv_mutex);
while ((server->tcpStatus != CifsExiting) &&
(server->tcpStatus != CifsGood)) {
@@ -212,10 +216,9 @@ cifs_reconnect(struct TCP_Server_Info *server)
if (server->tcpStatus != CifsExiting)
server->tcpStatus = CifsGood;
spin_unlock(&GlobalMid_Lock);
- /* atomic_set(&server->inFlight,0);*/
- wake_up(&server->response_q);
}
}
+
return rc;
}
@@ -229,9 +232,8 @@ cifs_reconnect(struct TCP_Server_Info *server)
static int check2ndT2(struct smb_hdr *pSMB, unsigned int maxBufSize)
{
struct smb_t2_rsp *pSMBt;
- int total_data_size;
- int data_in_this_rsp;
int remaining;
+ __u16 total_data_size, data_in_this_rsp;
if (pSMB->Command != SMB_COM_TRANSACTION2)
return 0;
@@ -245,8 +247,8 @@ static int check2ndT2(struct smb_hdr *pSMB, unsigned int maxBufSize)
pSMBt = (struct smb_t2_rsp *)pSMB;
- total_data_size = le16_to_cpu(pSMBt->t2_rsp.TotalDataCount);
- data_in_this_rsp = le16_to_cpu(pSMBt->t2_rsp.DataCount);
+ total_data_size = get_unaligned_le16(&pSMBt->t2_rsp.TotalDataCount);
+ data_in_this_rsp = get_unaligned_le16(&pSMBt->t2_rsp.DataCount);
remaining = total_data_size - data_in_this_rsp;
@@ -272,21 +274,18 @@ static int coalesce_t2(struct smb_hdr *psecond, struct smb_hdr *pTargetSMB)
{
struct smb_t2_rsp *pSMB2 = (struct smb_t2_rsp *)psecond;
struct smb_t2_rsp *pSMBt = (struct smb_t2_rsp *)pTargetSMB;
- int total_data_size;
- int total_in_buf;
- int remaining;
- int total_in_buf2;
char *data_area_of_target;
char *data_area_of_buf2;
- __u16 byte_count;
+ int remaining;
+ __u16 byte_count, total_data_size, total_in_buf, total_in_buf2;
- total_data_size = le16_to_cpu(pSMBt->t2_rsp.TotalDataCount);
+ total_data_size = get_unaligned_le16(&pSMBt->t2_rsp.TotalDataCount);
- if (total_data_size != le16_to_cpu(pSMB2->t2_rsp.TotalDataCount)) {
+ if (total_data_size !=
+ get_unaligned_le16(&pSMB2->t2_rsp.TotalDataCount))
cFYI(1, "total data size of primary and secondary t2 differ");
- }
- total_in_buf = le16_to_cpu(pSMBt->t2_rsp.DataCount);
+ total_in_buf = get_unaligned_le16(&pSMBt->t2_rsp.DataCount);
remaining = total_data_size - total_in_buf;
@@ -296,28 +295,28 @@ static int coalesce_t2(struct smb_hdr *psecond, struct smb_hdr *pTargetSMB)
if (remaining == 0) /* nothing to do, ignore */
return 0;
- total_in_buf2 = le16_to_cpu(pSMB2->t2_rsp.DataCount);
+ total_in_buf2 = get_unaligned_le16(&pSMB2->t2_rsp.DataCount);
if (remaining < total_in_buf2) {
cFYI(1, "transact2 2nd response contains too much data");
}
/* find end of first SMB data area */
data_area_of_target = (char *)&pSMBt->hdr.Protocol +
- le16_to_cpu(pSMBt->t2_rsp.DataOffset);
+ get_unaligned_le16(&pSMBt->t2_rsp.DataOffset);
/* validate target area */
- data_area_of_buf2 = (char *) &pSMB2->hdr.Protocol +
- le16_to_cpu(pSMB2->t2_rsp.DataOffset);
+ data_area_of_buf2 = (char *)&pSMB2->hdr.Protocol +
+ get_unaligned_le16(&pSMB2->t2_rsp.DataOffset);
data_area_of_target += total_in_buf;
/* copy second buffer into end of first buffer */
memcpy(data_area_of_target, data_area_of_buf2, total_in_buf2);
total_in_buf += total_in_buf2;
- pSMBt->t2_rsp.DataCount = cpu_to_le16(total_in_buf);
- byte_count = le16_to_cpu(BCC_LE(pTargetSMB));
+ put_unaligned_le16(total_in_buf, &pSMBt->t2_rsp.DataCount);
+ byte_count = get_bcc_le(pTargetSMB);
byte_count += total_in_buf2;
- BCC_LE(pTargetSMB) = cpu_to_le16(byte_count);
+ put_bcc_le(byte_count, pTargetSMB);
byte_count = pTargetSMB->smb_buf_length;
byte_count += total_in_buf2;
@@ -331,7 +330,26 @@ static int coalesce_t2(struct smb_hdr *psecond, struct smb_hdr *pTargetSMB)
return 0; /* we are done */
} else /* more responses to go */
return 1;
+}
+
+static void
+cifs_echo_request(struct work_struct *work)
+{
+ int rc;
+ struct TCP_Server_Info *server = container_of(work,
+ struct TCP_Server_Info, echo.work);
+ /* no need to ping if we got a response recently */
+ if (time_before(jiffies, server->lstrp + SMB_ECHO_INTERVAL - HZ))
+ goto requeue_echo;
+
+ rc = CIFSSMBEcho(server);
+ if (rc)
+ cFYI(1, "Unable to send echo request to server: %s",
+ server->hostname);
+
+requeue_echo:
+ queue_delayed_work(system_nrt_wq, &server->echo, SMB_ECHO_INTERVAL);
}
static int
@@ -345,8 +363,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
struct msghdr smb_msg;
struct kvec iov;
struct socket *csocket = server->ssocket;
- struct list_head *tmp;
- struct cifsSesInfo *ses;
+ struct list_head *tmp, *tmp2;
struct task_struct *task_to_wake = NULL;
struct mid_q_entry *mid_entry;
char temp;
@@ -399,7 +416,20 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
smb_msg.msg_control = NULL;
smb_msg.msg_controllen = 0;
pdu_length = 4; /* enough to get RFC1001 header */
+
incomplete_rcv:
+ if (echo_retries > 0 &&
+ time_after(jiffies, server->lstrp +
+ (echo_retries * SMB_ECHO_INTERVAL))) {
+ cERROR(1, "Server %s has not responded in %d seconds. "
+ "Reconnecting...", server->hostname,
+ (echo_retries * SMB_ECHO_INTERVAL / HZ));
+ cifs_reconnect(server);
+ csocket = server->ssocket;
+ wake_up(&server->response_q);
+ continue;
+ }
+
length =
kernel_recvmsg(csocket, &smb_msg,
&iov, 1, pdu_length, 0 /* BB other flags? */);
@@ -559,10 +589,11 @@ incomplete_rcv:
continue;
}
+ mid_entry = NULL;
+ server->lstrp = jiffies;
- task_to_wake = NULL;
spin_lock(&GlobalMid_Lock);
- list_for_each(tmp, &server->pending_mid_q) {
+ list_for_each_safe(tmp, tmp2, &server->pending_mid_q) {
mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
if ((mid_entry->mid == smb_buffer->Mid) &&
@@ -603,20 +634,19 @@ incomplete_rcv:
mid_entry->resp_buf = smb_buffer;
mid_entry->largeBuf = isLargeBuf;
multi_t2_fnd:
- task_to_wake = mid_entry->tsk;
mid_entry->midState = MID_RESPONSE_RECEIVED;
+ list_del_init(&mid_entry->qhead);
+ mid_entry->callback(mid_entry);
#ifdef CONFIG_CIFS_STATS2
mid_entry->when_received = jiffies;
#endif
- /* so we do not time out requests to server
- which is still responding (since server could
- be busy but not dead) */
- server->lstrp = jiffies;
break;
}
+ mid_entry = NULL;
}
spin_unlock(&GlobalMid_Lock);
- if (task_to_wake) {
+
+ if (mid_entry != NULL) {
/* Was previous buf put in mpx struct for multi-rsp? */
if (!isMultiRsp) {
/* smb buffer will be freed by user thread */
@@ -625,11 +655,10 @@ multi_t2_fnd:
else
smallbuf = NULL;
}
- wake_up_process(task_to_wake);
} else if (!is_valid_oplock_break(smb_buffer, server) &&
!isMultiRsp) {
cERROR(1, "No task to wake, unknown frame received! "
- "NumMids %d", midCount.counter);
+ "NumMids %d", atomic_read(&midCount));
cifs_dump_mem("Received Data is: ", (char *)smb_buffer,
sizeof(struct smb_hdr));
#ifdef CONFIG_CIFS_DEBUG2
@@ -677,44 +706,16 @@ multi_t2_fnd:
if (smallbuf) /* no sense logging a debug message if NULL */
cifs_small_buf_release(smallbuf);
- /*
- * BB: we shouldn't have to do any of this. It shouldn't be
- * possible to exit from the thread with active SMB sessions
- */
- spin_lock(&cifs_tcp_ses_lock);
- if (list_empty(&server->pending_mid_q)) {
- /* loop through server session structures attached to this and
- mark them dead */
- list_for_each(tmp, &server->smb_ses_list) {
- ses = list_entry(tmp, struct cifsSesInfo,
- smb_ses_list);
- ses->status = CifsExiting;
- ses->server = NULL;
- }
- spin_unlock(&cifs_tcp_ses_lock);
- } else {
- /* although we can not zero the server struct pointer yet,
- since there are active requests which may depnd on them,
- mark the corresponding SMB sessions as exiting too */
- list_for_each(tmp, &server->smb_ses_list) {
- ses = list_entry(tmp, struct cifsSesInfo,
- smb_ses_list);
- ses->status = CifsExiting;
- }
-
+ if (!list_empty(&server->pending_mid_q)) {
spin_lock(&GlobalMid_Lock);
- list_for_each(tmp, &server->pending_mid_q) {
- mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
- if (mid_entry->midState == MID_REQUEST_SUBMITTED) {
- cFYI(1, "Clearing Mid 0x%x - waking up ",
+ list_for_each_safe(tmp, tmp2, &server->pending_mid_q) {
+ mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
+ cFYI(1, "Clearing Mid 0x%x - issuing callback",
mid_entry->mid);
- task_to_wake = mid_entry->tsk;
- if (task_to_wake)
- wake_up_process(task_to_wake);
- }
+ list_del_init(&mid_entry->qhead);
+ mid_entry->callback(mid_entry);
}
spin_unlock(&GlobalMid_Lock);
- spin_unlock(&cifs_tcp_ses_lock);
/* 1/8th of sec is more than enough time for them to exit */
msleep(125);
}
@@ -732,18 +733,6 @@ multi_t2_fnd:
coming home not much else we can do but free the memory */
}
- /* last chance to mark ses pointers invalid
- if there are any pointing to this (e.g
- if a crazy root user tried to kill cifsd
- kernel thread explicitly this might happen) */
- /* BB: This shouldn't be necessary, see above */
- spin_lock(&cifs_tcp_ses_lock);
- list_for_each(tmp, &server->smb_ses_list) {
- ses = list_entry(tmp, struct cifsSesInfo, smb_ses_list);
- ses->server = NULL;
- }
- spin_unlock(&cifs_tcp_ses_lock);
-
kfree(server->hostname);
task_to_wake = xchg(&server->tsk, NULL);
kfree(server);
@@ -1113,6 +1102,8 @@ cifs_parse_mount_options(char *options, const char *devname,
} else if (!strnicmp(data, "uid", 3) && value && *value) {
vol->linux_uid = simple_strtoul(value, &value, 0);
uid_specified = true;
+ } else if (!strnicmp(data, "cruid", 5) && value && *value) {
+ vol->cred_uid = simple_strtoul(value, &value, 0);
} else if (!strnicmp(data, "forceuid", 8)) {
override_uid = 1;
} else if (!strnicmp(data, "noforceuid", 10)) {
@@ -1577,6 +1568,9 @@ cifs_find_tcp_session(struct sockaddr *addr, struct smb_vol *vol)
spin_lock(&cifs_tcp_ses_lock);
list_for_each_entry(server, &cifs_tcp_ses_list, tcp_ses_list) {
+ if (!net_eq(cifs_net_ns(server), current->nsproxy->net_ns))
+ continue;
+
if (!match_address(server, addr,
(struct sockaddr *)&vol->srcaddr))
continue;
@@ -1607,9 +1601,13 @@ cifs_put_tcp_session(struct TCP_Server_Info *server)
return;
}
+ put_net(cifs_net_ns(server));
+
list_del_init(&server->tcp_ses_list);
spin_unlock(&cifs_tcp_ses_lock);
+ cancel_delayed_work_sync(&server->echo);
+
spin_lock(&GlobalMid_Lock);
server->tcpStatus = CifsExiting;
spin_unlock(&GlobalMid_Lock);
@@ -1679,6 +1677,7 @@ cifs_get_tcp_session(struct smb_vol *volume_info)
goto out_err;
}
+ cifs_set_net_ns(tcp_ses, get_net(current->nsproxy->net_ns));
tcp_ses->hostname = extract_hostname(volume_info->UNC);
if (IS_ERR(tcp_ses->hostname)) {
rc = PTR_ERR(tcp_ses->hostname);
@@ -1699,8 +1698,10 @@ cifs_get_tcp_session(struct smb_vol *volume_info)
volume_info->target_rfc1001_name, RFC1001_NAME_LEN_WITH_NULL);
tcp_ses->session_estab = false;
tcp_ses->sequence_number = 0;
+ tcp_ses->lstrp = jiffies;
INIT_LIST_HEAD(&tcp_ses->tcp_ses_list);
INIT_LIST_HEAD(&tcp_ses->smb_ses_list);
+ INIT_DELAYED_WORK(&tcp_ses->echo, cifs_echo_request);
/*
* at this point we are the only ones with the pointer
@@ -1749,11 +1750,16 @@ cifs_get_tcp_session(struct smb_vol *volume_info)
cifs_fscache_get_client_cookie(tcp_ses);
+ /* queue echo request delayed work */
+ queue_delayed_work(system_nrt_wq, &tcp_ses->echo, SMB_ECHO_INTERVAL);
+
return tcp_ses;
out_err_crypto_release:
cifs_crypto_shash_release(tcp_ses);
+ put_net(cifs_net_ns(tcp_ses));
+
out_err:
if (tcp_ses) {
if (!IS_ERR(tcp_ses->hostname))
@@ -2265,8 +2271,8 @@ generic_ip_connect(struct TCP_Server_Info *server)
}
if (socket == NULL) {
- rc = sock_create_kern(sfamily, SOCK_STREAM,
- IPPROTO_TCP, &socket);
+ rc = __sock_create(cifs_net_ns(server), sfamily, SOCK_STREAM,
+ IPPROTO_TCP, &socket, 1);
if (rc < 0) {
cERROR(1, "Error %d creating socket", rc);
server->ssocket = NULL;
@@ -2934,8 +2940,8 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
TCONX_RSP *pSMBr;
unsigned char *bcc_ptr;
int rc = 0;
- int length, bytes_left;
- __u16 count;
+ int length;
+ __u16 bytes_left, count;
if (ses == NULL)
return -EIO;
@@ -2963,7 +2969,7 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
bcc_ptr++; /* skip password */
/* already aligned so no need to do it below */
} else {
- pSMB->PasswordLength = cpu_to_le16(CIFS_SESS_KEY_SIZE);
+ pSMB->PasswordLength = cpu_to_le16(CIFS_AUTH_RESP_SIZE);
/* BB FIXME add code to fail this if NTLMv2 or Kerberos
specified as required (when that support is added to
the vfs in the future) as only NTLM or the much
@@ -2981,7 +2987,7 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
#endif /* CIFS_WEAK_PW_HASH */
SMBNTencrypt(tcon->password, ses->server->cryptkey, bcc_ptr);
- bcc_ptr += CIFS_SESS_KEY_SIZE;
+ bcc_ptr += CIFS_AUTH_RESP_SIZE;
if (ses->capabilities & CAP_UNICODE) {
/* must align unicode strings */
*bcc_ptr = 0; /* null byte password */
@@ -3019,7 +3025,7 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
pSMB->ByteCount = cpu_to_le16(count);
rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &length,
- CIFS_STD_OP);
+ 0);
/* above now done in SendReceive */
if ((rc == 0) && (tcon != NULL)) {
@@ -3029,7 +3035,7 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
tcon->need_reconnect = false;
tcon->tid = smb_buffer_response->Tid;
bcc_ptr = pByteArea(smb_buffer_response);
- bytes_left = BCC(smb_buffer_response);
+ bytes_left = get_bcc(smb_buffer_response);
length = strnlen(bcc_ptr, bytes_left - 2);
if (smb_buffer->Flags2 & SMBFLG2_UNICODE)
is_unicode = true;
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c
index 1e95dd6..dd5f229 100644
--- a/fs/cifs/dir.c
+++ b/fs/cifs/dir.c
@@ -675,6 +675,7 @@ cifs_d_revalidate(struct dentry *direntry, struct nameidata *nd)
const struct dentry_operations cifs_dentry_ops = {
.d_revalidate = cifs_d_revalidate,
+ .d_automount = cifs_dfs_d_automount,
/* d_delete: cifs_d_delete, */ /* not needed except for debugging */
};
@@ -711,4 +712,5 @@ const struct dentry_operations cifs_ci_dentry_ops = {
.d_revalidate = cifs_d_revalidate,
.d_hash = cifs_ci_hash,
.d_compare = cifs_ci_compare,
+ .d_automount = cifs_dfs_d_automount,
};
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index d843631..d7d65a7 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -287,6 +287,7 @@ void cifsFileInfo_put(struct cifsFileInfo *cifs_file)
struct inode *inode = cifs_file->dentry->d_inode;
struct cifsTconInfo *tcon = tlink_tcon(cifs_file->tlink);
struct cifsInodeInfo *cifsi = CIFS_I(inode);
+ struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
struct cifsLockInfo *li, *tmp;
spin_lock(&cifs_file_list_lock);
@@ -302,6 +303,13 @@ void cifsFileInfo_put(struct cifsFileInfo *cifs_file)
if (list_empty(&cifsi->openFileList)) {
cFYI(1, "closing last open instance for inode %p",
cifs_file->dentry->d_inode);
+
+ /* in strict cache mode we need invalidate mapping on the last
+ close because it may cause a error when we open this file
+ again and get at least level II oplock */
+ if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_STRICT_IO)
+ CIFS_I(inode)->invalid_mapping = true;
+
cifs_set_oplock_level(cifsi, 0);
}
spin_unlock(&cifs_file_list_lock);
@@ -726,12 +734,12 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
/* BB we could chain these into one lock request BB */
rc = CIFSSMBLock(xid, tcon, netfid, length, pfLock->fl_start,
- 0, 1, lockType, 0 /* wait flag */ );
+ 0, 1, lockType, 0 /* wait flag */, 0);
if (rc == 0) {
rc = CIFSSMBLock(xid, tcon, netfid, length,
pfLock->fl_start, 1 /* numUnlock */ ,
0 /* numLock */ , lockType,
- 0 /* wait flag */ );
+ 0 /* wait flag */, 0);
pfLock->fl_type = F_UNLCK;
if (rc != 0)
cERROR(1, "Error unlocking previously locked "
@@ -748,13 +756,13 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
rc = CIFSSMBLock(xid, tcon, netfid, length,
pfLock->fl_start, 0, 1,
lockType | LOCKING_ANDX_SHARED_LOCK,
- 0 /* wait flag */);
+ 0 /* wait flag */, 0);
if (rc == 0) {
rc = CIFSSMBLock(xid, tcon, netfid,
length, pfLock->fl_start, 1, 0,
lockType |
LOCKING_ANDX_SHARED_LOCK,
- 0 /* wait flag */);
+ 0 /* wait flag */, 0);
pfLock->fl_type = F_RDLCK;
if (rc != 0)
cERROR(1, "Error unlocking "
@@ -797,8 +805,8 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
if (numLock) {
rc = CIFSSMBLock(xid, tcon, netfid, length,
- pfLock->fl_start,
- 0, numLock, lockType, wait_flag);
+ pfLock->fl_start, 0, numLock, lockType,
+ wait_flag, 0);
if (rc == 0) {
/* For Windows locks we must store them. */
@@ -818,9 +826,9 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
(pfLock->fl_start + length) >=
(li->offset + li->length)) {
stored_rc = CIFSSMBLock(xid, tcon,
- netfid,
- li->length, li->offset,
- 1, 0, li->type, false);
+ netfid, li->length,
+ li->offset, 1, 0,
+ li->type, false, 0);
if (stored_rc)
rc = stored_rc;
else {
@@ -839,29 +847,6 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
return rc;
}
-/*
- * Set the timeout on write requests past EOF. For some servers (Windows)
- * these calls can be very long.
- *
- * If we're writing >10M past the EOF we give a 180s timeout. Anything less
- * than that gets a 45s timeout. Writes not past EOF get 15s timeouts.
- * The 10M cutoff is totally arbitrary. A better scheme for this would be
- * welcome if someone wants to suggest one.
- *
- * We may be able to do a better job with this if there were some way to
- * declare that a file should be sparse.
- */
-static int
-cifs_write_timeout(struct cifsInodeInfo *cifsi, loff_t offset)
-{
- if (offset <= cifsi->server_eof)
- return CIFS_STD_OP;
- else if (offset > (cifsi->server_eof + (10 * 1024 * 1024)))
- return CIFS_VLONG_OP;
- else
- return CIFS_LONG_OP;
-}
-
/* update the file size (if needed) after a write */
static void
cifs_update_eof(struct cifsInodeInfo *cifsi, loff_t offset,
@@ -882,7 +867,7 @@ ssize_t cifs_user_write(struct file *file, const char __user *write_data,
unsigned int total_written;
struct cifs_sb_info *cifs_sb;
struct cifsTconInfo *pTcon;
- int xid, long_op;
+ int xid;
struct cifsFileInfo *open_file;
struct cifsInodeInfo *cifsi = CIFS_I(inode);
@@ -903,7 +888,6 @@ ssize_t cifs_user_write(struct file *file, const char __user *write_data,
xid = GetXid();
- long_op = cifs_write_timeout(cifsi, *poffset);
for (total_written = 0; write_size > total_written;
total_written += bytes_written) {
rc = -EAGAIN;
@@ -931,7 +915,7 @@ ssize_t cifs_user_write(struct file *file, const char __user *write_data,
min_t(const int, cifs_sb->wsize,
write_size - total_written),
*poffset, &bytes_written,
- NULL, write_data + total_written, long_op);
+ NULL, write_data + total_written, 0);
}
if (rc || (bytes_written == 0)) {
if (total_written)
@@ -944,8 +928,6 @@ ssize_t cifs_user_write(struct file *file, const char __user *write_data,
cifs_update_eof(cifsi, *poffset, bytes_written);
*poffset += bytes_written;
}
- long_op = CIFS_STD_OP; /* subsequent writes fast -
- 15 seconds is plenty */
}
cifs_stats_bytes_written(pTcon, total_written);
@@ -974,7 +956,7 @@ static ssize_t cifs_write(struct cifsFileInfo *open_file,
unsigned int total_written;
struct cifs_sb_info *cifs_sb;
struct cifsTconInfo *pTcon;
- int xid, long_op;
+ int xid;
struct dentry *dentry = open_file->dentry;
struct cifsInodeInfo *cifsi = CIFS_I(dentry->d_inode);
@@ -987,7 +969,6 @@ static ssize_t cifs_write(struct cifsFileInfo *open_file,
xid = GetXid();
- long_op = cifs_write_timeout(cifsi, *poffset);
for (total_written = 0; write_size > total_written;
total_written += bytes_written) {
rc = -EAGAIN;
@@ -1017,7 +998,7 @@ static ssize_t cifs_write(struct cifsFileInfo *open_file,
rc = CIFSSMBWrite2(xid, pTcon,
open_file->netfid, len,
*poffset, &bytes_written,
- iov, 1, long_op);
+ iov, 1, 0);
} else
rc = CIFSSMBWrite(xid, pTcon,
open_file->netfid,
@@ -1025,7 +1006,7 @@ static ssize_t cifs_write(struct cifsFileInfo *open_file,
write_size - total_written),
*poffset, &bytes_written,
write_data + total_written,
- NULL, long_op);
+ NULL, 0);
}
if (rc || (bytes_written == 0)) {
if (total_written)
@@ -1038,8 +1019,6 @@ static ssize_t cifs_write(struct cifsFileInfo *open_file,
cifs_update_eof(cifsi, *poffset, bytes_written);
*poffset += bytes_written;
}
- long_op = CIFS_STD_OP; /* subsequent writes fast -
- 15 seconds is plenty */
}
cifs_stats_bytes_written(pTcon, total_written);
@@ -1239,7 +1218,7 @@ static int cifs_writepages(struct address_space *mapping,
struct pagevec pvec;
int rc = 0;
int scanned = 0;
- int xid, long_op;
+ int xid;
cifs_sb = CIFS_SB(mapping->host->i_sb);
@@ -1377,43 +1356,67 @@ retry:
break;
}
if (n_iov) {
+retry_write:
open_file = find_writable_file(CIFS_I(mapping->host),
false);
if (!open_file) {
cERROR(1, "No writable handles for inode");
rc = -EBADF;
} else {
- long_op = cifs_write_timeout(cifsi, offset);
rc = CIFSSMBWrite2(xid, tcon, open_file->netfid,
bytes_to_write, offset,
&bytes_written, iov, n_iov,
- long_op);
+ 0);
cifsFileInfo_put(open_file);
- cifs_update_eof(cifsi, offset, bytes_written);
}
- if (rc || bytes_written < bytes_to_write) {
- cERROR(1, "Write2 ret %d, wrote %d",
- rc, bytes_written);
- mapping_set_error(mapping, rc);
- } else {
+ cFYI(1, "Write2 rc=%d, wrote=%u", rc, bytes_written);
+
+ /*
+ * For now, treat a short write as if nothing got
+ * written. A zero length write however indicates
+ * ENOSPC or EFBIG. We have no way to know which
+ * though, so call it ENOSPC for now. EFBIG would
+ * get translated to AS_EIO anyway.
+ *
+ * FIXME: make it take into account the data that did
+ * get written
+ */
+ if (rc == 0) {
+ if (bytes_written == 0)
+ rc = -ENOSPC;
+ else if (bytes_written < bytes_to_write)
+ rc = -EAGAIN;
+ }
+
+ /* retry on data-integrity flush */
+ if (wbc->sync_mode == WB_SYNC_ALL && rc == -EAGAIN)
+ goto retry_write;
+
+ /* fix the stats and EOF */
+ if (bytes_written > 0) {
cifs_stats_bytes_written(tcon, bytes_written);
+ cifs_update_eof(cifsi, offset, bytes_written);
}
for (i = 0; i < n_iov; i++) {
page = pvec.pages[first + i];
- /* Should we also set page error on
- success rc but too little data written? */
- /* BB investigate retry logic on temporary
- server crash cases and how recovery works
- when page marked as error */
- if (rc)
+ /* on retryable write error, redirty page */
+ if (rc == -EAGAIN)
+ redirty_page_for_writepage(wbc, page);
+ else if (rc != 0)
SetPageError(page);
kunmap(page);
unlock_page(page);
end_page_writeback(page);
page_cache_release(page);
}
+
+ if (rc != -EAGAIN)
+ mapping_set_error(mapping, rc);
+ else
+ rc = 0;
+
if ((wbc->nr_to_write -= n_iov) <= 0)
done = 1;
index = next;
@@ -1525,27 +1528,47 @@ static int cifs_write_end(struct file *file, struct address_space *mapping,
return rc;
}
-int cifs_fsync(struct file *file, int datasync)
+int cifs_strict_fsync(struct file *file, int datasync)
{
int xid;
int rc = 0;
struct cifsTconInfo *tcon;
struct cifsFileInfo *smbfile = file->private_data;
struct inode *inode = file->f_path.dentry->d_inode;
+ struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
xid = GetXid();
cFYI(1, "Sync file - name: %s datasync: 0x%x",
file->f_path.dentry->d_name.name, datasync);
- rc = filemap_write_and_wait(inode->i_mapping);
- if (rc == 0) {
- struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
+ if (!CIFS_I(inode)->clientCanCacheRead)
+ cifs_invalidate_mapping(inode);
- tcon = tlink_tcon(smbfile->tlink);
- if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC))
- rc = CIFSSMBFlush(xid, tcon, smbfile->netfid);
- }
+ tcon = tlink_tcon(smbfile->tlink);
+ if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC))
+ rc = CIFSSMBFlush(xid, tcon, smbfile->netfid);
+
+ FreeXid(xid);
+ return rc;
+}
+
+int cifs_fsync(struct file *file, int datasync)
+{
+ int xid;
+ int rc = 0;
+ struct cifsTconInfo *tcon;
+ struct cifsFileInfo *smbfile = file->private_data;
+ struct cifs_sb_info *cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
+
+ xid = GetXid();
+
+ cFYI(1, "Sync file - name: %s datasync: 0x%x",
+ file->f_path.dentry->d_name.name, datasync);
+
+ tcon = tlink_tcon(smbfile->tlink);
+ if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC))
+ rc = CIFSSMBFlush(xid, tcon, smbfile->netfid);
FreeXid(xid);
return rc;
@@ -1596,42 +1619,42 @@ int cifs_flush(struct file *file, fl_owner_t id)
return rc;
}
-ssize_t cifs_user_read(struct file *file, char __user *read_data,
- size_t read_size, loff_t *poffset)
+static ssize_t
+cifs_iovec_read(struct file *file, const struct iovec *iov,
+ unsigned long nr_segs, loff_t *poffset)
{
- int rc = -EACCES;
- unsigned int bytes_read = 0;
- unsigned int total_read = 0;
- unsigned int current_read_size;
+ int rc;
+ int xid;
+ unsigned int total_read, bytes_read = 0;
+ size_t len, cur_len;
+ int iov_offset = 0;
struct cifs_sb_info *cifs_sb;
struct cifsTconInfo *pTcon;
- int xid;
struct cifsFileInfo *open_file;
- char *smb_read_data;
- char __user *current_offset;
struct smb_com_read_rsp *pSMBr;
+ char *read_data;
+
+ if (!nr_segs)
+ return 0;
+
+ len = iov_length(iov, nr_segs);
+ if (!len)
+ return 0;
xid = GetXid();
cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
- if (file->private_data == NULL) {
- rc = -EBADF;
- FreeXid(xid);
- return rc;
- }
open_file = file->private_data;
pTcon = tlink_tcon(open_file->tlink);
if ((file->f_flags & O_ACCMODE) == O_WRONLY)
cFYI(1, "attempting read on write only file instance");
- for (total_read = 0, current_offset = read_data;
- read_size > total_read;
- total_read += bytes_read, current_offset += bytes_read) {
- current_read_size = min_t(const int, read_size - total_read,
- cifs_sb->rsize);
+ for (total_read = 0; total_read < len; total_read += bytes_read) {
+ cur_len = min_t(const size_t, len - total_read, cifs_sb->rsize);
rc = -EAGAIN;
- smb_read_data = NULL;
+ read_data = NULL;
+
while (rc == -EAGAIN) {
int buf_type = CIFS_NO_BUFFER;
if (open_file->invalidHandle) {
@@ -1639,27 +1662,25 @@ ssize_t cifs_user_read(struct file *file, char __user *read_data,
if (rc != 0)
break;
}
- rc = CIFSSMBRead(xid, pTcon,
- open_file->netfid,
- current_read_size, *poffset,
- &bytes_read, &smb_read_data,
- &buf_type);
- pSMBr = (struct smb_com_read_rsp *)smb_read_data;
- if (smb_read_data) {
- if (copy_to_user(current_offset,
- smb_read_data +
- 4 /* RFC1001 length field */ +
- le16_to_cpu(pSMBr->DataOffset),
- bytes_read))
+ rc = CIFSSMBRead(xid, pTcon, open_file->netfid,
+ cur_len, *poffset, &bytes_read,
+ &read_data, &buf_type);
+ pSMBr = (struct smb_com_read_rsp *)read_data;
+ if (read_data) {
+ char *data_offset = read_data + 4 +
+ le16_to_cpu(pSMBr->DataOffset);
+ if (memcpy_toiovecend(iov, data_offset,
+ iov_offset, bytes_read))
rc = -EFAULT;
-
if (buf_type == CIFS_SMALL_BUFFER)
- cifs_small_buf_release(smb_read_data);
+ cifs_small_buf_release(read_data);
else if (buf_type == CIFS_LARGE_BUFFER)
- cifs_buf_release(smb_read_data);
- smb_read_data = NULL;
+ cifs_buf_release(read_data);
+ read_data = NULL;
+ iov_offset += bytes_read;
}
}
+
if (rc || (bytes_read == 0)) {
if (total_read) {
break;
@@ -1672,13 +1693,57 @@ ssize_t cifs_user_read(struct file *file, char __user *read_data,
*poffset += bytes_read;
}
}
+
FreeXid(xid);
return total_read;
}
+ssize_t cifs_user_read(struct file *file, char __user *read_data,
+ size_t read_size, loff_t *poffset)
+{
+ struct iovec iov;
+ iov.iov_base = read_data;
+ iov.iov_len = read_size;
+
+ return cifs_iovec_read(file, &iov, 1, poffset);
+}
+
+static ssize_t cifs_user_readv(struct kiocb *iocb, const struct iovec *iov,
+ unsigned long nr_segs, loff_t pos)
+{
+ ssize_t read;
+
+ read = cifs_iovec_read(iocb->ki_filp, iov, nr_segs, &pos);
+ if (read > 0)
+ iocb->ki_pos = pos;
+
+ return read;
+}
+
+ssize_t cifs_strict_readv(struct kiocb *iocb, const struct iovec *iov,
+ unsigned long nr_segs, loff_t pos)
+{
+ struct inode *inode;
+
+ inode = iocb->ki_filp->f_path.dentry->d_inode;
+
+ if (CIFS_I(inode)->clientCanCacheRead)
+ return generic_file_aio_read(iocb, iov, nr_segs, pos);
+
+ /*
+ * In strict cache mode we need to read from the server all the time
+ * if we don't have level II oplock because the server can delay mtime
+ * change - so we can't make a decision about inode invalidating.
+ * And we can also fail with pagereading if there are mandatory locks
+ * on pages affected by this read but not on the region from pos to
+ * pos+len-1.
+ */
+
+ return cifs_user_readv(iocb, iov, nr_segs, pos);
+}
static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
- loff_t *poffset)
+ loff_t *poffset)
{
int rc = -EACCES;
unsigned int bytes_read = 0;
@@ -1746,6 +1811,21 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
return total_read;
}
+int cifs_file_strict_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ int rc, xid;
+ struct inode *inode = file->f_path.dentry->d_inode;
+
+ xid = GetXid();
+
+ if (!CIFS_I(inode)->clientCanCacheRead)
+ cifs_invalidate_mapping(inode);
+
+ rc = generic_file_mmap(file, vma);
+ FreeXid(xid);
+ return rc;
+}
+
int cifs_file_mmap(struct file *file, struct vm_area_struct *vma)
{
int rc, xid;
@@ -2192,7 +2272,8 @@ void cifs_oplock_break(struct work_struct *work)
*/
if (!cfile->oplock_break_cancelled) {
rc = CIFSSMBLock(0, tlink_tcon(cfile->tlink), cfile->netfid, 0,
- 0, 0, 0, LOCKING_ANDX_OPLOCK_RELEASE, false);
+ 0, 0, 0, LOCKING_ANDX_OPLOCK_RELEASE, false,
+ cinode->clientCanCacheRead ? 1 : 0);
cFYI(1, "Oplock release rc = %d", rc);
}
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index b06b606..8852470 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -32,7 +32,7 @@
#include "fscache.h"
-static void cifs_set_ops(struct inode *inode, const bool is_dfs_referral)
+static void cifs_set_ops(struct inode *inode)
{
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
@@ -44,13 +44,17 @@ static void cifs_set_ops(struct inode *inode, const bool is_dfs_referral)
inode->i_fop = &cifs_file_direct_nobrl_ops;
else
inode->i_fop = &cifs_file_direct_ops;
+ } else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_STRICT_IO) {
+ if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
+ inode->i_fop = &cifs_file_strict_nobrl_ops;
+ else
+ inode->i_fop = &cifs_file_strict_ops;
} else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
inode->i_fop = &cifs_file_nobrl_ops;
else { /* not direct, send byte range locks */
inode->i_fop = &cifs_file_ops;
}
-
/* check if server can support readpages */
if (cifs_sb_master_tcon(cifs_sb)->ses->server->maxBuf <
PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE)
@@ -60,7 +64,7 @@ static void cifs_set_ops(struct inode *inode, const bool is_dfs_referral)
break;
case S_IFDIR:
#ifdef CONFIG_CIFS_DFS_UPCALL
- if (is_dfs_referral) {
+ if (IS_AUTOMOUNT(inode)) {
inode->i_op = &cifs_dfs_referral_inode_operations;
} else {
#else /* NO DFS support, treat as a directory */
@@ -167,7 +171,9 @@ cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr)
}
spin_unlock(&inode->i_lock);
- cifs_set_ops(inode, fattr->cf_flags & CIFS_FATTR_DFS_REFERRAL);
+ if (fattr->cf_flags & CIFS_FATTR_DFS_REFERRAL)
+ inode->i_flags |= S_AUTOMOUNT;
+ cifs_set_ops(inode);
}
void
@@ -1677,7 +1683,7 @@ cifs_inode_needs_reval(struct inode *inode)
/*
* Zap the cache. Called when invalid_mapping flag is set.
*/
-static void
+void
cifs_invalidate_mapping(struct inode *inode)
{
int rc;
diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c
index 43f1028..a09e077 100644
--- a/fs/cifs/misc.c
+++ b/fs/cifs/misc.c
@@ -571,7 +571,7 @@ is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv)
pCifsInode = CIFS_I(netfile->dentry->d_inode);
cifs_set_oplock_level(pCifsInode,
- pSMB->OplockLevel);
+ pSMB->OplockLevel ? OPLOCK_READ : 0);
/*
* cifs_oplock_break_put() can't be called
* from here. Get reference after queueing
@@ -637,77 +637,6 @@ dump_smb(struct smb_hdr *smb_buf, int smb_buf_length)
return;
}
-/* Convert 16 bit Unicode pathname to wire format from string in current code
- page. Conversion may involve remapping up the seven characters that are
- only legal in POSIX-like OS (if they are present in the string). Path
- names are little endian 16 bit Unicode on the wire */
-int
-cifsConvertToUCS(__le16 *target, const char *source, int maxlen,
- const struct nls_table *cp, int mapChars)
-{
- int i, j, charlen;
- int len_remaining = maxlen;
- char src_char;
- __u16 temp;
-
- if (!mapChars)
- return cifs_strtoUCS(target, source, PATH_MAX, cp);
-
- for (i = 0, j = 0; i < maxlen; j++) {
- src_char = source[i];
- switch (src_char) {
- case 0:
- target[j] = 0;
- goto ctoUCS_out;
- case ':':
- target[j] = cpu_to_le16(UNI_COLON);
- break;
- case '*':
- target[j] = cpu_to_le16(UNI_ASTERIK);
- break;
- case '?':
- target[j] = cpu_to_le16(UNI_QUESTION);
- break;
- case '<':
- target[j] = cpu_to_le16(UNI_LESSTHAN);
- break;
- case '>':
- target[j] = cpu_to_le16(UNI_GRTRTHAN);
- break;
- case '|':
- target[j] = cpu_to_le16(UNI_PIPE);
- break;
- /* BB We can not handle remapping slash until
- all the calls to build_path_from_dentry
- are modified, as they use slash as separator BB */
- /* case '\\':
- target[j] = cpu_to_le16(UNI_SLASH);
- break;*/
- default:
- charlen = cp->char2uni(source+i,
- len_remaining, &temp);
- /* if no match, use question mark, which
- at least in some cases servers as wild card */
- if (charlen < 1) {
- target[j] = cpu_to_le16(0x003f);
- charlen = 1;
- } else
- target[j] = cpu_to_le16(temp);
- len_remaining -= charlen;
- /* character may take more than one byte in the
- the source string, but will take exactly two
- bytes in the target string */
- i += charlen;
- continue;
- }
- i++; /* move to next char in source string */
- len_remaining--;
- }
-
-ctoUCS_out:
- return i;
-}
-
void
cifs_autodisable_serverino(struct cifs_sb_info *cifs_sb)
{
diff --git a/fs/cifs/netmisc.c b/fs/cifs/netmisc.c
index 9aad47a..8d9189f 100644
--- a/fs/cifs/netmisc.c
+++ b/fs/cifs/netmisc.c
@@ -899,8 +899,8 @@ map_smb_to_linux_error(struct smb_hdr *smb, int logErr)
}
/* else ERRHRD class errors or junk - return EIO */
- cFYI(1, "Mapping smb error code %d to POSIX err %d",
- smberrcode, rc);
+ cFYI(1, "Mapping smb error code 0x%x to POSIX err %d",
+ le32_to_cpu(smb->Status.CifsError), rc);
/* generic corrective action e.g. reconnect SMB session on
* ERRbaduid could be added */
@@ -916,14 +916,14 @@ unsigned int
smbCalcSize(struct smb_hdr *ptr)
{
return (sizeof(struct smb_hdr) + (2 * ptr->WordCount) +
- 2 /* size of the bcc field */ + BCC(ptr));
+ 2 /* size of the bcc field */ + get_bcc(ptr));
}
unsigned int
smbCalcSize_LE(struct smb_hdr *ptr)
{
return (sizeof(struct smb_hdr) + (2 * ptr->WordCount) +
- 2 /* size of the bcc field */ + le16_to_cpu(BCC_LE(ptr)));
+ 2 /* size of the bcc field */ + get_bcc_le(ptr));
}
/* The following are taken from fs/ntfs/util.c */
diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c
index eb74648..1adc962 100644
--- a/fs/cifs/sess.c
+++ b/fs/cifs/sess.c
@@ -277,7 +277,7 @@ static void ascii_ssetup_strings(char **pbcc_area, struct cifsSesInfo *ses,
}
static void
-decode_unicode_ssetup(char **pbcc_area, int bleft, struct cifsSesInfo *ses,
+decode_unicode_ssetup(char **pbcc_area, __u16 bleft, struct cifsSesInfo *ses,
const struct nls_table *nls_cp)
{
int len;
@@ -323,7 +323,7 @@ decode_unicode_ssetup(char **pbcc_area, int bleft, struct cifsSesInfo *ses,
return;
}
-static int decode_ascii_ssetup(char **pbcc_area, int bleft,
+static int decode_ascii_ssetup(char **pbcc_area, __u16 bleft,
struct cifsSesInfo *ses,
const struct nls_table *nls_cp)
{
@@ -575,12 +575,11 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses,
char *str_area;
SESSION_SETUP_ANDX *pSMB;
__u32 capabilities;
- int count;
+ __u16 count;
int resp_buf_type;
struct kvec iov[3];
enum securityEnum type;
- __u16 action;
- int bytes_remaining;
+ __u16 action, bytes_remaining;
struct key *spnego_key = NULL;
__le32 phase = NtLmNegotiate; /* NTLMSSP, if needed, is multistage */
u16 blob_len;
@@ -876,10 +875,10 @@ ssetup_ntlmssp_authenticate:
count = iov[1].iov_len + iov[2].iov_len;
smb_buf->smb_buf_length += count;
- BCC_LE(smb_buf) = cpu_to_le16(count);
+ put_bcc_le(count, smb_buf);
rc = SendReceive2(xid, ses, iov, 3 /* num_iovecs */, &resp_buf_type,
- CIFS_STD_OP /* not long */ | CIFS_LOG_ERROR);
+ CIFS_LOG_ERROR);
/* SMB request buf freed in SendReceive2 */
pSMB = (SESSION_SETUP_ANDX *)iov[0].iov_base;
@@ -910,7 +909,7 @@ ssetup_ntlmssp_authenticate:
cFYI(1, "UID = %d ", ses->Suid);
/* response can have either 3 or 4 word count - Samba sends 3 */
/* and lanman response is 3 */
- bytes_remaining = BCC(smb_buf);
+ bytes_remaining = get_bcc(smb_buf);
bcc_ptr = pByteArea(smb_buf);
if (smb_buf->WordCount == 4) {
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c
index 59ca81b..c1ccca1 100644
--- a/fs/cifs/transport.c
+++ b/fs/cifs/transport.c
@@ -36,7 +36,13 @@
extern mempool_t *cifs_mid_poolp;
-static struct mid_q_entry *
+static void
+wake_up_task(struct mid_q_entry *mid)
+{
+ wake_up_process(mid->callback_data);
+}
+
+struct mid_q_entry *
AllocMidQEntry(const struct smb_hdr *smb_buffer, struct TCP_Server_Info *server)
{
struct mid_q_entry *temp;
@@ -58,28 +64,28 @@ AllocMidQEntry(const struct smb_hdr *smb_buffer, struct TCP_Server_Info *server)
/* do_gettimeofday(&temp->when_sent);*/ /* easier to use jiffies */
/* when mid allocated can be before when sent */
temp->when_alloc = jiffies;
- temp->tsk = current;
+
+ /*
+ * The default is for the mid to be synchronous, so the
+ * default callback just wakes up the current task.
+ */
+ temp->callback = wake_up_task;
+ temp->callback_data = current;
}
- spin_lock(&GlobalMid_Lock);
- list_add_tail(&temp->qhead, &server->pending_mid_q);
atomic_inc(&midCount);
temp->midState = MID_REQUEST_ALLOCATED;
- spin_unlock(&GlobalMid_Lock);
return temp;
}
-static void
+void
DeleteMidQEntry(struct mid_q_entry *midEntry)
{
#ifdef CONFIG_CIFS_STATS2
unsigned long now;
#endif
- spin_lock(&GlobalMid_Lock);
midEntry->midState = MID_FREE;
- list_del(&midEntry->qhead);
atomic_dec(&midCount);
- spin_unlock(&GlobalMid_Lock);
if (midEntry->largeBuf)
cifs_buf_release(midEntry->resp_buf);
else
@@ -103,6 +109,16 @@ DeleteMidQEntry(struct mid_q_entry *midEntry)
mempool_free(midEntry, cifs_mid_poolp);
}
+static void
+delete_mid(struct mid_q_entry *mid)
+{
+ spin_lock(&GlobalMid_Lock);
+ list_del(&mid->qhead);
+ spin_unlock(&GlobalMid_Lock);
+
+ DeleteMidQEntry(mid);
+}
+
static int
smb_sendv(struct TCP_Server_Info *server, struct kvec *iov, int n_vec)
{
@@ -244,31 +260,31 @@ smb_send(struct TCP_Server_Info *server, struct smb_hdr *smb_buffer,
return smb_sendv(server, &iov, 1);
}
-static int wait_for_free_request(struct cifsSesInfo *ses, const int long_op)
+static int wait_for_free_request(struct TCP_Server_Info *server,
+ const int long_op)
{
if (long_op == CIFS_ASYNC_OP) {
/* oplock breaks must not be held up */
- atomic_inc(&ses->server->inFlight);
+ atomic_inc(&server->inFlight);
return 0;
}
spin_lock(&GlobalMid_Lock);
while (1) {
- if (atomic_read(&ses->server->inFlight) >=
- cifs_max_pending){
+ if (atomic_read(&server->inFlight) >= cifs_max_pending) {
spin_unlock(&GlobalMid_Lock);
#ifdef CONFIG_CIFS_STATS2
- atomic_inc(&ses->server->num_waiters);
+ atomic_inc(&server->num_waiters);
#endif
- wait_event(ses->server->request_q,
- atomic_read(&ses->server->inFlight)
+ wait_event(server->request_q,
+ atomic_read(&server->inFlight)
< cifs_max_pending);
#ifdef CONFIG_CIFS_STATS2
- atomic_dec(&ses->server->num_waiters);
+ atomic_dec(&server->num_waiters);
#endif
spin_lock(&GlobalMid_Lock);
} else {
- if (ses->server->tcpStatus == CifsExiting) {
+ if (server->tcpStatus == CifsExiting) {
spin_unlock(&GlobalMid_Lock);
return -ENOENT;
}
@@ -278,7 +294,7 @@ static int wait_for_free_request(struct cifsSesInfo *ses, const int long_op)
/* update # of requests on the wire to server */
if (long_op != CIFS_BLOCKING_OP)
- atomic_inc(&ses->server->inFlight);
+ atomic_inc(&server->inFlight);
spin_unlock(&GlobalMid_Lock);
break;
}
@@ -308,53 +324,81 @@ static int allocate_mid(struct cifsSesInfo *ses, struct smb_hdr *in_buf,
*ppmidQ = AllocMidQEntry(in_buf, ses->server);
if (*ppmidQ == NULL)
return -ENOMEM;
+ spin_lock(&GlobalMid_Lock);
+ list_add_tail(&(*ppmidQ)->qhead, &ses->server->pending_mid_q);
+ spin_unlock(&GlobalMid_Lock);
return 0;
}
-static int wait_for_response(struct cifsSesInfo *ses,
- struct mid_q_entry *midQ,
- unsigned long timeout,
- unsigned long time_to_wait)
+static int
+wait_for_response(struct TCP_Server_Info *server, struct mid_q_entry *midQ)
{
- unsigned long curr_timeout;
+ int error;
- for (;;) {
- curr_timeout = timeout + jiffies;
- wait_event_timeout(ses->server->response_q,
- midQ->midState != MID_REQUEST_SUBMITTED, timeout);
+ error = wait_event_killable(server->response_q,
+ midQ->midState != MID_REQUEST_SUBMITTED);
+ if (error < 0)
+ return -ERESTARTSYS;
- if (time_after(jiffies, curr_timeout) &&
- (midQ->midState == MID_REQUEST_SUBMITTED) &&
- ((ses->server->tcpStatus == CifsGood) ||
- (ses->server->tcpStatus == CifsNew))) {
+ return 0;
+}
- unsigned long lrt;
- /* We timed out. Is the server still
- sending replies ? */
- spin_lock(&GlobalMid_Lock);
- lrt = ses->server->lstrp;
- spin_unlock(&GlobalMid_Lock);
+/*
+ * Send a SMB request and set the callback function in the mid to handle
+ * the result. Caller is responsible for dealing with timeouts.
+ */
+int
+cifs_call_async(struct TCP_Server_Info *server, struct smb_hdr *in_buf,
+ mid_callback_t *callback, void *cbdata)
+{
+ int rc;
+ struct mid_q_entry *mid;
- /* Calculate time_to_wait past last receive time.
- Although we prefer not to time out if the
- server is still responding - we will time
- out if the server takes more than 15 (or 45
- or 180) seconds to respond to this request
- and has not responded to any request from
- other threads on the client within 10 seconds */
- lrt += time_to_wait;
- if (time_after(jiffies, lrt)) {
- /* No replies for time_to_wait. */
- cERROR(1, "server not responding");
- return -1;
- }
- } else {
- return 0;
- }
+ rc = wait_for_free_request(server, CIFS_ASYNC_OP);
+ if (rc)
+ return rc;
+
+ mutex_lock(&server->srv_mutex);
+ mid = AllocMidQEntry(in_buf, server);
+ if (mid == NULL) {
+ mutex_unlock(&server->srv_mutex);
+ return -ENOMEM;
}
-}
+ /* put it on the pending_mid_q */
+ spin_lock(&GlobalMid_Lock);
+ list_add_tail(&mid->qhead, &server->pending_mid_q);
+ spin_unlock(&GlobalMid_Lock);
+
+ rc = cifs_sign_smb(in_buf, server, &mid->sequence_number);
+ if (rc) {
+ mutex_unlock(&server->srv_mutex);
+ goto out_err;
+ }
+
+ mid->callback = callback;
+ mid->callback_data = cbdata;
+ mid->midState = MID_REQUEST_SUBMITTED;
+#ifdef CONFIG_CIFS_STATS2
+ atomic_inc(&server->inSend);
+#endif
+ rc = smb_send(server, in_buf, in_buf->smb_buf_length);
+#ifdef CONFIG_CIFS_STATS2
+ atomic_dec(&server->inSend);
+ mid->when_sent = jiffies;
+#endif
+ mutex_unlock(&server->srv_mutex);
+ if (rc)
+ goto out_err;
+
+ return rc;
+out_err:
+ delete_mid(mid);
+ atomic_dec(&server->inFlight);
+ wake_up(&server->request_q);
+ return rc;
+}
/*
*
@@ -382,6 +426,81 @@ SendReceiveNoRsp(const unsigned int xid, struct cifsSesInfo *ses,
return rc;
}
+static int
+sync_mid_result(struct mid_q_entry *mid, struct TCP_Server_Info *server)
+{
+ int rc = 0;
+
+ cFYI(1, "%s: cmd=%d mid=%d state=%d", __func__, mid->command,
+ mid->mid, mid->midState);
+
+ spin_lock(&GlobalMid_Lock);
+ /* ensure that it's no longer on the pending_mid_q */
+ list_del_init(&mid->qhead);
+
+ switch (mid->midState) {
+ case MID_RESPONSE_RECEIVED:
+ spin_unlock(&GlobalMid_Lock);
+ return rc;
+ case MID_REQUEST_SUBMITTED:
+ /* socket is going down, reject all calls */
+ if (server->tcpStatus == CifsExiting) {
+ cERROR(1, "%s: canceling mid=%d cmd=0x%x state=%d",
+ __func__, mid->mid, mid->command, mid->midState);
+ rc = -EHOSTDOWN;
+ break;
+ }
+ case MID_RETRY_NEEDED:
+ rc = -EAGAIN;
+ break;
+ default:
+ cERROR(1, "%s: invalid mid state mid=%d state=%d", __func__,
+ mid->mid, mid->midState);
+ rc = -EIO;
+ }
+ spin_unlock(&GlobalMid_Lock);
+
+ DeleteMidQEntry(mid);
+ return rc;
+}
+
+/*
+ * An NT cancel request header looks just like the original request except:
+ *
+ * The Command is SMB_COM_NT_CANCEL
+ * The WordCount is zeroed out
+ * The ByteCount is zeroed out
+ *
+ * This function mangles an existing request buffer into a
+ * SMB_COM_NT_CANCEL request and then sends it.
+ */
+static int
+send_nt_cancel(struct TCP_Server_Info *server, struct smb_hdr *in_buf,
+ struct mid_q_entry *mid)
+{
+ int rc = 0;
+
+ /* -4 for RFC1001 length and +2 for BCC field */
+ in_buf->smb_buf_length = sizeof(struct smb_hdr) - 4 + 2;
+ in_buf->Command = SMB_COM_NT_CANCEL;
+ in_buf->WordCount = 0;
+ put_bcc_le(0, in_buf);
+
+ mutex_lock(&server->srv_mutex);
+ rc = cifs_sign_smb(in_buf, server, &mid->sequence_number);
+ if (rc) {
+ mutex_unlock(&server->srv_mutex);
+ return rc;
+ }
+ rc = smb_send(server, in_buf, in_buf->smb_buf_length);
+ mutex_unlock(&server->srv_mutex);
+
+ cFYI(1, "issued NT_CANCEL for mid %u, rc = %d",
+ in_buf->Mid, rc);
+
+ return rc;
+}
+
int
SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
struct kvec *iov, int n_vec, int *pRespBufType /* ret */,
@@ -390,7 +509,6 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
int rc = 0;
int long_op;
unsigned int receive_len;
- unsigned long timeout;
struct mid_q_entry *midQ;
struct smb_hdr *in_buf = iov[0].iov_base;
@@ -413,7 +531,7 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
to the same server. We may make this configurable later or
use ses->maxReq */
- rc = wait_for_free_request(ses, long_op);
+ rc = wait_for_free_request(ses->server, long_op);
if (rc) {
cifs_small_buf_release(in_buf);
return rc;
@@ -457,65 +575,20 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
if (rc < 0)
goto out;
- if (long_op == CIFS_STD_OP)
- timeout = 15 * HZ;
- else if (long_op == CIFS_VLONG_OP) /* e.g. slow writes past EOF */
- timeout = 180 * HZ;
- else if (long_op == CIFS_LONG_OP)
- timeout = 45 * HZ; /* should be greater than
- servers oplock break timeout (about 43 seconds) */
- else if (long_op == CIFS_ASYNC_OP)
+ if (long_op == CIFS_ASYNC_OP)
goto out;
- else if (long_op == CIFS_BLOCKING_OP)
- timeout = 0x7FFFFFFF; /* large, but not so large as to wrap */
- else {
- cERROR(1, "unknown timeout flag %d", long_op);
- rc = -EIO;
- goto out;
- }
-
- /* wait for 15 seconds or until woken up due to response arriving or
- due to last connection to this server being unmounted */
- if (signal_pending(current)) {
- /* if signal pending do not hold up user for full smb timeout
- but we still give response a chance to complete */
- timeout = 2 * HZ;
- }
-
- /* No user interrupts in wait - wreaks havoc with performance */
- wait_for_response(ses, midQ, timeout, 10 * HZ);
-
- spin_lock(&GlobalMid_Lock);
- if (midQ->resp_buf == NULL) {
- cERROR(1, "No response to cmd %d mid %d",
- midQ->command, midQ->mid);
- if (midQ->midState == MID_REQUEST_SUBMITTED) {
- if (ses->server->tcpStatus == CifsExiting)
- rc = -EHOSTDOWN;
- else {
- ses->server->tcpStatus = CifsNeedReconnect;
- midQ->midState = MID_RETRY_NEEDED;
- }
- }
+ rc = wait_for_response(ses->server, midQ);
+ if (rc != 0)
+ goto out;
- if (rc != -EHOSTDOWN) {
- if (midQ->midState == MID_RETRY_NEEDED) {
- rc = -EAGAIN;
- cFYI(1, "marking request for retry");
- } else {
- rc = -EIO;
- }
- }
- spin_unlock(&GlobalMid_Lock);
- DeleteMidQEntry(midQ);
- /* Update # of requests on wire to server */
+ rc = sync_mid_result(midQ, ses->server);
+ if (rc != 0) {
atomic_dec(&ses->server->inFlight);
wake_up(&ses->server->request_q);
return rc;
}
- spin_unlock(&GlobalMid_Lock);
receive_len = midQ->resp_buf->smb_buf_length;
if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
@@ -559,19 +632,18 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
if (receive_len >= sizeof(struct smb_hdr) - 4
/* do not count RFC1001 header */ +
(2 * midQ->resp_buf->WordCount) + 2 /* bcc */ )
- BCC(midQ->resp_buf) =
- le16_to_cpu(BCC_LE(midQ->resp_buf));
+ put_bcc(get_bcc_le(midQ->resp_buf), midQ->resp_buf);
if ((flags & CIFS_NO_RESP) == 0)
midQ->resp_buf = NULL; /* mark it so buf will
not be freed by
- DeleteMidQEntry */
+ delete_mid */
} else {
rc = -EIO;
cFYI(1, "Bad MID state?");
}
out:
- DeleteMidQEntry(midQ);
+ delete_mid(midQ);
atomic_dec(&ses->server->inFlight);
wake_up(&ses->server->request_q);
@@ -585,7 +657,6 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
{
int rc = 0;
unsigned int receive_len;
- unsigned long timeout;
struct mid_q_entry *midQ;
if (ses == NULL) {
@@ -610,7 +681,7 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
return -EIO;
}
- rc = wait_for_free_request(ses, long_op);
+ rc = wait_for_free_request(ses->server, long_op);
if (rc)
return rc;
@@ -649,64 +720,20 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
if (rc < 0)
goto out;
- if (long_op == CIFS_STD_OP)
- timeout = 15 * HZ;
- /* wait for 15 seconds or until woken up due to response arriving or
- due to last connection to this server being unmounted */
- else if (long_op == CIFS_ASYNC_OP)
+ if (long_op == CIFS_ASYNC_OP)
goto out;
- else if (long_op == CIFS_VLONG_OP) /* writes past EOF can be slow */
- timeout = 180 * HZ;
- else if (long_op == CIFS_LONG_OP)
- timeout = 45 * HZ; /* should be greater than
- servers oplock break timeout (about 43 seconds) */
- else if (long_op == CIFS_BLOCKING_OP)
- timeout = 0x7FFFFFFF; /* large but no so large as to wrap */
- else {
- cERROR(1, "unknown timeout flag %d", long_op);
- rc = -EIO;
- goto out;
- }
- if (signal_pending(current)) {
- /* if signal pending do not hold up user for full smb timeout
- but we still give response a chance to complete */
- timeout = 2 * HZ;
- }
-
- /* No user interrupts in wait - wreaks havoc with performance */
- wait_for_response(ses, midQ, timeout, 10 * HZ);
-
- spin_lock(&GlobalMid_Lock);
- if (midQ->resp_buf == NULL) {
- cERROR(1, "No response for cmd %d mid %d",
- midQ->command, midQ->mid);
- if (midQ->midState == MID_REQUEST_SUBMITTED) {
- if (ses->server->tcpStatus == CifsExiting)
- rc = -EHOSTDOWN;
- else {
- ses->server->tcpStatus = CifsNeedReconnect;
- midQ->midState = MID_RETRY_NEEDED;
- }
- }
+ rc = wait_for_response(ses->server, midQ);
+ if (rc != 0)
+ goto out;
- if (rc != -EHOSTDOWN) {
- if (midQ->midState == MID_RETRY_NEEDED) {
- rc = -EAGAIN;
- cFYI(1, "marking request for retry");
- } else {
- rc = -EIO;
- }
- }
- spin_unlock(&GlobalMid_Lock);
- DeleteMidQEntry(midQ);
- /* Update # of requests on wire to server */
+ rc = sync_mid_result(midQ, ses->server);
+ if (rc != 0) {
atomic_dec(&ses->server->inFlight);
wake_up(&ses->server->request_q);
return rc;
}
- spin_unlock(&GlobalMid_Lock);
receive_len = midQ->resp_buf->smb_buf_length;
if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
@@ -748,43 +775,20 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
if (receive_len >= sizeof(struct smb_hdr) - 4
/* do not count RFC1001 header */ +
(2 * out_buf->WordCount) + 2 /* bcc */ )
- BCC(out_buf) = le16_to_cpu(BCC_LE(out_buf));
+ put_bcc(get_bcc_le(midQ->resp_buf), midQ->resp_buf);
} else {
rc = -EIO;
cERROR(1, "Bad MID state?");
}
out:
- DeleteMidQEntry(midQ);
+ delete_mid(midQ);
atomic_dec(&ses->server->inFlight);
wake_up(&ses->server->request_q);
return rc;
}
-/* Send an NT_CANCEL SMB to cause the POSIX blocking lock to return. */
-
-static int
-send_nt_cancel(struct cifsTconInfo *tcon, struct smb_hdr *in_buf,
- struct mid_q_entry *midQ)
-{
- int rc = 0;
- struct cifsSesInfo *ses = tcon->ses;
- __u16 mid = in_buf->Mid;
-
- header_assemble(in_buf, SMB_COM_NT_CANCEL, tcon, 0);
- in_buf->Mid = mid;
- mutex_lock(&ses->server->srv_mutex);
- rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
- if (rc) {
- mutex_unlock(&ses->server->srv_mutex);
- return rc;
- }
- rc = smb_send(ses->server, in_buf, in_buf->smb_buf_length);
- mutex_unlock(&ses->server->srv_mutex);
- return rc;
-}
-
/* We send a LOCKINGX_CANCEL_LOCK to cause the Windows
blocking lock to return. */
@@ -807,7 +811,7 @@ send_lock_cancel(const unsigned int xid, struct cifsTconInfo *tcon,
pSMB->hdr.Mid = GetNextMid(ses->server);
return SendReceive(xid, ses, in_buf, out_buf,
- &bytes_returned, CIFS_STD_OP);
+ &bytes_returned, 0);
}
int
@@ -845,7 +849,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon,
return -EIO;
}
- rc = wait_for_free_request(ses, CIFS_BLOCKING_OP);
+ rc = wait_for_free_request(ses->server, CIFS_BLOCKING_OP);
if (rc)
return rc;
@@ -863,7 +867,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon,
rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
if (rc) {
- DeleteMidQEntry(midQ);
+ delete_mid(midQ);
mutex_unlock(&ses->server->srv_mutex);
return rc;
}
@@ -880,7 +884,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon,
mutex_unlock(&ses->server->srv_mutex);
if (rc < 0) {
- DeleteMidQEntry(midQ);
+ delete_mid(midQ);
return rc;
}
@@ -899,10 +903,9 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon,
if (in_buf->Command == SMB_COM_TRANSACTION2) {
/* POSIX lock. We send a NT_CANCEL SMB to cause the
blocking lock to return. */
-
- rc = send_nt_cancel(tcon, in_buf, midQ);
+ rc = send_nt_cancel(ses->server, in_buf, midQ);
if (rc) {
- DeleteMidQEntry(midQ);
+ delete_mid(midQ);
return rc;
}
} else {
@@ -914,47 +917,22 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon,
/* If we get -ENOLCK back the lock may have
already been removed. Don't exit in this case. */
if (rc && rc != -ENOLCK) {
- DeleteMidQEntry(midQ);
+ delete_mid(midQ);
return rc;
}
}
- /* Wait 5 seconds for the response. */
- if (wait_for_response(ses, midQ, 5 * HZ, 5 * HZ) == 0) {
+ if (wait_for_response(ses->server, midQ) == 0) {
/* We got the response - restart system call. */
rstart = 1;
}
}
- spin_lock(&GlobalMid_Lock);
- if (midQ->resp_buf) {
- spin_unlock(&GlobalMid_Lock);
- receive_len = midQ->resp_buf->smb_buf_length;
- } else {
- cERROR(1, "No response for cmd %d mid %d",
- midQ->command, midQ->mid);
- if (midQ->midState == MID_REQUEST_SUBMITTED) {
- if (ses->server->tcpStatus == CifsExiting)
- rc = -EHOSTDOWN;
- else {
- ses->server->tcpStatus = CifsNeedReconnect;
- midQ->midState = MID_RETRY_NEEDED;
- }
- }
-
- if (rc != -EHOSTDOWN) {
- if (midQ->midState == MID_RETRY_NEEDED) {
- rc = -EAGAIN;
- cFYI(1, "marking request for retry");
- } else {
- rc = -EIO;
- }
- }
- spin_unlock(&GlobalMid_Lock);
- DeleteMidQEntry(midQ);
+ rc = sync_mid_result(midQ, ses->server);
+ if (rc != 0)
return rc;
- }
+ receive_len = midQ->resp_buf->smb_buf_length;
if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
cERROR(1, "Frame too large received. Length: %d Xid: %d",
receive_len, xid);
@@ -998,10 +976,10 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon,
if (receive_len >= sizeof(struct smb_hdr) - 4
/* do not count RFC1001 header */ +
(2 * out_buf->WordCount) + 2 /* bcc */ )
- BCC(out_buf) = le16_to_cpu(BCC_LE(out_buf));
+ put_bcc(get_bcc_le(out_buf), out_buf);
out:
- DeleteMidQEntry(midQ);
+ delete_mid(midQ);
if (rstart && rc == -EACCES)
return -ERESTARTSYS;
return rc;
diff --git a/fs/compat.c b/fs/compat.c
index eb1740a..f6fd0a0 100644
--- a/fs/compat.c
+++ b/fs/compat.c
@@ -257,7 +257,7 @@ static int put_compat_statfs(struct compat_statfs __user *ubuf, struct kstatfs *
}
/*
- * The following statfs calls are copies of code from fs/open.c and
+ * The following statfs calls are copies of code from fs/statfs.c and
* should be checked against those from time to time
*/
asmlinkage long compat_sys_statfs(const char __user *pathname, struct compat_statfs __user *buf)
@@ -320,7 +320,9 @@ static int put_compat_statfs64(struct compat_statfs64 __user *ubuf, struct kstat
__put_user(kbuf->f_namelen, &ubuf->f_namelen) ||
__put_user(kbuf->f_fsid.val[0], &ubuf->f_fsid.val[0]) ||
__put_user(kbuf->f_fsid.val[1], &ubuf->f_fsid.val[1]) ||
- __put_user(kbuf->f_frsize, &ubuf->f_frsize))
+ __put_user(kbuf->f_frsize, &ubuf->f_frsize) ||
+ __put_user(kbuf->f_flags, &ubuf->f_flags) ||
+ __clear_user(ubuf->f_spare, sizeof(ubuf->f_spare)))
return -EFAULT;
return 0;
}
@@ -597,10 +599,8 @@ ssize_t compat_rw_copy_check_uvector(int type,
if (nr_segs > fast_segs) {
ret = -ENOMEM;
iov = kmalloc(nr_segs*sizeof(struct iovec), GFP_KERNEL);
- if (iov == NULL) {
- *ret_pointer = fast_pointer;
+ if (iov == NULL)
goto out;
- }
}
*ret_pointer = iov;
diff --git a/fs/configfs/Kconfig b/fs/configfs/Kconfig
index 13587cc..9febcde 100644
--- a/fs/configfs/Kconfig
+++ b/fs/configfs/Kconfig
@@ -1,8 +1,8 @@
config CONFIGFS_FS
tristate "Userspace-driven configuration filesystem"
- depends on SYSFS
+ select SYSFS
help
- configfs is a ram-based filesystem that provides the converse
+ configfs is a RAM-based filesystem that provides the converse
of sysfs's functionality. Where sysfs is a filesystem-based
view of kernel objects, configfs is a filesystem-based manager
of kernel objects, or config_items.
diff --git a/fs/dcache.c b/fs/dcache.c
index 0c6d5c5..2a6bd9a 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -176,6 +176,7 @@ static void d_free(struct dentry *dentry)
/**
* dentry_rcuwalk_barrier - invalidate in-progress rcu-walk lookups
+ * @dentry: the target dentry
* After this call, in-progress rcu-walk path lookup will fail. This
* should be called after unhashing, and after changing d_inode (if
* the dentry has not already been unhashed).
@@ -281,6 +282,7 @@ static void dentry_lru_move_tail(struct dentry *dentry)
/**
* d_kill - kill dentry and return parent
* @dentry: dentry to kill
+ * @parent: parent dentry
*
* The dentry must already be unhashed and removed from the LRU.
*
@@ -1357,8 +1359,8 @@ EXPORT_SYMBOL(d_alloc_name);
void d_set_d_op(struct dentry *dentry, const struct dentry_operations *op)
{
- BUG_ON(dentry->d_op);
- BUG_ON(dentry->d_flags & (DCACHE_OP_HASH |
+ WARN_ON_ONCE(dentry->d_op);
+ WARN_ON_ONCE(dentry->d_flags & (DCACHE_OP_HASH |
DCACHE_OP_COMPARE |
DCACHE_OP_REVALIDATE |
DCACHE_OP_DELETE ));
@@ -1380,8 +1382,11 @@ EXPORT_SYMBOL(d_set_d_op);
static void __d_instantiate(struct dentry *dentry, struct inode *inode)
{
spin_lock(&dentry->d_lock);
- if (inode)
+ if (inode) {
+ if (unlikely(IS_AUTOMOUNT(inode)))
+ dentry->d_flags |= DCACHE_NEED_AUTOMOUNT;
list_add(&dentry->d_alias, &inode->i_dentry);
+ }
dentry->d_inode = inode;
dentry_rcuwalk_barrier(dentry);
spin_unlock(&dentry->d_lock);
@@ -1970,7 +1975,7 @@ out:
/**
* d_validate - verify dentry provided from insecure source (deprecated)
* @dentry: The dentry alleged to be valid child of @dparent
- * @parent: The parent dentry (known to be valid)
+ * @dparent: The parent dentry (known to be valid)
*
* An insecure source has sent us a dentry, here we verify it and dget() it.
* This is used by ncpfs in its readdir implementation.
diff --git a/fs/direct-io.c b/fs/direct-io.c
index 85882f6..b044705 100644
--- a/fs/direct-io.c
+++ b/fs/direct-io.c
@@ -325,12 +325,16 @@ void dio_end_io(struct bio *bio, int error)
}
EXPORT_SYMBOL_GPL(dio_end_io);
-static int
+static void
dio_bio_alloc(struct dio *dio, struct block_device *bdev,
sector_t first_sector, int nr_vecs)
{
struct bio *bio;
+ /*
+ * bio_alloc() is guaranteed to return a bio when called with
+ * __GFP_WAIT and we request a valid number of vectors.
+ */
bio = bio_alloc(GFP_KERNEL, nr_vecs);
bio->bi_bdev = bdev;
@@ -342,7 +346,6 @@ dio_bio_alloc(struct dio *dio, struct block_device *bdev,
dio->bio = bio;
dio->logical_offset_in_bio = dio->cur_page_fs_offset;
- return 0;
}
/*
@@ -583,8 +586,9 @@ static int dio_new_bio(struct dio *dio, sector_t start_sector)
goto out;
sector = start_sector << (dio->blkbits - 9);
nr_pages = min(dio->pages_in_io, bio_get_nr_vecs(dio->map_bh.b_bdev));
+ nr_pages = min(nr_pages, BIO_MAX_PAGES);
BUG_ON(nr_pages <= 0);
- ret = dio_bio_alloc(dio, dio->map_bh.b_bdev, sector, nr_pages);
+ dio_bio_alloc(dio, dio->map_bh.b_bdev, sector, nr_pages);
dio->boundary = 0;
out:
return ret;
diff --git a/fs/dlm/Kconfig b/fs/dlm/Kconfig
index 2dbb422..1897eb1b 100644
--- a/fs/dlm/Kconfig
+++ b/fs/dlm/Kconfig
@@ -1,8 +1,7 @@
menuconfig DLM
tristate "Distributed Lock Manager (DLM)"
depends on EXPERIMENTAL && INET
- depends on SYSFS && (IPV6 || IPV6=n)
- select CONFIGFS_FS
+ depends on SYSFS && CONFIGFS_FS && (IPV6 || IPV6=n)
select IP_SCTP
help
A general purpose distributed lock manager for kernel or userspace
diff --git a/fs/ecryptfs/crypto.c b/fs/ecryptfs/crypto.c
index cbadc1b..bfd8b68 100644
--- a/fs/ecryptfs/crypto.c
+++ b/fs/ecryptfs/crypto.c
@@ -348,7 +348,7 @@ static int encrypt_scatterlist(struct ecryptfs_crypt_stat *crypt_stat,
BUG_ON(!crypt_stat || !crypt_stat->tfm
|| !(crypt_stat->flags & ECRYPTFS_STRUCT_INITIALIZED));
if (unlikely(ecryptfs_verbosity > 0)) {
- ecryptfs_printk(KERN_DEBUG, "Key size [%d]; key:\n",
+ ecryptfs_printk(KERN_DEBUG, "Key size [%zd]; key:\n",
crypt_stat->key_size);
ecryptfs_dump_hex(crypt_stat->key,
crypt_stat->key_size);
@@ -413,10 +413,9 @@ static int ecryptfs_encrypt_extent(struct page *enc_extent_page,
rc = ecryptfs_derive_iv(extent_iv, crypt_stat,
(extent_base + extent_offset));
if (rc) {
- ecryptfs_printk(KERN_ERR, "Error attempting to "
- "derive IV for extent [0x%.16x]; "
- "rc = [%d]\n", (extent_base + extent_offset),
- rc);
+ ecryptfs_printk(KERN_ERR, "Error attempting to derive IV for "
+ "extent [0x%.16llx]; rc = [%d]\n",
+ (unsigned long long)(extent_base + extent_offset), rc);
goto out;
}
if (unlikely(ecryptfs_verbosity > 0)) {
@@ -443,9 +442,9 @@ static int ecryptfs_encrypt_extent(struct page *enc_extent_page,
}
rc = 0;
if (unlikely(ecryptfs_verbosity > 0)) {
- ecryptfs_printk(KERN_DEBUG, "Encrypt extent [0x%.16x]; "
- "rc = [%d]\n", (extent_base + extent_offset),
- rc);
+ ecryptfs_printk(KERN_DEBUG, "Encrypt extent [0x%.16llx]; "
+ "rc = [%d]\n",
+ (unsigned long long)(extent_base + extent_offset), rc);
ecryptfs_printk(KERN_DEBUG, "First 8 bytes after "
"encryption:\n");
ecryptfs_dump_hex((char *)(page_address(enc_extent_page)), 8);
@@ -540,10 +539,9 @@ static int ecryptfs_decrypt_extent(struct page *page,
rc = ecryptfs_derive_iv(extent_iv, crypt_stat,
(extent_base + extent_offset));
if (rc) {
- ecryptfs_printk(KERN_ERR, "Error attempting to "
- "derive IV for extent [0x%.16x]; "
- "rc = [%d]\n", (extent_base + extent_offset),
- rc);
+ ecryptfs_printk(KERN_ERR, "Error attempting to derive IV for "
+ "extent [0x%.16llx]; rc = [%d]\n",
+ (unsigned long long)(extent_base + extent_offset), rc);
goto out;
}
if (unlikely(ecryptfs_verbosity > 0)) {
@@ -571,9 +569,9 @@ static int ecryptfs_decrypt_extent(struct page *page,
}
rc = 0;
if (unlikely(ecryptfs_verbosity > 0)) {
- ecryptfs_printk(KERN_DEBUG, "Decrypt extent [0x%.16x]; "
- "rc = [%d]\n", (extent_base + extent_offset),
- rc);
+ ecryptfs_printk(KERN_DEBUG, "Decrypt extent [0x%.16llx]; "
+ "rc = [%d]\n",
+ (unsigned long long)(extent_base + extent_offset), rc);
ecryptfs_printk(KERN_DEBUG, "First 8 bytes after "
"decryption:\n");
ecryptfs_dump_hex((char *)(page_address(page)
@@ -780,7 +778,7 @@ int ecryptfs_init_crypt_ctx(struct ecryptfs_crypt_stat *crypt_stat)
}
ecryptfs_printk(KERN_DEBUG,
"Initializing cipher [%s]; strlen = [%d]; "
- "key_size_bits = [%d]\n",
+ "key_size_bits = [%zd]\n",
crypt_stat->cipher, (int)strlen(crypt_stat->cipher),
crypt_stat->key_size << 3);
if (crypt_stat->tfm) {
diff --git a/fs/ecryptfs/ecryptfs_kernel.h b/fs/ecryptfs/ecryptfs_kernel.h
index 413a3c4..dbc84ed 100644
--- a/fs/ecryptfs/ecryptfs_kernel.h
+++ b/fs/ecryptfs/ecryptfs_kernel.h
@@ -192,7 +192,6 @@ ecryptfs_get_key_payload_data(struct key *key)
(((struct user_key_payload*)key->payload.data)->data);
}
-#define ECRYPTFS_SUPER_MAGIC 0xf15f
#define ECRYPTFS_MAX_KEYSET_SIZE 1024
#define ECRYPTFS_MAX_CIPHER_NAME_SIZE 32
#define ECRYPTFS_MAX_NUM_ENC_KEYS 64
@@ -584,6 +583,7 @@ ecryptfs_set_dentry_lower_mnt(struct dentry *dentry, struct vfsmount *lower_mnt)
#define ecryptfs_printk(type, fmt, arg...) \
__ecryptfs_printk(type "%s: " fmt, __func__, ## arg);
+__attribute__ ((format(printf, 1, 2)))
void __ecryptfs_printk(const char *fmt, ...);
extern const struct file_operations ecryptfs_main_fops;
diff --git a/fs/ecryptfs/file.c b/fs/ecryptfs/file.c
index 91da029..81e10e6 100644
--- a/fs/ecryptfs/file.c
+++ b/fs/ecryptfs/file.c
@@ -47,7 +47,7 @@ static ssize_t ecryptfs_read_update_atime(struct kiocb *iocb,
const struct iovec *iov,
unsigned long nr_segs, loff_t pos)
{
- int rc;
+ ssize_t rc;
struct dentry *lower_dentry;
struct vfsmount *lower_vfsmount;
struct file *file = iocb->ki_filp;
@@ -191,18 +191,16 @@ static int ecryptfs_open(struct inode *inode, struct file *file)
| ECRYPTFS_ENCRYPTED);
}
mutex_unlock(&crypt_stat->cs_mutex);
- if (!ecryptfs_inode_to_private(inode)->lower_file) {
- rc = ecryptfs_init_persistent_file(ecryptfs_dentry);
- if (rc) {
- printk(KERN_ERR "%s: Error attempting to initialize "
- "the persistent file for the dentry with name "
- "[%s]; rc = [%d]\n", __func__,
- ecryptfs_dentry->d_name.name, rc);
- goto out_free;
- }
+ rc = ecryptfs_init_persistent_file(ecryptfs_dentry);
+ if (rc) {
+ printk(KERN_ERR "%s: Error attempting to initialize "
+ "the persistent file for the dentry with name "
+ "[%s]; rc = [%d]\n", __func__,
+ ecryptfs_dentry->d_name.name, rc);
+ goto out_free;
}
- if ((ecryptfs_inode_to_private(inode)->lower_file->f_flags & O_RDONLY)
- && !(file->f_flags & O_RDONLY)) {
+ if ((ecryptfs_inode_to_private(inode)->lower_file->f_flags & O_ACCMODE)
+ == O_RDONLY && (file->f_flags & O_ACCMODE) != O_RDONLY) {
rc = -EPERM;
printk(KERN_WARNING "%s: Lower persistent file is RO; eCryptfs "
"file must hence be opened RO\n", __func__);
@@ -243,9 +241,9 @@ static int ecryptfs_open(struct inode *inode, struct file *file)
}
}
mutex_unlock(&crypt_stat->cs_mutex);
- ecryptfs_printk(KERN_DEBUG, "inode w/ addr = [0x%p], i_ino = [0x%.16x] "
- "size: [0x%.16x]\n", inode, inode->i_ino,
- i_size_read(inode));
+ ecryptfs_printk(KERN_DEBUG, "inode w/ addr = [0x%p], i_ino = "
+ "[0x%.16lx] size: [0x%.16llx]\n", inode, inode->i_ino,
+ (unsigned long long)i_size_read(inode));
goto out;
out_free:
kmem_cache_free(ecryptfs_file_info_cache,
diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c
index 64ff023..bd33f87 100644
--- a/fs/ecryptfs/inode.c
+++ b/fs/ecryptfs/inode.c
@@ -185,15 +185,13 @@ static int ecryptfs_initialize_file(struct dentry *ecryptfs_dentry)
"context; rc = [%d]\n", rc);
goto out;
}
- if (!ecryptfs_inode_to_private(ecryptfs_dentry->d_inode)->lower_file) {
- rc = ecryptfs_init_persistent_file(ecryptfs_dentry);
- if (rc) {
- printk(KERN_ERR "%s: Error attempting to initialize "
- "the persistent file for the dentry with name "
- "[%s]; rc = [%d]\n", __func__,
- ecryptfs_dentry->d_name.name, rc);
- goto out;
- }
+ rc = ecryptfs_init_persistent_file(ecryptfs_dentry);
+ if (rc) {
+ printk(KERN_ERR "%s: Error attempting to initialize "
+ "the persistent file for the dentry with name "
+ "[%s]; rc = [%d]\n", __func__,
+ ecryptfs_dentry->d_name.name, rc);
+ goto out;
}
rc = ecryptfs_write_metadata(ecryptfs_dentry);
if (rc) {
@@ -302,15 +300,13 @@ int ecryptfs_lookup_and_interpose_lower(struct dentry *ecryptfs_dentry,
rc = -ENOMEM;
goto out;
}
- if (!ecryptfs_inode_to_private(ecryptfs_dentry->d_inode)->lower_file) {
- rc = ecryptfs_init_persistent_file(ecryptfs_dentry);
- if (rc) {
- printk(KERN_ERR "%s: Error attempting to initialize "
- "the persistent file for the dentry with name "
- "[%s]; rc = [%d]\n", __func__,
- ecryptfs_dentry->d_name.name, rc);
- goto out_free_kmem;
- }
+ rc = ecryptfs_init_persistent_file(ecryptfs_dentry);
+ if (rc) {
+ printk(KERN_ERR "%s: Error attempting to initialize "
+ "the persistent file for the dentry with name "
+ "[%s]; rc = [%d]\n", __func__,
+ ecryptfs_dentry->d_name.name, rc);
+ goto out_free_kmem;
}
crypt_stat = &ecryptfs_inode_to_private(
ecryptfs_dentry->d_inode)->crypt_stat;
diff --git a/fs/ecryptfs/keystore.c b/fs/ecryptfs/keystore.c
index b1f6858..c1436cf 100644
--- a/fs/ecryptfs/keystore.c
+++ b/fs/ecryptfs/keystore.c
@@ -59,7 +59,7 @@ static int process_request_key_err(long err_code)
break;
default:
ecryptfs_printk(KERN_WARNING, "Unknown error code: "
- "[0x%.16x]\n", err_code);
+ "[0x%.16lx]\n", err_code);
rc = -EINVAL;
}
return rc;
@@ -130,7 +130,7 @@ int ecryptfs_write_packet_length(char *dest, size_t size,
} else {
rc = -EINVAL;
ecryptfs_printk(KERN_WARNING,
- "Unsupported packet size: [%d]\n", size);
+ "Unsupported packet size: [%zd]\n", size);
}
return rc;
}
@@ -1672,7 +1672,7 @@ decrypt_passphrase_encrypted_session_key(struct ecryptfs_auth_tok *auth_tok,
auth_tok->session_key.decrypted_key_size);
crypt_stat->flags |= ECRYPTFS_KEY_VALID;
if (unlikely(ecryptfs_verbosity > 0)) {
- ecryptfs_printk(KERN_DEBUG, "FEK of size [%d]:\n",
+ ecryptfs_printk(KERN_DEBUG, "FEK of size [%zd]:\n",
crypt_stat->key_size);
ecryptfs_dump_hex(crypt_stat->key,
crypt_stat->key_size);
@@ -1754,7 +1754,7 @@ int ecryptfs_parse_packet_set(struct ecryptfs_crypt_stat *crypt_stat,
if (ECRYPTFS_SIG_SIZE != tag_11_contents_size) {
ecryptfs_printk(KERN_ERR, "Expected "
"signature of size [%d]; "
- "read size [%d]\n",
+ "read size [%zd]\n",
ECRYPTFS_SIG_SIZE,
tag_11_contents_size);
rc = -EIO;
@@ -1787,8 +1787,8 @@ int ecryptfs_parse_packet_set(struct ecryptfs_crypt_stat *crypt_stat,
goto out_wipe_list;
break;
default:
- ecryptfs_printk(KERN_DEBUG, "No packet at offset "
- "[%d] of the file header; hex value of "
+ ecryptfs_printk(KERN_DEBUG, "No packet at offset [%zd] "
+ "of the file header; hex value of "
"character is [0x%.2x]\n", i, src[i]);
next_packet_is_auth_tok_packet = 0;
}
@@ -1864,8 +1864,8 @@ found_matching_auth_tok:
"session key for authentication token with sig "
"[%.*s]; rc = [%d]. Removing auth tok "
"candidate from the list and searching for "
- "the next match.\n", candidate_auth_tok_sig,
- ECRYPTFS_SIG_SIZE_HEX, rc);
+ "the next match.\n", ECRYPTFS_SIG_SIZE_HEX,
+ candidate_auth_tok_sig, rc);
list_for_each_entry_safe(auth_tok_list_item,
auth_tok_list_item_tmp,
&auth_tok_list, list) {
@@ -2168,7 +2168,7 @@ write_tag_3_packet(char *dest, size_t *remaining_bytes,
if (encrypted_session_key_valid) {
ecryptfs_printk(KERN_DEBUG, "encrypted_session_key_valid != 0; "
"using auth_tok->session_key.encrypted_key, "
- "where key_rec->enc_key_size = [%d]\n",
+ "where key_rec->enc_key_size = [%zd]\n",
key_rec->enc_key_size);
memcpy(key_rec->enc_key,
auth_tok->session_key.encrypted_key,
@@ -2198,7 +2198,7 @@ write_tag_3_packet(char *dest, size_t *remaining_bytes,
if (rc < 1 || rc > 2) {
ecryptfs_printk(KERN_ERR, "Error generating scatterlist "
"for crypt_stat session key; expected rc = 1; "
- "got rc = [%d]. key_rec->enc_key_size = [%d]\n",
+ "got rc = [%d]. key_rec->enc_key_size = [%zd]\n",
rc, key_rec->enc_key_size);
rc = -ENOMEM;
goto out;
@@ -2209,7 +2209,7 @@ write_tag_3_packet(char *dest, size_t *remaining_bytes,
ecryptfs_printk(KERN_ERR, "Error generating scatterlist "
"for crypt_stat encrypted session key; "
"expected rc = 1; got rc = [%d]. "
- "key_rec->enc_key_size = [%d]\n", rc,
+ "key_rec->enc_key_size = [%zd]\n", rc,
key_rec->enc_key_size);
rc = -ENOMEM;
goto out;
@@ -2224,7 +2224,7 @@ write_tag_3_packet(char *dest, size_t *remaining_bytes,
goto out;
}
rc = 0;
- ecryptfs_printk(KERN_DEBUG, "Encrypting [%d] bytes of the key\n",
+ ecryptfs_printk(KERN_DEBUG, "Encrypting [%zd] bytes of the key\n",
crypt_stat->key_size);
rc = crypto_blkcipher_encrypt(&desc, dst_sg, src_sg,
(*key_rec).enc_key_size);
@@ -2235,7 +2235,7 @@ write_tag_3_packet(char *dest, size_t *remaining_bytes,
}
ecryptfs_printk(KERN_DEBUG, "This should be the encrypted key:\n");
if (ecryptfs_verbosity > 0) {
- ecryptfs_printk(KERN_DEBUG, "EFEK of size [%d]:\n",
+ ecryptfs_printk(KERN_DEBUG, "EFEK of size [%zd]:\n",
key_rec->enc_key_size);
ecryptfs_dump_hex(key_rec->enc_key,
key_rec->enc_key_size);
diff --git a/fs/ecryptfs/main.c b/fs/ecryptfs/main.c
index d3b28ab..758323a 100644
--- a/fs/ecryptfs/main.c
+++ b/fs/ecryptfs/main.c
@@ -36,6 +36,7 @@
#include <linux/parser.h>
#include <linux/fs_stack.h>
#include <linux/slab.h>
+#include <linux/magic.h>
#include "ecryptfs_kernel.h"
/**
@@ -564,6 +565,7 @@ static struct dentry *ecryptfs_mount(struct file_system_type *fs_type, int flags
ecryptfs_set_superblock_lower(s, path.dentry->d_sb);
s->s_maxbytes = path.dentry->d_sb->s_maxbytes;
s->s_blocksize = path.dentry->d_sb->s_blocksize;
+ s->s_magic = ECRYPTFS_SUPER_MAGIC;
inode = ecryptfs_get_inode(path.dentry->d_inode, s);
rc = PTR_ERR(inode);
@@ -808,9 +810,10 @@ static int __init ecryptfs_init(void)
ecryptfs_printk(KERN_ERR, "The eCryptfs extent size is "
"larger than the host's page size, and so "
"eCryptfs cannot run on this system. The "
- "default eCryptfs extent size is [%d] bytes; "
- "the page size is [%d] bytes.\n",
- ECRYPTFS_DEFAULT_EXTENT_SIZE, PAGE_CACHE_SIZE);
+ "default eCryptfs extent size is [%u] bytes; "
+ "the page size is [%lu] bytes.\n",
+ ECRYPTFS_DEFAULT_EXTENT_SIZE,
+ (unsigned long)PAGE_CACHE_SIZE);
goto out;
}
rc = ecryptfs_init_kmem_caches();
diff --git a/fs/ecryptfs/mmap.c b/fs/ecryptfs/mmap.c
index b1d8275..cc64fca 100644
--- a/fs/ecryptfs/mmap.c
+++ b/fs/ecryptfs/mmap.c
@@ -65,7 +65,7 @@ static int ecryptfs_writepage(struct page *page, struct writeback_control *wbc)
rc = ecryptfs_encrypt_page(page);
if (rc) {
ecryptfs_printk(KERN_WARNING, "Error encrypting "
- "page (upper index [0x%.16x])\n", page->index);
+ "page (upper index [0x%.16lx])\n", page->index);
ClearPageUptodate(page);
goto out;
}
@@ -237,7 +237,7 @@ out:
ClearPageUptodate(page);
else
SetPageUptodate(page);
- ecryptfs_printk(KERN_DEBUG, "Unlocking page with index = [0x%.16x]\n",
+ ecryptfs_printk(KERN_DEBUG, "Unlocking page with index = [0x%.16lx]\n",
page->index);
unlock_page(page);
return rc;
@@ -290,6 +290,7 @@ static int ecryptfs_write_begin(struct file *file,
return -ENOMEM;
*pagep = page;
+ prev_page_end_size = ((loff_t)index << PAGE_CACHE_SHIFT);
if (!PageUptodate(page)) {
struct ecryptfs_crypt_stat *crypt_stat =
&ecryptfs_inode_to_private(mapping->host)->crypt_stat;
@@ -335,18 +336,23 @@ static int ecryptfs_write_begin(struct file *file,
SetPageUptodate(page);
}
} else {
- rc = ecryptfs_decrypt_page(page);
- if (rc) {
- printk(KERN_ERR "%s: Error decrypting page "
- "at index [%ld]; rc = [%d]\n",
- __func__, page->index, rc);
- ClearPageUptodate(page);
- goto out;
+ if (prev_page_end_size
+ >= i_size_read(page->mapping->host)) {
+ zero_user(page, 0, PAGE_CACHE_SIZE);
+ } else {
+ rc = ecryptfs_decrypt_page(page);
+ if (rc) {
+ printk(KERN_ERR "%s: Error decrypting "
+ "page at index [%ld]; "
+ "rc = [%d]\n",
+ __func__, page->index, rc);
+ ClearPageUptodate(page);
+ goto out;
+ }
}
SetPageUptodate(page);
}
}
- prev_page_end_size = ((loff_t)index << PAGE_CACHE_SHIFT);
/* If creating a page or more of holes, zero them out via truncate.
* Note, this will increase i_size. */
if (index != 0) {
@@ -488,7 +494,7 @@ static int ecryptfs_write_end(struct file *file,
} else
ecryptfs_printk(KERN_DEBUG, "Not a new file\n");
ecryptfs_printk(KERN_DEBUG, "Calling fill_zeros_to_end_of_page"
- "(page w/ index = [0x%.16x], to = [%d])\n", index, to);
+ "(page w/ index = [0x%.16lx], to = [%d])\n", index, to);
if (!(crypt_stat->flags & ECRYPTFS_ENCRYPTED)) {
rc = ecryptfs_write_lower_page_segment(ecryptfs_inode, page, 0,
to);
@@ -503,19 +509,20 @@ static int ecryptfs_write_end(struct file *file,
rc = fill_zeros_to_end_of_page(page, to);
if (rc) {
ecryptfs_printk(KERN_WARNING, "Error attempting to fill "
- "zeros in page with index = [0x%.16x]\n", index);
+ "zeros in page with index = [0x%.16lx]\n", index);
goto out;
}
rc = ecryptfs_encrypt_page(page);
if (rc) {
ecryptfs_printk(KERN_WARNING, "Error encrypting page (upper "
- "index [0x%.16x])\n", index);
+ "index [0x%.16lx])\n", index);
goto out;
}
if (pos + copied > i_size_read(ecryptfs_inode)) {
i_size_write(ecryptfs_inode, pos + copied);
ecryptfs_printk(KERN_DEBUG, "Expanded file size to "
- "[0x%.16x]\n", i_size_read(ecryptfs_inode));
+ "[0x%.16llx]\n",
+ (unsigned long long)i_size_read(ecryptfs_inode));
}
rc = ecryptfs_write_inode_size_to_metadata(ecryptfs_inode);
if (rc)
diff --git a/fs/ext3/super.c b/fs/ext3/super.c
index 7aa767d..85c8cc8 100644
--- a/fs/ext3/super.c
+++ b/fs/ext3/super.c
@@ -754,7 +754,7 @@ static int ext3_release_dquot(struct dquot *dquot);
static int ext3_mark_dquot_dirty(struct dquot *dquot);
static int ext3_write_info(struct super_block *sb, int type);
static int ext3_quota_on(struct super_block *sb, int type, int format_id,
- char *path);
+ struct path *path);
static int ext3_quota_on_mount(struct super_block *sb, int type);
static ssize_t ext3_quota_read(struct super_block *sb, int type, char *data,
size_t len, loff_t off);
@@ -2877,27 +2877,20 @@ static int ext3_quota_on_mount(struct super_block *sb, int type)
* Standard function to be called on quota_on
*/
static int ext3_quota_on(struct super_block *sb, int type, int format_id,
- char *name)
+ struct path *path)
{
int err;
- struct path path;
if (!test_opt(sb, QUOTA))
return -EINVAL;
- err = kern_path(name, LOOKUP_FOLLOW, &path);
- if (err)
- return err;
-
/* Quotafile not on the same filesystem? */
- if (path.mnt->mnt_sb != sb) {
- path_put(&path);
+ if (path->mnt->mnt_sb != sb)
return -EXDEV;
- }
/* Journaling quota? */
if (EXT3_SB(sb)->s_qf_names[type]) {
/* Quotafile not of fs root? */
- if (path.dentry->d_parent != sb->s_root)
+ if (path->dentry->d_parent != sb->s_root)
ext3_msg(sb, KERN_WARNING,
"warning: Quota file not on filesystem root. "
"Journaled quota will not work.");
@@ -2907,7 +2900,7 @@ static int ext3_quota_on(struct super_block *sb, int type, int format_id,
* When we journal data on quota file, we have to flush journal to see
* all updates to the file when we bypass pagecache...
*/
- if (ext3_should_journal_data(path.dentry->d_inode)) {
+ if (ext3_should_journal_data(path->dentry->d_inode)) {
/*
* We don't need to lock updates but journal_flush() could
* otherwise be livelocked...
@@ -2915,15 +2908,11 @@ static int ext3_quota_on(struct super_block *sb, int type, int format_id,
journal_lock_updates(EXT3_SB(sb)->s_journal);
err = journal_flush(EXT3_SB(sb)->s_journal);
journal_unlock_updates(EXT3_SB(sb)->s_journal);
- if (err) {
- path_put(&path);
+ if (err)
return err;
- }
}
- err = dquot_quota_on_path(sb, type, format_id, &path);
- path_put(&path);
- return err;
+ return dquot_quota_on(sb, type, format_id, path);
}
/* Read data from quotafile - avoid pagecache and such because we cannot afford
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index 1de65f5..0c8d97b 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -2065,7 +2065,7 @@ extern int ext4_ext_map_blocks(handle_t *handle, struct inode *inode,
extern void ext4_ext_truncate(struct inode *);
extern void ext4_ext_init(struct super_block *);
extern void ext4_ext_release(struct super_block *);
-extern long ext4_fallocate(struct inode *inode, int mode, loff_t offset,
+extern long ext4_fallocate(struct file *file, int mode, loff_t offset,
loff_t len);
extern int ext4_convert_unwritten_extents(struct inode *inode, loff_t offset,
ssize_t len);
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
index c4068f6..63a7581 100644
--- a/fs/ext4/extents.c
+++ b/fs/ext4/extents.c
@@ -3627,14 +3627,15 @@ static void ext4_falloc_update_inode(struct inode *inode,
}
/*
- * preallocate space for a file. This implements ext4's fallocate inode
+ * preallocate space for a file. This implements ext4's fallocate file
* operation, which gets called from sys_fallocate system call.
* For block-mapped files, posix_fallocate should fall back to the method
* of writing zeroes to the required new blocks (the same behavior which is
* expected for file systems which do not support fallocate() system call).
*/
-long ext4_fallocate(struct inode *inode, int mode, loff_t offset, loff_t len)
+long ext4_fallocate(struct file *file, int mode, loff_t offset, loff_t len)
{
+ struct inode *inode = file->f_path.dentry->d_inode;
handle_t *handle;
loff_t new_size;
unsigned int max_blocks;
@@ -3645,7 +3646,7 @@ long ext4_fallocate(struct inode *inode, int mode, loff_t offset, loff_t len)
unsigned int credits, blkbits = inode->i_blkbits;
/* We only support the FALLOC_FL_KEEP_SIZE mode */
- if (mode && (mode != FALLOC_FL_KEEP_SIZE))
+ if (mode & ~FALLOC_FL_KEEP_SIZE)
return -EOPNOTSUPP;
/*
@@ -3655,10 +3656,6 @@ long ext4_fallocate(struct inode *inode, int mode, loff_t offset, loff_t len)
if (!(ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)))
return -EOPNOTSUPP;
- /* preallocation to directories is currently not supported */
- if (S_ISDIR(inode->i_mode))
- return -ENODEV;
-
map.m_lblk = offset >> blkbits;
/*
* We can't just convert len to max_blocks because
diff --git a/fs/ext4/file.c b/fs/ext4/file.c
index bb003dc..2e8322c 100644
--- a/fs/ext4/file.c
+++ b/fs/ext4/file.c
@@ -210,6 +210,7 @@ const struct file_operations ext4_file_operations = {
.fsync = ext4_sync_file,
.splice_read = generic_file_splice_read,
.splice_write = generic_file_splice_write,
+ .fallocate = ext4_fallocate,
};
const struct inode_operations ext4_file_inode_operations = {
@@ -223,7 +224,6 @@ const struct inode_operations ext4_file_inode_operations = {
.removexattr = generic_removexattr,
#endif
.check_acl = ext4_check_acl,
- .fallocate = ext4_fallocate,
.fiemap = ext4_fiemap,
};
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index cb10a06..48ce561 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -1161,7 +1161,7 @@ static int ext4_release_dquot(struct dquot *dquot);
static int ext4_mark_dquot_dirty(struct dquot *dquot);
static int ext4_write_info(struct super_block *sb, int type);
static int ext4_quota_on(struct super_block *sb, int type, int format_id,
- char *path);
+ struct path *path);
static int ext4_quota_off(struct super_block *sb, int type);
static int ext4_quota_on_mount(struct super_block *sb, int type);
static ssize_t ext4_quota_read(struct super_block *sb, int type, char *data,
@@ -4558,27 +4558,20 @@ static int ext4_quota_on_mount(struct super_block *sb, int type)
* Standard function to be called on quota_on
*/
static int ext4_quota_on(struct super_block *sb, int type, int format_id,
- char *name)
+ struct path *path)
{
int err;
- struct path path;
if (!test_opt(sb, QUOTA))
return -EINVAL;
- err = kern_path(name, LOOKUP_FOLLOW, &path);
- if (err)
- return err;
-
/* Quotafile not on the same filesystem? */
- if (path.mnt->mnt_sb != sb) {
- path_put(&path);
+ if (path->mnt->mnt_sb != sb)
return -EXDEV;
- }
/* Journaling quota? */
if (EXT4_SB(sb)->s_qf_names[type]) {
/* Quotafile not in fs root? */
- if (path.dentry->d_parent != sb->s_root)
+ if (path->dentry->d_parent != sb->s_root)
ext4_msg(sb, KERN_WARNING,
"Quota file not on filesystem root. "
"Journaled quota will not work");
@@ -4589,7 +4582,7 @@ static int ext4_quota_on(struct super_block *sb, int type, int format_id,
* all updates to the file when we bypass pagecache...
*/
if (EXT4_SB(sb)->s_journal &&
- ext4_should_journal_data(path.dentry->d_inode)) {
+ ext4_should_journal_data(path->dentry->d_inode)) {
/*
* We don't need to lock updates but journal_flush() could
* otherwise be livelocked...
@@ -4597,15 +4590,11 @@ static int ext4_quota_on(struct super_block *sb, int type, int format_id,
jbd2_journal_lock_updates(EXT4_SB(sb)->s_journal);
err = jbd2_journal_flush(EXT4_SB(sb)->s_journal);
jbd2_journal_unlock_updates(EXT4_SB(sb)->s_journal);
- if (err) {
- path_put(&path);
+ if (err)
return err;
- }
}
- err = dquot_quota_on_path(sb, type, format_id, &path);
- path_put(&path);
- return err;
+ return dquot_quota_on(sb, type, format_id, path);
}
static int ext4_quota_off(struct super_block *sb, int type)
diff --git a/fs/file_table.c b/fs/file_table.c
index c3dee38..c3e89ad 100644
--- a/fs/file_table.c
+++ b/fs/file_table.c
@@ -311,7 +311,7 @@ struct file *fget_light(unsigned int fd, int *fput_needed)
struct files_struct *files = current->files;
*fput_needed = 0;
- if (likely((atomic_read(&files->count) == 1))) {
+ if (atomic_read(&files->count) == 1) {
file = fcheck_files(files, fd);
} else {
rcu_read_lock();
diff --git a/fs/fs_struct.c b/fs/fs_struct.c
index 68ca487..78b519c 100644
--- a/fs/fs_struct.c
+++ b/fs/fs_struct.c
@@ -4,6 +4,19 @@
#include <linux/path.h>
#include <linux/slab.h>
#include <linux/fs_struct.h>
+#include "internal.h"
+
+static inline void path_get_longterm(struct path *path)
+{
+ path_get(path);
+ mnt_make_longterm(path->mnt);
+}
+
+static inline void path_put_longterm(struct path *path)
+{
+ mnt_make_shortterm(path->mnt);
+ path_put(path);
+}
/*
* Replace the fs->{rootmnt,root} with {mnt,dentry}. Put the old values.
@@ -17,11 +30,11 @@ void set_fs_root(struct fs_struct *fs, struct path *path)
write_seqcount_begin(&fs->seq);
old_root = fs->root;
fs->root = *path;
- path_get_long(path);
+ path_get_longterm(path);
write_seqcount_end(&fs->seq);
spin_unlock(&fs->lock);
if (old_root.dentry)
- path_put_long(&old_root);
+ path_put_longterm(&old_root);
}
/*
@@ -36,12 +49,12 @@ void set_fs_pwd(struct fs_struct *fs, struct path *path)
write_seqcount_begin(&fs->seq);
old_pwd = fs->pwd;
fs->pwd = *path;
- path_get_long(path);
+ path_get_longterm(path);
write_seqcount_end(&fs->seq);
spin_unlock(&fs->lock);
if (old_pwd.dentry)
- path_put_long(&old_pwd);
+ path_put_longterm(&old_pwd);
}
void chroot_fs_refs(struct path *old_root, struct path *new_root)
@@ -59,13 +72,13 @@ void chroot_fs_refs(struct path *old_root, struct path *new_root)
write_seqcount_begin(&fs->seq);
if (fs->root.dentry == old_root->dentry
&& fs->root.mnt == old_root->mnt) {
- path_get_long(new_root);
+ path_get_longterm(new_root);
fs->root = *new_root;
count++;
}
if (fs->pwd.dentry == old_root->dentry
&& fs->pwd.mnt == old_root->mnt) {
- path_get_long(new_root);
+ path_get_longterm(new_root);
fs->pwd = *new_root;
count++;
}
@@ -76,13 +89,13 @@ void chroot_fs_refs(struct path *old_root, struct path *new_root)
} while_each_thread(g, p);
read_unlock(&tasklist_lock);
while (count--)
- path_put_long(old_root);
+ path_put_longterm(old_root);
}
void free_fs_struct(struct fs_struct *fs)
{
- path_put_long(&fs->root);
- path_put_long(&fs->pwd);
+ path_put_longterm(&fs->root);
+ path_put_longterm(&fs->pwd);
kmem_cache_free(fs_cachep, fs);
}
@@ -118,9 +131,9 @@ struct fs_struct *copy_fs_struct(struct fs_struct *old)
spin_lock(&old->lock);
fs->root = old->root;
- path_get_long(&fs->root);
+ path_get_longterm(&fs->root);
fs->pwd = old->pwd;
- path_get_long(&fs->pwd);
+ path_get_longterm(&fs->pwd);
spin_unlock(&old->lock);
}
return fs;
diff --git a/fs/fscache/operation.c b/fs/fscache/operation.c
index b9f34ea..48a18f1 100644
--- a/fs/fscache/operation.c
+++ b/fs/fscache/operation.c
@@ -101,7 +101,7 @@ int fscache_submit_exclusive_op(struct fscache_object *object,
object->n_ops++;
object->n_exclusive++; /* reads and writes must wait */
- if (object->n_ops > 0) {
+ if (object->n_ops > 1) {
atomic_inc(&op->usage);
list_add_tail(&op->pend_link, &object->pending_ops);
fscache_stat(&fscache_n_op_pend);
diff --git a/fs/gfs2/file.c b/fs/gfs2/file.c
index fca6689..7cfdcb9 100644
--- a/fs/gfs2/file.c
+++ b/fs/gfs2/file.c
@@ -19,6 +19,8 @@
#include <linux/fs.h>
#include <linux/gfs2_ondisk.h>
#include <linux/ext2_fs.h>
+#include <linux/falloc.h>
+#include <linux/swap.h>
#include <linux/crc32.h>
#include <linux/writeback.h>
#include <asm/uaccess.h>
@@ -610,6 +612,260 @@ static ssize_t gfs2_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
return generic_file_aio_write(iocb, iov, nr_segs, pos);
}
+static void empty_write_end(struct page *page, unsigned from,
+ unsigned to)
+{
+ struct gfs2_inode *ip = GFS2_I(page->mapping->host);
+
+ page_zero_new_buffers(page, from, to);
+ flush_dcache_page(page);
+ mark_page_accessed(page);
+
+ if (!gfs2_is_writeback(ip))
+ gfs2_page_add_databufs(ip, page, from, to);
+
+ block_commit_write(page, from, to);
+}
+
+static int write_empty_blocks(struct page *page, unsigned from, unsigned to)
+{
+ unsigned start, end, next;
+ struct buffer_head *bh, *head;
+ int error;
+
+ if (!page_has_buffers(page)) {
+ error = __block_write_begin(page, from, to - from, gfs2_block_map);
+ if (unlikely(error))
+ return error;
+
+ empty_write_end(page, from, to);
+ return 0;
+ }
+
+ bh = head = page_buffers(page);
+ next = end = 0;
+ while (next < from) {
+ next += bh->b_size;
+ bh = bh->b_this_page;
+ }
+ start = next;
+ do {
+ next += bh->b_size;
+ if (buffer_mapped(bh)) {
+ if (end) {
+ error = __block_write_begin(page, start, end - start,
+ gfs2_block_map);
+ if (unlikely(error))
+ return error;
+ empty_write_end(page, start, end);
+ end = 0;
+ }
+ start = next;
+ }
+ else
+ end = next;
+ bh = bh->b_this_page;
+ } while (next < to);
+
+ if (end) {
+ error = __block_write_begin(page, start, end - start, gfs2_block_map);
+ if (unlikely(error))
+ return error;
+ empty_write_end(page, start, end);
+ }
+
+ return 0;
+}
+
+static int fallocate_chunk(struct inode *inode, loff_t offset, loff_t len,
+ int mode)
+{
+ struct gfs2_inode *ip = GFS2_I(inode);
+ struct buffer_head *dibh;
+ int error;
+ u64 start = offset >> PAGE_CACHE_SHIFT;
+ unsigned int start_offset = offset & ~PAGE_CACHE_MASK;
+ u64 end = (offset + len - 1) >> PAGE_CACHE_SHIFT;
+ pgoff_t curr;
+ struct page *page;
+ unsigned int end_offset = (offset + len) & ~PAGE_CACHE_MASK;
+ unsigned int from, to;
+
+ if (!end_offset)
+ end_offset = PAGE_CACHE_SIZE;
+
+ error = gfs2_meta_inode_buffer(ip, &dibh);
+ if (unlikely(error))
+ goto out;
+
+ gfs2_trans_add_bh(ip->i_gl, dibh, 1);
+
+ if (gfs2_is_stuffed(ip)) {
+ error = gfs2_unstuff_dinode(ip, NULL);
+ if (unlikely(error))
+ goto out;
+ }
+
+ curr = start;
+ offset = start << PAGE_CACHE_SHIFT;
+ from = start_offset;
+ to = PAGE_CACHE_SIZE;
+ while (curr <= end) {
+ page = grab_cache_page_write_begin(inode->i_mapping, curr,
+ AOP_FLAG_NOFS);
+ if (unlikely(!page)) {
+ error = -ENOMEM;
+ goto out;
+ }
+
+ if (curr == end)
+ to = end_offset;
+ error = write_empty_blocks(page, from, to);
+ if (!error && offset + to > inode->i_size &&
+ !(mode & FALLOC_FL_KEEP_SIZE)) {
+ i_size_write(inode, offset + to);
+ }
+ unlock_page(page);
+ page_cache_release(page);
+ if (error)
+ goto out;
+ curr++;
+ offset += PAGE_CACHE_SIZE;
+ from = 0;
+ }
+
+ gfs2_dinode_out(ip, dibh->b_data);
+ mark_inode_dirty(inode);
+
+ brelse(dibh);
+
+out:
+ return error;
+}
+
+static void calc_max_reserv(struct gfs2_inode *ip, loff_t max, loff_t *len,
+ unsigned int *data_blocks, unsigned int *ind_blocks)
+{
+ const struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
+ unsigned int max_blocks = ip->i_alloc->al_rgd->rd_free_clone;
+ unsigned int tmp, max_data = max_blocks - 3 * (sdp->sd_max_height - 1);
+
+ for (tmp = max_data; tmp > sdp->sd_diptrs;) {
+ tmp = DIV_ROUND_UP(tmp, sdp->sd_inptrs);
+ max_data -= tmp;
+ }
+ /* This calculation isn't the exact reverse of gfs2_write_calc_reserve,
+ so it might end up with fewer data blocks */
+ if (max_data <= *data_blocks)
+ return;
+ *data_blocks = max_data;
+ *ind_blocks = max_blocks - max_data;
+ *len = ((loff_t)max_data - 3) << sdp->sd_sb.sb_bsize_shift;
+ if (*len > max) {
+ *len = max;
+ gfs2_write_calc_reserv(ip, max, data_blocks, ind_blocks);
+ }
+}
+
+static long gfs2_fallocate(struct file *file, int mode, loff_t offset,
+ loff_t len)
+{
+ struct inode *inode = file->f_path.dentry->d_inode;
+ struct gfs2_sbd *sdp = GFS2_SB(inode);
+ struct gfs2_inode *ip = GFS2_I(inode);
+ unsigned int data_blocks = 0, ind_blocks = 0, rblocks;
+ loff_t bytes, max_bytes;
+ struct gfs2_alloc *al;
+ int error;
+ loff_t next = (offset + len - 1) >> sdp->sd_sb.sb_bsize_shift;
+ next = (next + 1) << sdp->sd_sb.sb_bsize_shift;
+
+ /* We only support the FALLOC_FL_KEEP_SIZE mode */
+ if (mode & ~FALLOC_FL_KEEP_SIZE)
+ return -EOPNOTSUPP;
+
+ offset = (offset >> sdp->sd_sb.sb_bsize_shift) <<
+ sdp->sd_sb.sb_bsize_shift;
+
+ len = next - offset;
+ bytes = sdp->sd_max_rg_data * sdp->sd_sb.sb_bsize / 2;
+ if (!bytes)
+ bytes = UINT_MAX;
+
+ gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &ip->i_gh);
+ error = gfs2_glock_nq(&ip->i_gh);
+ if (unlikely(error))
+ goto out_uninit;
+
+ if (!gfs2_write_alloc_required(ip, offset, len))
+ goto out_unlock;
+
+ while (len > 0) {
+ if (len < bytes)
+ bytes = len;
+ al = gfs2_alloc_get(ip);
+ if (!al) {
+ error = -ENOMEM;
+ goto out_unlock;
+ }
+
+ error = gfs2_quota_lock_check(ip);
+ if (error)
+ goto out_alloc_put;
+
+retry:
+ gfs2_write_calc_reserv(ip, bytes, &data_blocks, &ind_blocks);
+
+ al->al_requested = data_blocks + ind_blocks;
+ error = gfs2_inplace_reserve(ip);
+ if (error) {
+ if (error == -ENOSPC && bytes > sdp->sd_sb.sb_bsize) {
+ bytes >>= 1;
+ goto retry;
+ }
+ goto out_qunlock;
+ }
+ max_bytes = bytes;
+ calc_max_reserv(ip, len, &max_bytes, &data_blocks, &ind_blocks);
+ al->al_requested = data_blocks + ind_blocks;
+
+ rblocks = RES_DINODE + ind_blocks + RES_STATFS + RES_QUOTA +
+ RES_RG_HDR + gfs2_rg_blocks(al);
+ if (gfs2_is_jdata(ip))
+ rblocks += data_blocks ? data_blocks : 1;
+
+ error = gfs2_trans_begin(sdp, rblocks,
+ PAGE_CACHE_SIZE/sdp->sd_sb.sb_bsize);
+ if (error)
+ goto out_trans_fail;
+
+ error = fallocate_chunk(inode, offset, max_bytes, mode);
+ gfs2_trans_end(sdp);
+
+ if (error)
+ goto out_trans_fail;
+
+ len -= max_bytes;
+ offset += max_bytes;
+ gfs2_inplace_release(ip);
+ gfs2_quota_unlock(ip);
+ gfs2_alloc_put(ip);
+ }
+ goto out_unlock;
+
+out_trans_fail:
+ gfs2_inplace_release(ip);
+out_qunlock:
+ gfs2_quota_unlock(ip);
+out_alloc_put:
+ gfs2_alloc_put(ip);
+out_unlock:
+ gfs2_glock_dq(&ip->i_gh);
+out_uninit:
+ gfs2_holder_uninit(&ip->i_gh);
+ return error;
+}
+
#ifdef CONFIG_GFS2_FS_LOCKING_DLM
/**
@@ -765,6 +1021,7 @@ const struct file_operations gfs2_file_fops = {
.splice_read = generic_file_splice_read,
.splice_write = generic_file_splice_write,
.setlease = gfs2_setlease,
+ .fallocate = gfs2_fallocate,
};
const struct file_operations gfs2_dir_fops = {
@@ -794,6 +1051,7 @@ const struct file_operations gfs2_file_fops_nolock = {
.splice_read = generic_file_splice_read,
.splice_write = generic_file_splice_write,
.setlease = generic_setlease,
+ .fallocate = gfs2_fallocate,
};
const struct file_operations gfs2_dir_fops_nolock = {
diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c
index 2232b3c..7aa7d4f 100644
--- a/fs/gfs2/inode.c
+++ b/fs/gfs2/inode.c
@@ -74,16 +74,14 @@ static struct inode *gfs2_iget(struct super_block *sb, u64 no_addr)
}
/**
- * GFS2 lookup code fills in vfs inode contents based on info obtained
- * from directory entry inside gfs2_inode_lookup(). This has caused issues
- * with NFS code path since its get_dentry routine doesn't have the relevant
- * directory entry when gfs2_inode_lookup() is invoked. Part of the code
- * segment inside gfs2_inode_lookup code needs to get moved around.
+ * gfs2_set_iop - Sets inode operations
+ * @inode: The inode with correct i_mode filled in
*
- * Clears I_NEW as well.
- **/
+ * GFS2 lookup code fills in vfs inode contents based on info obtained
+ * from directory entry inside gfs2_inode_lookup().
+ */
-void gfs2_set_iop(struct inode *inode)
+static void gfs2_set_iop(struct inode *inode)
{
struct gfs2_sbd *sdp = GFS2_SB(inode);
umode_t mode = inode->i_mode;
@@ -106,8 +104,6 @@ void gfs2_set_iop(struct inode *inode)
inode->i_op = &gfs2_file_iops;
init_special_inode(inode, inode->i_mode, inode->i_rdev);
}
-
- unlock_new_inode(inode);
}
/**
@@ -119,10 +115,8 @@ void gfs2_set_iop(struct inode *inode)
* Returns: A VFS inode, or an error
*/
-struct inode *gfs2_inode_lookup(struct super_block *sb,
- unsigned int type,
- u64 no_addr,
- u64 no_formal_ino)
+struct inode *gfs2_inode_lookup(struct super_block *sb, unsigned int type,
+ u64 no_addr, u64 no_formal_ino)
{
struct inode *inode;
struct gfs2_inode *ip;
@@ -152,51 +146,37 @@ struct inode *gfs2_inode_lookup(struct super_block *sb,
error = gfs2_glock_nq_init(io_gl, LM_ST_SHARED, GL_EXACT, &ip->i_iopen_gh);
if (unlikely(error))
goto fail_iopen;
- ip->i_iopen_gh.gh_gl->gl_object = ip;
+ ip->i_iopen_gh.gh_gl->gl_object = ip;
gfs2_glock_put(io_gl);
io_gl = NULL;
- if ((type == DT_UNKNOWN) && (no_formal_ino == 0))
- goto gfs2_nfsbypass;
-
- inode->i_mode = DT2IF(type);
-
- /*
- * We must read the inode in order to work out its type in
- * this case. Note that this doesn't happen often as we normally
- * know the type beforehand. This code path only occurs during
- * unlinked inode recovery (where it is safe to do this glock,
- * which is not true in the general case).
- */
if (type == DT_UNKNOWN) {
- struct gfs2_holder gh;
- error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh);
- if (unlikely(error))
- goto fail_glock;
- /* Inode is now uptodate */
- gfs2_glock_dq_uninit(&gh);
+ /* Inode glock must be locked already */
+ error = gfs2_inode_refresh(GFS2_I(inode));
+ if (error)
+ goto fail_refresh;
+ } else {
+ inode->i_mode = DT2IF(type);
}
gfs2_set_iop(inode);
+ unlock_new_inode(inode);
}
-gfs2_nfsbypass:
return inode;
-fail_glock:
- gfs2_glock_dq(&ip->i_iopen_gh);
+
+fail_refresh:
+ ip->i_iopen_gh.gh_gl->gl_object = NULL;
+ gfs2_glock_dq_uninit(&ip->i_iopen_gh);
fail_iopen:
if (io_gl)
gfs2_glock_put(io_gl);
fail_put:
- if (inode->i_state & I_NEW)
- ip->i_gl->gl_object = NULL;
+ ip->i_gl->gl_object = NULL;
gfs2_glock_put(ip->i_gl);
fail:
- if (inode->i_state & I_NEW)
- iget_failed(inode);
- else
- iput(inode);
+ iget_failed(inode);
return ERR_PTR(error);
}
@@ -221,14 +201,6 @@ struct inode *gfs2_lookup_by_inum(struct gfs2_sbd *sdp, u64 no_addr,
if (IS_ERR(inode))
goto fail;
- error = gfs2_inode_refresh(GFS2_I(inode));
- if (error)
- goto fail_iput;
-
- /* Pick up the works we bypass in gfs2_inode_lookup */
- if (inode->i_state & I_NEW)
- gfs2_set_iop(inode);
-
/* Two extra checks for NFS only */
if (no_formal_ino) {
error = -ESTALE;
diff --git a/fs/gfs2/inode.h b/fs/gfs2/inode.h
index 732a183..3e00a66 100644
--- a/fs/gfs2/inode.h
+++ b/fs/gfs2/inode.h
@@ -96,7 +96,6 @@ err:
return -EIO;
}
-extern void gfs2_set_iop(struct inode *inode);
extern struct inode *gfs2_inode_lookup(struct super_block *sb, unsigned type,
u64 no_addr, u64 no_formal_ino);
extern struct inode *gfs2_lookup_by_inum(struct gfs2_sbd *sdp, u64 no_addr,
diff --git a/fs/gfs2/ops_inode.c b/fs/gfs2/ops_inode.c
index 040b5a2..d8b26ac 100644
--- a/fs/gfs2/ops_inode.c
+++ b/fs/gfs2/ops_inode.c
@@ -18,8 +18,6 @@
#include <linux/gfs2_ondisk.h>
#include <linux/crc32.h>
#include <linux/fiemap.h>
-#include <linux/swap.h>
-#include <linux/falloc.h>
#include <asm/uaccess.h>
#include "gfs2.h"
@@ -1257,261 +1255,6 @@ static int gfs2_removexattr(struct dentry *dentry, const char *name)
return ret;
}
-static void empty_write_end(struct page *page, unsigned from,
- unsigned to)
-{
- struct gfs2_inode *ip = GFS2_I(page->mapping->host);
-
- page_zero_new_buffers(page, from, to);
- flush_dcache_page(page);
- mark_page_accessed(page);
-
- if (!gfs2_is_writeback(ip))
- gfs2_page_add_databufs(ip, page, from, to);
-
- block_commit_write(page, from, to);
-}
-
-
-static int write_empty_blocks(struct page *page, unsigned from, unsigned to)
-{
- unsigned start, end, next;
- struct buffer_head *bh, *head;
- int error;
-
- if (!page_has_buffers(page)) {
- error = __block_write_begin(page, from, to - from, gfs2_block_map);
- if (unlikely(error))
- return error;
-
- empty_write_end(page, from, to);
- return 0;
- }
-
- bh = head = page_buffers(page);
- next = end = 0;
- while (next < from) {
- next += bh->b_size;
- bh = bh->b_this_page;
- }
- start = next;
- do {
- next += bh->b_size;
- if (buffer_mapped(bh)) {
- if (end) {
- error = __block_write_begin(page, start, end - start,
- gfs2_block_map);
- if (unlikely(error))
- return error;
- empty_write_end(page, start, end);
- end = 0;
- }
- start = next;
- }
- else
- end = next;
- bh = bh->b_this_page;
- } while (next < to);
-
- if (end) {
- error = __block_write_begin(page, start, end - start, gfs2_block_map);
- if (unlikely(error))
- return error;
- empty_write_end(page, start, end);
- }
-
- return 0;
-}
-
-static int fallocate_chunk(struct inode *inode, loff_t offset, loff_t len,
- int mode)
-{
- struct gfs2_inode *ip = GFS2_I(inode);
- struct buffer_head *dibh;
- int error;
- u64 start = offset >> PAGE_CACHE_SHIFT;
- unsigned int start_offset = offset & ~PAGE_CACHE_MASK;
- u64 end = (offset + len - 1) >> PAGE_CACHE_SHIFT;
- pgoff_t curr;
- struct page *page;
- unsigned int end_offset = (offset + len) & ~PAGE_CACHE_MASK;
- unsigned int from, to;
-
- if (!end_offset)
- end_offset = PAGE_CACHE_SIZE;
-
- error = gfs2_meta_inode_buffer(ip, &dibh);
- if (unlikely(error))
- goto out;
-
- gfs2_trans_add_bh(ip->i_gl, dibh, 1);
-
- if (gfs2_is_stuffed(ip)) {
- error = gfs2_unstuff_dinode(ip, NULL);
- if (unlikely(error))
- goto out;
- }
-
- curr = start;
- offset = start << PAGE_CACHE_SHIFT;
- from = start_offset;
- to = PAGE_CACHE_SIZE;
- while (curr <= end) {
- page = grab_cache_page_write_begin(inode->i_mapping, curr,
- AOP_FLAG_NOFS);
- if (unlikely(!page)) {
- error = -ENOMEM;
- goto out;
- }
-
- if (curr == end)
- to = end_offset;
- error = write_empty_blocks(page, from, to);
- if (!error && offset + to > inode->i_size &&
- !(mode & FALLOC_FL_KEEP_SIZE)) {
- i_size_write(inode, offset + to);
- }
- unlock_page(page);
- page_cache_release(page);
- if (error)
- goto out;
- curr++;
- offset += PAGE_CACHE_SIZE;
- from = 0;
- }
-
- gfs2_dinode_out(ip, dibh->b_data);
- mark_inode_dirty(inode);
-
- brelse(dibh);
-
-out:
- return error;
-}
-
-static void calc_max_reserv(struct gfs2_inode *ip, loff_t max, loff_t *len,
- unsigned int *data_blocks, unsigned int *ind_blocks)
-{
- const struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
- unsigned int max_blocks = ip->i_alloc->al_rgd->rd_free_clone;
- unsigned int tmp, max_data = max_blocks - 3 * (sdp->sd_max_height - 1);
-
- for (tmp = max_data; tmp > sdp->sd_diptrs;) {
- tmp = DIV_ROUND_UP(tmp, sdp->sd_inptrs);
- max_data -= tmp;
- }
- /* This calculation isn't the exact reverse of gfs2_write_calc_reserve,
- so it might end up with fewer data blocks */
- if (max_data <= *data_blocks)
- return;
- *data_blocks = max_data;
- *ind_blocks = max_blocks - max_data;
- *len = ((loff_t)max_data - 3) << sdp->sd_sb.sb_bsize_shift;
- if (*len > max) {
- *len = max;
- gfs2_write_calc_reserv(ip, max, data_blocks, ind_blocks);
- }
-}
-
-static long gfs2_fallocate(struct inode *inode, int mode, loff_t offset,
- loff_t len)
-{
- struct gfs2_sbd *sdp = GFS2_SB(inode);
- struct gfs2_inode *ip = GFS2_I(inode);
- unsigned int data_blocks = 0, ind_blocks = 0, rblocks;
- loff_t bytes, max_bytes;
- struct gfs2_alloc *al;
- int error;
- loff_t next = (offset + len - 1) >> sdp->sd_sb.sb_bsize_shift;
- next = (next + 1) << sdp->sd_sb.sb_bsize_shift;
-
- /* We only support the FALLOC_FL_KEEP_SIZE mode */
- if (mode && (mode != FALLOC_FL_KEEP_SIZE))
- return -EOPNOTSUPP;
-
- offset = (offset >> sdp->sd_sb.sb_bsize_shift) <<
- sdp->sd_sb.sb_bsize_shift;
-
- len = next - offset;
- bytes = sdp->sd_max_rg_data * sdp->sd_sb.sb_bsize / 2;
- if (!bytes)
- bytes = UINT_MAX;
-
- gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &ip->i_gh);
- error = gfs2_glock_nq(&ip->i_gh);
- if (unlikely(error))
- goto out_uninit;
-
- if (!gfs2_write_alloc_required(ip, offset, len))
- goto out_unlock;
-
- while (len > 0) {
- if (len < bytes)
- bytes = len;
- al = gfs2_alloc_get(ip);
- if (!al) {
- error = -ENOMEM;
- goto out_unlock;
- }
-
- error = gfs2_quota_lock_check(ip);
- if (error)
- goto out_alloc_put;
-
-retry:
- gfs2_write_calc_reserv(ip, bytes, &data_blocks, &ind_blocks);
-
- al->al_requested = data_blocks + ind_blocks;
- error = gfs2_inplace_reserve(ip);
- if (error) {
- if (error == -ENOSPC && bytes > sdp->sd_sb.sb_bsize) {
- bytes >>= 1;
- goto retry;
- }
- goto out_qunlock;
- }
- max_bytes = bytes;
- calc_max_reserv(ip, len, &max_bytes, &data_blocks, &ind_blocks);
- al->al_requested = data_blocks + ind_blocks;
-
- rblocks = RES_DINODE + ind_blocks + RES_STATFS + RES_QUOTA +
- RES_RG_HDR + gfs2_rg_blocks(al);
- if (gfs2_is_jdata(ip))
- rblocks += data_blocks ? data_blocks : 1;
-
- error = gfs2_trans_begin(sdp, rblocks,
- PAGE_CACHE_SIZE/sdp->sd_sb.sb_bsize);
- if (error)
- goto out_trans_fail;
-
- error = fallocate_chunk(inode, offset, max_bytes, mode);
- gfs2_trans_end(sdp);
-
- if (error)
- goto out_trans_fail;
-
- len -= max_bytes;
- offset += max_bytes;
- gfs2_inplace_release(ip);
- gfs2_quota_unlock(ip);
- gfs2_alloc_put(ip);
- }
- goto out_unlock;
-
-out_trans_fail:
- gfs2_inplace_release(ip);
-out_qunlock:
- gfs2_quota_unlock(ip);
-out_alloc_put:
- gfs2_alloc_put(ip);
-out_unlock:
- gfs2_glock_dq(&ip->i_gh);
-out_uninit:
- gfs2_holder_uninit(&ip->i_gh);
- return error;
-}
-
-
static int gfs2_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
u64 start, u64 len)
{
@@ -1562,7 +1305,6 @@ const struct inode_operations gfs2_file_iops = {
.getxattr = gfs2_getxattr,
.listxattr = gfs2_listxattr,
.removexattr = gfs2_removexattr,
- .fallocate = gfs2_fallocate,
.fiemap = gfs2_fiemap,
};
diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c
index 16c2eca..ec73ed7 100644
--- a/fs/gfs2/super.c
+++ b/fs/gfs2/super.c
@@ -1336,6 +1336,7 @@ static void gfs2_evict_inode(struct inode *inode)
if (error)
goto out_truncate;
+ ip->i_iopen_gh.gh_flags |= GL_NOCACHE;
gfs2_glock_dq_wait(&ip->i_iopen_gh);
gfs2_holder_reinit(LM_ST_EXCLUSIVE, LM_FLAG_TRY_1CB | GL_NOCACHE, &ip->i_iopen_gh);
error = gfs2_glock_nq(&ip->i_iopen_gh);
diff --git a/fs/hpfs/inode.c b/fs/hpfs/inode.c
index 56f0da1..1ae35ba 100644
--- a/fs/hpfs/inode.c
+++ b/fs/hpfs/inode.c
@@ -281,7 +281,7 @@ int hpfs_setattr(struct dentry *dentry, struct iattr *attr)
attr->ia_size != i_size_read(inode)) {
error = vmtruncate(inode, attr->ia_size);
if (error)
- return error;
+ goto out_unlock;
}
setattr_copy(inode, attr);
diff --git a/fs/internal.h b/fs/internal.h
index 9687c2e..0663568 100644
--- a/fs/internal.h
+++ b/fs/internal.h
@@ -70,6 +70,10 @@ extern void mnt_set_mountpoint(struct vfsmount *, struct dentry *,
extern void release_mounts(struct list_head *);
extern void umount_tree(struct vfsmount *, int, struct list_head *);
extern struct vfsmount *copy_tree(struct vfsmount *, struct dentry *, int);
+extern int finish_automount(struct vfsmount *, struct path *);
+
+extern void mnt_make_longterm(struct vfsmount *);
+extern void mnt_make_shortterm(struct vfsmount *);
extern void __init mnt_init(void);
diff --git a/fs/ioctl.c b/fs/ioctl.c
index d6cc164..a59635e 100644
--- a/fs/ioctl.c
+++ b/fs/ioctl.c
@@ -86,7 +86,7 @@ int fiemap_fill_next_extent(struct fiemap_extent_info *fieinfo, u64 logical,
u64 phys, u64 len, u32 flags)
{
struct fiemap_extent extent;
- struct fiemap_extent *dest = fieinfo->fi_extents_start;
+ struct fiemap_extent __user *dest = fieinfo->fi_extents_start;
/* only count the extents */
if (fieinfo->fi_extents_max == 0) {
@@ -173,6 +173,7 @@ static int fiemap_check_ranges(struct super_block *sb,
static int ioctl_fiemap(struct file *filp, unsigned long arg)
{
struct fiemap fiemap;
+ struct fiemap __user *ufiemap = (struct fiemap __user *) arg;
struct fiemap_extent_info fieinfo = { 0, };
struct inode *inode = filp->f_path.dentry->d_inode;
struct super_block *sb = inode->i_sb;
@@ -182,8 +183,7 @@ static int ioctl_fiemap(struct file *filp, unsigned long arg)
if (!inode->i_op->fiemap)
return -EOPNOTSUPP;
- if (copy_from_user(&fiemap, (struct fiemap __user *)arg,
- sizeof(struct fiemap)))
+ if (copy_from_user(&fiemap, ufiemap, sizeof(fiemap)))
return -EFAULT;
if (fiemap.fm_extent_count > FIEMAP_MAX_EXTENTS)
@@ -196,7 +196,7 @@ static int ioctl_fiemap(struct file *filp, unsigned long arg)
fieinfo.fi_flags = fiemap.fm_flags;
fieinfo.fi_extents_max = fiemap.fm_extent_count;
- fieinfo.fi_extents_start = (struct fiemap_extent *)(arg + sizeof(fiemap));
+ fieinfo.fi_extents_start = ufiemap->fm_extents;
if (fiemap.fm_extent_count != 0 &&
!access_ok(VERIFY_WRITE, fieinfo.fi_extents_start,
@@ -209,7 +209,7 @@ static int ioctl_fiemap(struct file *filp, unsigned long arg)
error = inode->i_op->fiemap(inode, &fieinfo, fiemap.fm_start, len);
fiemap.fm_flags = fieinfo.fi_flags;
fiemap.fm_mapped_extents = fieinfo.fi_extents_mapped;
- if (copy_to_user((char *)arg, &fiemap, sizeof(fiemap)))
+ if (copy_to_user(ufiemap, &fiemap, sizeof(fiemap)))
error = -EFAULT;
return error;
diff --git a/fs/jffs2/build.c b/fs/jffs2/build.c
index 85c6be2..3005ec4 100644
--- a/fs/jffs2/build.c
+++ b/fs/jffs2/build.c
@@ -336,14 +336,13 @@ int jffs2_do_mount_fs(struct jffs2_sb_info *c)
size = sizeof(struct jffs2_eraseblock) * c->nr_blocks;
#ifndef __ECOS
if (jffs2_blocks_use_vmalloc(c))
- c->blocks = vmalloc(size);
+ c->blocks = vzalloc(size);
else
#endif
- c->blocks = kmalloc(size, GFP_KERNEL);
+ c->blocks = kzalloc(size, GFP_KERNEL);
if (!c->blocks)
return -ENOMEM;
- memset(c->blocks, 0, size);
for (i=0; i<c->nr_blocks; i++) {
INIT_LIST_HEAD(&c->blocks[i].list);
c->blocks[i].offset = i * c->sector_size;
diff --git a/fs/jffs2/jffs2_fs_sb.h b/fs/jffs2/jffs2_fs_sb.h
index f864005..0bc6a6c 100644
--- a/fs/jffs2/jffs2_fs_sb.h
+++ b/fs/jffs2/jffs2_fs_sb.h
@@ -144,4 +144,4 @@ struct jffs2_sb_info {
void *os_priv;
};
-#endif /* _JFFS2_FB_SB */
+#endif /* _JFFS2_FS_SB */
diff --git a/fs/jffs2/xattr.c b/fs/jffs2/xattr.c
index 9b572ca..4f9cc04 100644
--- a/fs/jffs2/xattr.c
+++ b/fs/jffs2/xattr.c
@@ -151,7 +151,7 @@ static int do_verify_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_dat
JFFS2_ERROR("node CRC failed at %#08x, read=%#08x, calc=%#08x\n",
offset, je32_to_cpu(rx.hdr_crc), crc);
xd->flags |= JFFS2_XFLAGS_INVALID;
- return EIO;
+ return -EIO;
}
totlen = PAD(sizeof(rx) + rx.name_len + 1 + je16_to_cpu(rx.value_len));
if (je16_to_cpu(rx.magic) != JFFS2_MAGIC_BITMASK
@@ -167,7 +167,7 @@ static int do_verify_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_dat
je32_to_cpu(rx.xid), xd->xid,
je32_to_cpu(rx.version), xd->version);
xd->flags |= JFFS2_XFLAGS_INVALID;
- return EIO;
+ return -EIO;
}
xd->xprefix = rx.xprefix;
xd->name_len = rx.name_len;
@@ -230,7 +230,7 @@ static int do_load_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum
ref_offset(xd->node), xd->data_crc, crc);
kfree(data);
xd->flags |= JFFS2_XFLAGS_INVALID;
- return EIO;
+ return -EIO;
}
xd->flags |= JFFS2_XFLAGS_HOT;
@@ -268,7 +268,7 @@ static int load_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *x
if (xd->xname)
return 0;
if (xd->flags & JFFS2_XFLAGS_INVALID)
- return EIO;
+ return -EIO;
if (unlikely(is_xattr_datum_unchecked(c, xd)))
rc = do_verify_xattr_datum(c, xd);
if (!rc)
@@ -460,7 +460,7 @@ static int verify_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref
if (crc != je32_to_cpu(rr.node_crc)) {
JFFS2_ERROR("node CRC failed at %#08x, read=%#08x, calc=%#08x\n",
offset, je32_to_cpu(rr.node_crc), crc);
- return EIO;
+ return -EIO;
}
if (je16_to_cpu(rr.magic) != JFFS2_MAGIC_BITMASK
|| je16_to_cpu(rr.nodetype) != JFFS2_NODETYPE_XREF
@@ -470,7 +470,7 @@ static int verify_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref
offset, je16_to_cpu(rr.magic), JFFS2_MAGIC_BITMASK,
je16_to_cpu(rr.nodetype), JFFS2_NODETYPE_XREF,
je32_to_cpu(rr.totlen), PAD(sizeof(rr)));
- return EIO;
+ return -EIO;
}
ref->ino = je32_to_cpu(rr.ino);
ref->xid = je32_to_cpu(rr.xid);
diff --git a/fs/locks.c b/fs/locks.c
index 08415b2..0f39982 100644
--- a/fs/locks.c
+++ b/fs/locks.c
@@ -444,15 +444,9 @@ static void lease_release_private_callback(struct file_lock *fl)
fl->fl_file->f_owner.signum = 0;
}
-static int lease_mylease_callback(struct file_lock *fl, struct file_lock *try)
-{
- return fl->fl_file == try->fl_file;
-}
-
static const struct lock_manager_operations lease_manager_ops = {
.fl_break = lease_break_callback,
.fl_release_private = lease_release_private_callback,
- .fl_mylease = lease_mylease_callback,
.fl_change = lease_modify,
};
@@ -1405,7 +1399,7 @@ int generic_setlease(struct file *filp, long arg, struct file_lock **flp)
for (before = &inode->i_flock;
((fl = *before) != NULL) && IS_LEASE(fl);
before = &fl->fl_next) {
- if (lease->fl_lmops->fl_mylease(fl, lease))
+ if (fl->fl_file == filp)
my_before = before;
else if (fl->fl_type == (F_INPROGRESS | F_UNLCK))
/*
diff --git a/fs/namei.c b/fs/namei.c
index 0b14f69..7d77f24 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -368,18 +368,6 @@ void path_get(struct path *path)
EXPORT_SYMBOL(path_get);
/**
- * path_get_long - get a long reference to a path
- * @path: path to get the reference to
- *
- * Given a path increment the reference count to the dentry and the vfsmount.
- */
-void path_get_long(struct path *path)
-{
- mntget_long(path->mnt);
- dget(path->dentry);
-}
-
-/**
* path_put - put a reference to a path
* @path: path to put the reference to
*
@@ -393,18 +381,6 @@ void path_put(struct path *path)
EXPORT_SYMBOL(path_put);
/**
- * path_put_long - put a long reference to a path
- * @path: path to put the reference to
- *
- * Given a path decrement the reference count to the dentry and the vfsmount.
- */
-void path_put_long(struct path *path)
-{
- dput(path->dentry);
- mntput_long(path->mnt);
-}
-
-/**
* nameidata_drop_rcu - drop this nameidata out of rcu-walk
* @nd: nameidata pathwalk data to drop
* Returns: 0 on success, -ECHILD on failure
@@ -479,6 +455,14 @@ static int nameidata_dentry_drop_rcu(struct nameidata *nd, struct dentry *dentry
struct fs_struct *fs = current->fs;
struct dentry *parent = nd->path.dentry;
+ /*
+ * It can be possible to revalidate the dentry that we started
+ * the path walk with. force_reval_path may also revalidate the
+ * dentry already committed to the nameidata.
+ */
+ if (unlikely(parent == dentry))
+ return nameidata_drop_rcu(nd);
+
BUG_ON(!(nd->flags & LOOKUP_RCU));
if (nd->root.mnt) {
spin_lock(&fs->lock);
@@ -583,6 +567,13 @@ void release_open_intent(struct nameidata *nd)
fput(nd->intent.open.file);
}
+/*
+ * Call d_revalidate and handle filesystems that request rcu-walk
+ * to be dropped. This may be called and return in rcu-walk mode,
+ * regardless of success or error. If -ECHILD is returned, the caller
+ * must return -ECHILD back up the path walk stack so path walk may
+ * be restarted in ref-walk mode.
+ */
static int d_revalidate(struct dentry *dentry, struct nameidata *nd)
{
int status;
@@ -673,6 +664,9 @@ force_reval_path(struct path *path, struct nameidata *nd)
return 0;
if (!status) {
+ /* Don't d_invalidate in rcu-walk mode */
+ if (nameidata_drop_rcu(nd))
+ return -ECHILD;
d_invalidate(dentry);
status = -ESTALE;
}
@@ -761,7 +755,8 @@ static void path_put_conditional(struct path *path, struct nameidata *nd)
mntput(path->mnt);
}
-static inline void path_to_nameidata(struct path *path, struct nameidata *nd)
+static inline void path_to_nameidata(const struct path *path,
+ struct nameidata *nd)
{
if (!(nd->flags & LOOKUP_RCU)) {
dput(nd->path.dentry);
@@ -773,20 +768,16 @@ static inline void path_to_nameidata(struct path *path, struct nameidata *nd)
}
static __always_inline int
-__do_follow_link(struct path *path, struct nameidata *nd, void **p)
+__do_follow_link(const struct path *link, struct nameidata *nd, void **p)
{
int error;
- struct dentry *dentry = path->dentry;
+ struct dentry *dentry = link->dentry;
- touch_atime(path->mnt, dentry);
+ touch_atime(link->mnt, dentry);
nd_set_link(nd, NULL);
- if (path->mnt != nd->path.mnt) {
- path_to_nameidata(path, nd);
- nd->inode = nd->path.dentry->d_inode;
- dget(dentry);
- }
- mntget(path->mnt);
+ if (link->mnt == nd->path.mnt)
+ mntget(link->mnt);
nd->last_type = LAST_BIND;
*p = dentry->d_inode->i_op->follow_link(dentry, nd);
@@ -877,54 +868,148 @@ int follow_up(struct path *path)
}
/*
- * serialization is taken care of in namespace.c
+ * Perform an automount
+ * - return -EISDIR to tell follow_managed() to stop and return the path we
+ * were called with.
*/
-static void __follow_mount_rcu(struct nameidata *nd, struct path *path,
- struct inode **inode)
+static int follow_automount(struct path *path, unsigned flags,
+ bool *need_mntput)
{
- while (d_mountpoint(path->dentry)) {
- struct vfsmount *mounted;
- mounted = __lookup_mnt(path->mnt, path->dentry, 1);
- if (!mounted)
- return;
- path->mnt = mounted;
- path->dentry = mounted->mnt_root;
- nd->seq = read_seqcount_begin(&path->dentry->d_seq);
- *inode = path->dentry->d_inode;
+ struct vfsmount *mnt;
+ int err;
+
+ if (!path->dentry->d_op || !path->dentry->d_op->d_automount)
+ return -EREMOTE;
+
+ /* We don't want to mount if someone supplied AT_NO_AUTOMOUNT
+ * and this is the terminal part of the path.
+ */
+ if ((flags & LOOKUP_NO_AUTOMOUNT) && !(flags & LOOKUP_CONTINUE))
+ return -EISDIR; /* we actually want to stop here */
+
+ /* We want to mount if someone is trying to open/create a file of any
+ * type under the mountpoint, wants to traverse through the mountpoint
+ * or wants to open the mounted directory.
+ *
+ * We don't want to mount if someone's just doing a stat and they've
+ * set AT_SYMLINK_NOFOLLOW - unless they're stat'ing a directory and
+ * appended a '/' to the name.
+ */
+ if (!(flags & LOOKUP_FOLLOW) &&
+ !(flags & (LOOKUP_CONTINUE | LOOKUP_DIRECTORY |
+ LOOKUP_OPEN | LOOKUP_CREATE)))
+ return -EISDIR;
+
+ current->total_link_count++;
+ if (current->total_link_count >= 40)
+ return -ELOOP;
+
+ mnt = path->dentry->d_op->d_automount(path);
+ if (IS_ERR(mnt)) {
+ /*
+ * The filesystem is allowed to return -EISDIR here to indicate
+ * it doesn't want to automount. For instance, autofs would do
+ * this so that its userspace daemon can mount on this dentry.
+ *
+ * However, we can only permit this if it's a terminal point in
+ * the path being looked up; if it wasn't then the remainder of
+ * the path is inaccessible and we should say so.
+ */
+ if (PTR_ERR(mnt) == -EISDIR && (flags & LOOKUP_CONTINUE))
+ return -EREMOTE;
+ return PTR_ERR(mnt);
}
-}
-static int __follow_mount(struct path *path)
-{
- int res = 0;
- while (d_mountpoint(path->dentry)) {
- struct vfsmount *mounted = lookup_mnt(path);
- if (!mounted)
- break;
+ if (!mnt) /* mount collision */
+ return 0;
+
+ err = finish_automount(mnt, path);
+
+ switch (err) {
+ case -EBUSY:
+ /* Someone else made a mount here whilst we were busy */
+ return 0;
+ case 0:
dput(path->dentry);
- if (res)
+ if (*need_mntput)
mntput(path->mnt);
- path->mnt = mounted;
- path->dentry = dget(mounted->mnt_root);
- res = 1;
+ path->mnt = mnt;
+ path->dentry = dget(mnt->mnt_root);
+ *need_mntput = true;
+ return 0;
+ default:
+ return err;
}
- return res;
+
}
-static void follow_mount(struct path *path)
+/*
+ * Handle a dentry that is managed in some way.
+ * - Flagged for transit management (autofs)
+ * - Flagged as mountpoint
+ * - Flagged as automount point
+ *
+ * This may only be called in refwalk mode.
+ *
+ * Serialization is taken care of in namespace.c
+ */
+static int follow_managed(struct path *path, unsigned flags)
{
- while (d_mountpoint(path->dentry)) {
- struct vfsmount *mounted = lookup_mnt(path);
- if (!mounted)
- break;
- dput(path->dentry);
- mntput(path->mnt);
- path->mnt = mounted;
- path->dentry = dget(mounted->mnt_root);
+ unsigned managed;
+ bool need_mntput = false;
+ int ret;
+
+ /* Given that we're not holding a lock here, we retain the value in a
+ * local variable for each dentry as we look at it so that we don't see
+ * the components of that value change under us */
+ while (managed = ACCESS_ONCE(path->dentry->d_flags),
+ managed &= DCACHE_MANAGED_DENTRY,
+ unlikely(managed != 0)) {
+ /* Allow the filesystem to manage the transit without i_mutex
+ * being held. */
+ if (managed & DCACHE_MANAGE_TRANSIT) {
+ BUG_ON(!path->dentry->d_op);
+ BUG_ON(!path->dentry->d_op->d_manage);
+ ret = path->dentry->d_op->d_manage(path->dentry,
+ false, false);
+ if (ret < 0)
+ return ret == -EISDIR ? 0 : ret;
+ }
+
+ /* Transit to a mounted filesystem. */
+ if (managed & DCACHE_MOUNTED) {
+ struct vfsmount *mounted = lookup_mnt(path);
+ if (mounted) {
+ dput(path->dentry);
+ if (need_mntput)
+ mntput(path->mnt);
+ path->mnt = mounted;
+ path->dentry = dget(mounted->mnt_root);
+ need_mntput = true;
+ continue;
+ }
+
+ /* Something is mounted on this dentry in another
+ * namespace and/or whatever was mounted there in this
+ * namespace got unmounted before we managed to get the
+ * vfsmount_lock */
+ }
+
+ /* Handle an automount point */
+ if (managed & DCACHE_NEED_AUTOMOUNT) {
+ ret = follow_automount(path, flags, &need_mntput);
+ if (ret < 0)
+ return ret == -EISDIR ? 0 : ret;
+ continue;
+ }
+
+ /* We didn't change the current path point */
+ break;
}
+ return 0;
}
-int follow_down(struct path *path)
+int follow_down_one(struct path *path)
{
struct vfsmount *mounted;
@@ -939,13 +1024,41 @@ int follow_down(struct path *path)
return 0;
}
+/*
+ * Skip to top of mountpoint pile in rcuwalk mode. We abort the rcu-walk if we
+ * meet a managed dentry and we're not walking to "..". True is returned to
+ * continue, false to abort.
+ */
+static bool __follow_mount_rcu(struct nameidata *nd, struct path *path,
+ struct inode **inode, bool reverse_transit)
+{
+ while (d_mountpoint(path->dentry)) {
+ struct vfsmount *mounted;
+ if (unlikely(path->dentry->d_flags & DCACHE_MANAGE_TRANSIT) &&
+ !reverse_transit &&
+ path->dentry->d_op->d_manage(path->dentry, false, true) < 0)
+ return false;
+ mounted = __lookup_mnt(path->mnt, path->dentry, 1);
+ if (!mounted)
+ break;
+ path->mnt = mounted;
+ path->dentry = mounted->mnt_root;
+ nd->seq = read_seqcount_begin(&path->dentry->d_seq);
+ *inode = path->dentry->d_inode;
+ }
+
+ if (unlikely(path->dentry->d_flags & DCACHE_NEED_AUTOMOUNT))
+ return reverse_transit;
+ return true;
+}
+
static int follow_dotdot_rcu(struct nameidata *nd)
{
struct inode *inode = nd->inode;
set_root_rcu(nd);
- while(1) {
+ while (1) {
if (nd->path.dentry == nd->root.dentry &&
nd->path.mnt == nd->root.mnt) {
break;
@@ -968,12 +1081,80 @@ static int follow_dotdot_rcu(struct nameidata *nd)
nd->seq = read_seqcount_begin(&nd->path.dentry->d_seq);
inode = nd->path.dentry->d_inode;
}
- __follow_mount_rcu(nd, &nd->path, &inode);
+ __follow_mount_rcu(nd, &nd->path, &inode, true);
nd->inode = inode;
return 0;
}
+/*
+ * Follow down to the covering mount currently visible to userspace. At each
+ * point, the filesystem owning that dentry may be queried as to whether the
+ * caller is permitted to proceed or not.
+ *
+ * Care must be taken as namespace_sem may be held (indicated by mounting_here
+ * being true).
+ */
+int follow_down(struct path *path, bool mounting_here)
+{
+ unsigned managed;
+ int ret;
+
+ while (managed = ACCESS_ONCE(path->dentry->d_flags),
+ unlikely(managed & DCACHE_MANAGED_DENTRY)) {
+ /* Allow the filesystem to manage the transit without i_mutex
+ * being held.
+ *
+ * We indicate to the filesystem if someone is trying to mount
+ * something here. This gives autofs the chance to deny anyone
+ * other than its daemon the right to mount on its
+ * superstructure.
+ *
+ * The filesystem may sleep at this point.
+ */
+ if (managed & DCACHE_MANAGE_TRANSIT) {
+ BUG_ON(!path->dentry->d_op);
+ BUG_ON(!path->dentry->d_op->d_manage);
+ ret = path->dentry->d_op->d_manage(
+ path->dentry, mounting_here, false);
+ if (ret < 0)
+ return ret == -EISDIR ? 0 : ret;
+ }
+
+ /* Transit to a mounted filesystem. */
+ if (managed & DCACHE_MOUNTED) {
+ struct vfsmount *mounted = lookup_mnt(path);
+ if (!mounted)
+ break;
+ dput(path->dentry);
+ mntput(path->mnt);
+ path->mnt = mounted;
+ path->dentry = dget(mounted->mnt_root);
+ continue;
+ }
+
+ /* Don't handle automount points here */
+ break;
+ }
+ return 0;
+}
+
+/*
+ * Skip to top of mountpoint pile in refwalk mode for follow_dotdot()
+ */
+static void follow_mount(struct path *path)
+{
+ while (d_mountpoint(path->dentry)) {
+ struct vfsmount *mounted = lookup_mnt(path);
+ if (!mounted)
+ break;
+ dput(path->dentry);
+ mntput(path->mnt);
+ path->mnt = mounted;
+ path->dentry = dget(mounted->mnt_root);
+ }
+}
+
static void follow_dotdot(struct nameidata *nd)
{
set_root(nd);
@@ -1038,12 +1219,14 @@ static int do_lookup(struct nameidata *nd, struct qstr *name,
struct vfsmount *mnt = nd->path.mnt;
struct dentry *dentry, *parent = nd->path.dentry;
struct inode *dir;
+ int err;
+
/*
* See if the low-level filesystem might want
* to use its own hash..
*/
if (unlikely(parent->d_flags & DCACHE_OP_HASH)) {
- int err = parent->d_op->d_hash(parent, nd->inode, name);
+ err = parent->d_op->d_hash(parent, nd->inode, name);
if (err < 0)
return err;
}
@@ -1070,22 +1253,30 @@ static int do_lookup(struct nameidata *nd, struct qstr *name,
nd->seq = seq;
if (dentry->d_flags & DCACHE_OP_REVALIDATE)
goto need_revalidate;
+done2:
path->mnt = mnt;
path->dentry = dentry;
- __follow_mount_rcu(nd, path, inode);
- } else {
- dentry = __d_lookup(parent, name);
- if (!dentry)
- goto need_lookup;
+ if (likely(__follow_mount_rcu(nd, path, inode, false)))
+ return 0;
+ if (nameidata_drop_rcu(nd))
+ return -ECHILD;
+ /* fallthru */
+ }
+ dentry = __d_lookup(parent, name);
+ if (!dentry)
+ goto need_lookup;
found:
- if (dentry->d_flags & DCACHE_OP_REVALIDATE)
- goto need_revalidate;
+ if (dentry->d_flags & DCACHE_OP_REVALIDATE)
+ goto need_revalidate;
done:
- path->mnt = mnt;
- path->dentry = dentry;
- __follow_mount(path);
- *inode = path->dentry->d_inode;
- }
+ path->mnt = mnt;
+ path->dentry = dentry;
+ err = follow_managed(path, nd->flags);
+ if (unlikely(err < 0)) {
+ path_put_conditional(path, nd);
+ return err;
+ }
+ *inode = path->dentry->d_inode;
return 0;
need_lookup:
@@ -1124,6 +1315,8 @@ need_revalidate:
goto need_lookup;
if (IS_ERR(dentry))
goto fail;
+ if (nd->flags & LOOKUP_RCU)
+ goto done2;
goto done;
fail:
@@ -1131,17 +1324,6 @@ fail:
}
/*
- * This is a temporary kludge to deal with "automount" symlinks; proper
- * solution is to trigger them on follow_mount(), so that do_lookup()
- * would DTRT. To be killed before 2.6.34-final.
- */
-static inline int follow_on_final(struct inode *inode, unsigned lookup_flags)
-{
- return inode && unlikely(inode->i_op->follow_link) &&
- ((lookup_flags & LOOKUP_FOLLOW) || S_ISDIR(inode->i_mode));
-}
-
-/*
* Name resolution.
* This is the basic name resolution function, turning a pathname into
* the final dentry. We expect 'base' to be positive and a directory.
@@ -1279,7 +1461,8 @@ last_component:
err = do_lookup(nd, &this, &next, &inode);
if (err)
break;
- if (follow_on_final(inode, lookup_flags)) {
+ if (inode && unlikely(inode->i_op->follow_link) &&
+ (lookup_flags & LOOKUP_FOLLOW)) {
if (nameidata_dentry_drop_rcu_maybe(nd, next.dentry))
return -ECHILD;
BUG_ON(inode != next.dentry->d_inode);
@@ -2105,11 +2288,13 @@ static struct file *do_last(struct nameidata *nd, struct path *path,
dir = nd->path.dentry;
case LAST_DOT:
if (need_reval_dot(dir)) {
- error = d_revalidate(nd->path.dentry, nd);
- if (!error)
- error = -ESTALE;
- if (error < 0)
+ int status = d_revalidate(nd->path.dentry, nd);
+ if (!status)
+ status = -ESTALE;
+ if (status < 0) {
+ error = status;
goto exit;
+ }
}
/* fallthrough */
case LAST_ROOT:
@@ -2179,11 +2364,9 @@ static struct file *do_last(struct nameidata *nd, struct path *path,
if (open_flag & O_EXCL)
goto exit_dput;
- if (__follow_mount(path)) {
- error = -ELOOP;
- if (open_flag & O_NOFOLLOW)
- goto exit_dput;
- }
+ error = follow_managed(path, nd->flags);
+ if (error < 0)
+ goto exit_dput;
error = -ENOENT;
if (!path->dentry->d_inode)
@@ -2328,11 +2511,11 @@ reval:
nd.flags = flags;
filp = do_last(&nd, &path, open_flag, acc_mode, mode, pathname);
while (unlikely(!filp)) { /* trailing symlink */
- struct path holder;
+ struct path link = path;
+ struct inode *linki = link.dentry->d_inode;
void *cookie;
error = -ELOOP;
- /* S_ISDIR part is a temporary automount kludge */
- if (!(nd.flags & LOOKUP_FOLLOW) && !S_ISDIR(nd.inode->i_mode))
+ if (!(nd.flags & LOOKUP_FOLLOW))
goto exit_dput;
if (count++ == 32)
goto exit_dput;
@@ -2348,23 +2531,22 @@ reval:
* just set LAST_BIND.
*/
nd.flags |= LOOKUP_PARENT;
- error = security_inode_follow_link(path.dentry, &nd);
+ error = security_inode_follow_link(link.dentry, &nd);
if (error)
goto exit_dput;
- error = __do_follow_link(&path, &nd, &cookie);
+ error = __do_follow_link(&link, &nd, &cookie);
if (unlikely(error)) {
- if (!IS_ERR(cookie) && nd.inode->i_op->put_link)
- nd.inode->i_op->put_link(path.dentry, &nd, cookie);
+ if (!IS_ERR(cookie) && linki->i_op->put_link)
+ linki->i_op->put_link(link.dentry, &nd, cookie);
/* nd.path had been dropped */
- nd.path = path;
+ nd.path = link;
goto out_path;
}
- holder = path;
nd.flags &= ~LOOKUP_PARENT;
filp = do_last(&nd, &path, open_flag, acc_mode, mode, pathname);
- if (nd.inode->i_op->put_link)
- nd.inode->i_op->put_link(holder.dentry, &nd, cookie);
- path_put(&holder);
+ if (linki->i_op->put_link)
+ linki->i_op->put_link(link.dentry, &nd, cookie);
+ path_put(&link);
}
out:
if (nd.root.mnt)
@@ -3392,6 +3574,7 @@ const struct inode_operations page_symlink_inode_operations = {
};
EXPORT_SYMBOL(user_path_at);
+EXPORT_SYMBOL(follow_down_one);
EXPORT_SYMBOL(follow_down);
EXPORT_SYMBOL(follow_up);
EXPORT_SYMBOL(get_write_access); /* binfmt_aout */
diff --git a/fs/namespace.c b/fs/namespace.c
index 3ddfd90..7b0b953 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -183,7 +183,7 @@ static inline void mnt_dec_count(struct vfsmount *mnt)
unsigned int mnt_get_count(struct vfsmount *mnt)
{
#ifdef CONFIG_SMP
- unsigned int count = atomic_read(&mnt->mnt_longrefs);
+ unsigned int count = 0;
int cpu;
for_each_possible_cpu(cpu) {
@@ -217,7 +217,7 @@ struct vfsmount *alloc_vfsmnt(const char *name)
if (!mnt->mnt_pcp)
goto out_free_devname;
- atomic_set(&mnt->mnt_longrefs, 1);
+ this_cpu_add(mnt->mnt_pcp->mnt_count, 1);
#else
mnt->mnt_count = 1;
mnt->mnt_writers = 0;
@@ -611,6 +611,21 @@ static void attach_mnt(struct vfsmount *mnt, struct path *path)
list_add_tail(&mnt->mnt_child, &path->mnt->mnt_mounts);
}
+static inline void __mnt_make_longterm(struct vfsmount *mnt)
+{
+#ifdef CONFIG_SMP
+ atomic_inc(&mnt->mnt_longterm);
+#endif
+}
+
+/* needs vfsmount lock for write */
+static inline void __mnt_make_shortterm(struct vfsmount *mnt)
+{
+#ifdef CONFIG_SMP
+ atomic_dec(&mnt->mnt_longterm);
+#endif
+}
+
/*
* vfsmount lock must be held for write
*/
@@ -624,8 +639,11 @@ static void commit_tree(struct vfsmount *mnt)
BUG_ON(parent == mnt);
list_add_tail(&head, &mnt->mnt_list);
- list_for_each_entry(m, &head, mnt_list)
+ list_for_each_entry(m, &head, mnt_list) {
m->mnt_ns = n;
+ __mnt_make_longterm(m);
+ }
+
list_splice(&head, n->list.prev);
list_add_tail(&mnt->mnt_hash, mount_hashtable +
@@ -734,51 +752,30 @@ static inline void mntfree(struct vfsmount *mnt)
deactivate_super(sb);
}
-#ifdef CONFIG_SMP
-static inline void __mntput(struct vfsmount *mnt, int longrefs)
+static void mntput_no_expire(struct vfsmount *mnt)
{
- if (!longrefs) {
put_again:
- br_read_lock(vfsmount_lock);
- if (likely(atomic_read(&mnt->mnt_longrefs))) {
- mnt_dec_count(mnt);
- br_read_unlock(vfsmount_lock);
- return;
- }
+#ifdef CONFIG_SMP
+ br_read_lock(vfsmount_lock);
+ if (likely(atomic_read(&mnt->mnt_longterm))) {
+ mnt_dec_count(mnt);
br_read_unlock(vfsmount_lock);
- } else {
- BUG_ON(!atomic_read(&mnt->mnt_longrefs));
- if (atomic_add_unless(&mnt->mnt_longrefs, -1, 1))
- return;
+ return;
}
+ br_read_unlock(vfsmount_lock);
br_write_lock(vfsmount_lock);
- if (!longrefs)
- mnt_dec_count(mnt);
- else
- atomic_dec(&mnt->mnt_longrefs);
+ mnt_dec_count(mnt);
if (mnt_get_count(mnt)) {
br_write_unlock(vfsmount_lock);
return;
}
- if (unlikely(mnt->mnt_pinned)) {
- mnt_add_count(mnt, mnt->mnt_pinned + 1);
- mnt->mnt_pinned = 0;
- br_write_unlock(vfsmount_lock);
- acct_auto_close_mnt(mnt);
- goto put_again;
- }
- br_write_unlock(vfsmount_lock);
- mntfree(mnt);
-}
#else
-static inline void __mntput(struct vfsmount *mnt, int longrefs)
-{
-put_again:
mnt_dec_count(mnt);
if (likely(mnt_get_count(mnt)))
return;
br_write_lock(vfsmount_lock);
+#endif
if (unlikely(mnt->mnt_pinned)) {
mnt_add_count(mnt, mnt->mnt_pinned + 1);
mnt->mnt_pinned = 0;
@@ -789,12 +786,6 @@ put_again:
br_write_unlock(vfsmount_lock);
mntfree(mnt);
}
-#endif
-
-static void mntput_no_expire(struct vfsmount *mnt)
-{
- __mntput(mnt, 0);
-}
void mntput(struct vfsmount *mnt)
{
@@ -802,7 +793,7 @@ void mntput(struct vfsmount *mnt)
/* avoid cacheline pingpong, hope gcc doesn't get "smart" */
if (unlikely(mnt->mnt_expiry_mark))
mnt->mnt_expiry_mark = 0;
- __mntput(mnt, 0);
+ mntput_no_expire(mnt);
}
}
EXPORT_SYMBOL(mntput);
@@ -815,33 +806,6 @@ struct vfsmount *mntget(struct vfsmount *mnt)
}
EXPORT_SYMBOL(mntget);
-void mntput_long(struct vfsmount *mnt)
-{
-#ifdef CONFIG_SMP
- if (mnt) {
- /* avoid cacheline pingpong, hope gcc doesn't get "smart" */
- if (unlikely(mnt->mnt_expiry_mark))
- mnt->mnt_expiry_mark = 0;
- __mntput(mnt, 1);
- }
-#else
- mntput(mnt);
-#endif
-}
-EXPORT_SYMBOL(mntput_long);
-
-struct vfsmount *mntget_long(struct vfsmount *mnt)
-{
-#ifdef CONFIG_SMP
- if (mnt)
- atomic_inc(&mnt->mnt_longrefs);
- return mnt;
-#else
- return mntget(mnt);
-#endif
-}
-EXPORT_SYMBOL(mntget_long);
-
void mnt_pin(struct vfsmount *mnt)
{
br_write_lock(vfsmount_lock);
@@ -1216,7 +1180,7 @@ void release_mounts(struct list_head *head)
dput(dentry);
mntput(m);
}
- mntput_long(mnt);
+ mntput(mnt);
}
}
@@ -1226,19 +1190,21 @@ void release_mounts(struct list_head *head)
*/
void umount_tree(struct vfsmount *mnt, int propagate, struct list_head *kill)
{
+ LIST_HEAD(tmp_list);
struct vfsmount *p;
for (p = mnt; p; p = next_mnt(p, mnt))
- list_move(&p->mnt_hash, kill);
+ list_move(&p->mnt_hash, &tmp_list);
if (propagate)
- propagate_umount(kill);
+ propagate_umount(&tmp_list);
- list_for_each_entry(p, kill, mnt_hash) {
+ list_for_each_entry(p, &tmp_list, mnt_hash) {
list_del_init(&p->mnt_expire);
list_del_init(&p->mnt_list);
__touch_mnt_namespace(p->mnt_ns);
p->mnt_ns = NULL;
+ __mnt_make_shortterm(p);
list_del_init(&p->mnt_child);
if (p->mnt_parent != p) {
p->mnt_parent->mnt_ghosts++;
@@ -1246,6 +1212,7 @@ void umount_tree(struct vfsmount *mnt, int propagate, struct list_head *kill)
}
change_mnt_propagation(p, MS_PRIVATE);
}
+ list_splice(&tmp_list, kill);
}
static void shrink_submounts(struct vfsmount *mnt, struct list_head *umounts);
@@ -1844,9 +1811,10 @@ static int do_move_mount(struct path *path, char *old_name)
return err;
down_write(&namespace_sem);
- while (d_mountpoint(path->dentry) &&
- follow_down(path))
- ;
+ err = follow_down(path, true);
+ if (err < 0)
+ goto out;
+
err = -EINVAL;
if (!check_mnt(path->mnt) || !check_mnt(old_path.mnt))
goto out;
@@ -1904,6 +1872,8 @@ out:
return err;
}
+static int do_add_mount(struct vfsmount *, struct path *, int);
+
/*
* create a new mount for userspace and request it to be added into the
* namespace's tree
@@ -1912,6 +1882,7 @@ static int do_new_mount(struct path *path, char *type, int flags,
int mnt_flags, char *name, void *data)
{
struct vfsmount *mnt;
+ int err;
if (!type)
return -EINVAL;
@@ -1924,15 +1895,47 @@ static int do_new_mount(struct path *path, char *type, int flags,
if (IS_ERR(mnt))
return PTR_ERR(mnt);
- return do_add_mount(mnt, path, mnt_flags, NULL);
+ err = do_add_mount(mnt, path, mnt_flags);
+ if (err)
+ mntput(mnt);
+ return err;
+}
+
+int finish_automount(struct vfsmount *m, struct path *path)
+{
+ int err;
+ /* The new mount record should have at least 2 refs to prevent it being
+ * expired before we get a chance to add it
+ */
+ BUG_ON(mnt_get_count(m) < 2);
+
+ if (m->mnt_sb == path->mnt->mnt_sb &&
+ m->mnt_root == path->dentry) {
+ err = -ELOOP;
+ goto fail;
+ }
+
+ err = do_add_mount(m, path, path->mnt->mnt_flags | MNT_SHRINKABLE);
+ if (!err)
+ return 0;
+fail:
+ /* remove m from any expiration list it may be on */
+ if (!list_empty(&m->mnt_expire)) {
+ down_write(&namespace_sem);
+ br_write_lock(vfsmount_lock);
+ list_del_init(&m->mnt_expire);
+ br_write_unlock(vfsmount_lock);
+ up_write(&namespace_sem);
+ }
+ mntput(m);
+ mntput(m);
+ return err;
}
/*
* add a mount into a namespace's mount tree
- * - provide the option of adding the new mount to an expiration list
*/
-int do_add_mount(struct vfsmount *newmnt, struct path *path,
- int mnt_flags, struct list_head *fslist)
+static int do_add_mount(struct vfsmount *newmnt, struct path *path, int mnt_flags)
{
int err;
@@ -1940,9 +1943,10 @@ int do_add_mount(struct vfsmount *newmnt, struct path *path,
down_write(&namespace_sem);
/* Something was mounted here while we slept */
- while (d_mountpoint(path->dentry) &&
- follow_down(path))
- ;
+ err = follow_down(path, true);
+ if (err < 0)
+ goto unlock;
+
err = -EINVAL;
if (!(mnt_flags & MNT_SHRINKABLE) && !check_mnt(path->mnt))
goto unlock;
@@ -1958,22 +1962,29 @@ int do_add_mount(struct vfsmount *newmnt, struct path *path,
goto unlock;
newmnt->mnt_flags = mnt_flags;
- if ((err = graft_tree(newmnt, path)))
- goto unlock;
-
- if (fslist) /* add to the specified expiration list */
- list_add_tail(&newmnt->mnt_expire, fslist);
-
- up_write(&namespace_sem);
- return 0;
+ err = graft_tree(newmnt, path);
unlock:
up_write(&namespace_sem);
- mntput_long(newmnt);
return err;
}
-EXPORT_SYMBOL_GPL(do_add_mount);
+/**
+ * mnt_set_expiry - Put a mount on an expiration list
+ * @mnt: The mount to list.
+ * @expiry_list: The list to add the mount to.
+ */
+void mnt_set_expiry(struct vfsmount *mnt, struct list_head *expiry_list)
+{
+ down_write(&namespace_sem);
+ br_write_lock(vfsmount_lock);
+
+ list_add_tail(&mnt->mnt_expire, expiry_list);
+
+ br_write_unlock(vfsmount_lock);
+ up_write(&namespace_sem);
+}
+EXPORT_SYMBOL(mnt_set_expiry);
/*
* process a list of expirable mountpoints with the intent of discarding any
@@ -2262,6 +2273,22 @@ static struct mnt_namespace *alloc_mnt_ns(void)
return new_ns;
}
+void mnt_make_longterm(struct vfsmount *mnt)
+{
+ __mnt_make_longterm(mnt);
+}
+
+void mnt_make_shortterm(struct vfsmount *mnt)
+{
+#ifdef CONFIG_SMP
+ if (atomic_add_unless(&mnt->mnt_longterm, -1, 1))
+ return;
+ br_write_lock(vfsmount_lock);
+ atomic_dec(&mnt->mnt_longterm);
+ br_write_unlock(vfsmount_lock);
+#endif
+}
+
/*
* Allocate a new namespace structure and populate it with contents
* copied from the namespace of the passed in task structure.
@@ -2299,14 +2326,19 @@ static struct mnt_namespace *dup_mnt_ns(struct mnt_namespace *mnt_ns,
q = new_ns->root;
while (p) {
q->mnt_ns = new_ns;
+ __mnt_make_longterm(q);
if (fs) {
if (p == fs->root.mnt) {
+ fs->root.mnt = mntget(q);
+ __mnt_make_longterm(q);
+ mnt_make_shortterm(p);
rootmnt = p;
- fs->root.mnt = mntget_long(q);
}
if (p == fs->pwd.mnt) {
+ fs->pwd.mnt = mntget(q);
+ __mnt_make_longterm(q);
+ mnt_make_shortterm(p);
pwdmnt = p;
- fs->pwd.mnt = mntget_long(q);
}
}
p = next_mnt(p, mnt_ns->root);
@@ -2315,9 +2347,9 @@ static struct mnt_namespace *dup_mnt_ns(struct mnt_namespace *mnt_ns,
up_write(&namespace_sem);
if (rootmnt)
- mntput_long(rootmnt);
+ mntput(rootmnt);
if (pwdmnt)
- mntput_long(pwdmnt);
+ mntput(pwdmnt);
return new_ns;
}
@@ -2350,6 +2382,7 @@ struct mnt_namespace *create_mnt_ns(struct vfsmount *mnt)
new_ns = alloc_mnt_ns();
if (!IS_ERR(new_ns)) {
mnt->mnt_ns = new_ns;
+ __mnt_make_longterm(mnt);
new_ns->root = mnt;
list_add(&new_ns->list, &new_ns->root->mnt_list);
}
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index 64ee240..2c3eb33 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -970,7 +970,7 @@ int nfs_lookup_verify_inode(struct inode *inode, struct nameidata *nd)
{
struct nfs_server *server = NFS_SERVER(inode);
- if (test_bit(NFS_INO_MOUNTPOINT, &NFS_I(inode)->flags))
+ if (IS_AUTOMOUNT(inode))
return 0;
if (nd != NULL) {
/* VFS wants an on-the-wire revalidation */
@@ -1173,6 +1173,7 @@ const struct dentry_operations nfs_dentry_operations = {
.d_revalidate = nfs_lookup_revalidate,
.d_delete = nfs_dentry_delete,
.d_iput = nfs_dentry_iput,
+ .d_automount = nfs_d_automount,
};
static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, struct nameidata *nd)
@@ -1246,6 +1247,7 @@ const struct dentry_operations nfs4_dentry_operations = {
.d_revalidate = nfs_open_revalidate,
.d_delete = nfs_dentry_delete,
.d_iput = nfs_dentry_iput,
+ .d_automount = nfs_d_automount,
};
/*
@@ -1406,11 +1408,15 @@ no_open:
static int nfs_open_revalidate(struct dentry *dentry, struct nameidata *nd)
{
struct dentry *parent = NULL;
- struct inode *inode = dentry->d_inode;
+ struct inode *inode;
struct inode *dir;
struct nfs_open_context *ctx;
int openflags, ret = 0;
+ if (nd->flags & LOOKUP_RCU)
+ return -ECHILD;
+
+ inode = dentry->d_inode;
if (!is_atomic_open(nd) || d_mountpoint(dentry))
goto no_open;
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index ce00b70..d851242 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -300,7 +300,7 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr)
else
inode->i_op = &nfs_mountpoint_inode_operations;
inode->i_fop = NULL;
- set_bit(NFS_INO_MOUNTPOINT, &nfsi->flags);
+ inode->i_flags |= S_AUTOMOUNT;
}
} else if (S_ISLNK(inode->i_mode))
inode->i_op = &nfs_symlink_inode_operations;
@@ -1208,7 +1208,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
/* Update the fsid? */
if (S_ISDIR(inode->i_mode) && (fattr->valid & NFS_ATTR_FATTR_FSID) &&
!nfs_fsid_equal(&server->fsid, &fattr->fsid) &&
- !test_bit(NFS_INO_MOUNTPOINT, &nfsi->flags))
+ !IS_AUTOMOUNT(inode))
server->fsid = fattr->fsid;
/*
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h
index bfa3a34..4644f04 100644
--- a/fs/nfs/internal.h
+++ b/fs/nfs/internal.h
@@ -252,6 +252,7 @@ extern char *nfs_path(const char *base,
const struct dentry *droot,
const struct dentry *dentry,
char *buffer, ssize_t buflen);
+extern struct vfsmount *nfs_d_automount(struct path *path);
/* getroot.c */
extern struct dentry *nfs_get_root(struct super_block *, struct nfs_fh *);
diff --git a/fs/nfs/namespace.c b/fs/nfs/namespace.c
index 74aaf39..f32b860 100644
--- a/fs/nfs/namespace.c
+++ b/fs/nfs/namespace.c
@@ -97,9 +97,8 @@ Elong:
}
/*
- * nfs_follow_mountpoint - handle crossing a mountpoint on the server
- * @dentry - dentry of mountpoint
- * @nd - nameidata info
+ * nfs_d_automount - Handle crossing a mountpoint on the server
+ * @path - The mountpoint
*
* When we encounter a mountpoint on the server, we want to set up
* a mountpoint on the client too, to prevent inode numbers from
@@ -109,87 +108,65 @@ Elong:
* situation, and that different filesystems may want to use
* different security flavours.
*/
-static void * nfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd)
+struct vfsmount *nfs_d_automount(struct path *path)
{
struct vfsmount *mnt;
- struct nfs_server *server = NFS_SERVER(dentry->d_inode);
+ struct nfs_server *server = NFS_SERVER(path->dentry->d_inode);
struct dentry *parent;
struct nfs_fh *fh = NULL;
struct nfs_fattr *fattr = NULL;
int err;
- dprintk("--> nfs_follow_mountpoint()\n");
+ dprintk("--> nfs_d_automount()\n");
- err = -ESTALE;
- if (IS_ROOT(dentry))
- goto out_err;
+ mnt = ERR_PTR(-ESTALE);
+ if (IS_ROOT(path->dentry))
+ goto out_nofree;
- err = -ENOMEM;
+ mnt = ERR_PTR(-ENOMEM);
fh = nfs_alloc_fhandle();
fattr = nfs_alloc_fattr();
if (fh == NULL || fattr == NULL)
- goto out_err;
+ goto out;
dprintk("%s: enter\n", __func__);
- dput(nd->path.dentry);
- nd->path.dentry = dget(dentry);
- /* Look it up again */
- parent = dget_parent(nd->path.dentry);
+ /* Look it up again to get its attributes */
+ parent = dget_parent(path->dentry);
err = server->nfs_client->rpc_ops->lookup(parent->d_inode,
- &nd->path.dentry->d_name,
+ &path->dentry->d_name,
fh, fattr);
dput(parent);
- if (err != 0)
- goto out_err;
+ if (err != 0) {
+ mnt = ERR_PTR(err);
+ goto out;
+ }
if (fattr->valid & NFS_ATTR_FATTR_V4_REFERRAL)
- mnt = nfs_do_refmount(nd->path.mnt, nd->path.dentry);
+ mnt = nfs_do_refmount(path->mnt, path->dentry);
else
- mnt = nfs_do_submount(nd->path.mnt, nd->path.dentry, fh,
- fattr);
- err = PTR_ERR(mnt);
+ mnt = nfs_do_submount(path->mnt, path->dentry, fh, fattr);
if (IS_ERR(mnt))
- goto out_err;
+ goto out;
- mntget(mnt);
- err = do_add_mount(mnt, &nd->path, nd->path.mnt->mnt_flags|MNT_SHRINKABLE,
- &nfs_automount_list);
- if (err < 0) {
- mntput(mnt);
- if (err == -EBUSY)
- goto out_follow;
- goto out_err;
- }
- path_put(&nd->path);
- nd->path.mnt = mnt;
- nd->path.dentry = dget(mnt->mnt_root);
+ dprintk("%s: done, success\n", __func__);
+ mntget(mnt); /* prevent immediate expiration */
+ mnt_set_expiry(mnt, &nfs_automount_list);
schedule_delayed_work(&nfs_automount_task, nfs_mountpoint_expiry_timeout);
+
out:
nfs_free_fattr(fattr);
nfs_free_fhandle(fh);
- dprintk("%s: done, returned %d\n", __func__, err);
-
- dprintk("<-- nfs_follow_mountpoint() = %d\n", err);
- return ERR_PTR(err);
-out_err:
- path_put(&nd->path);
- goto out;
-out_follow:
- while (d_mountpoint(nd->path.dentry) &&
- follow_down(&nd->path))
- ;
- err = 0;
- goto out;
+out_nofree:
+ dprintk("<-- nfs_follow_mountpoint() = %p\n", mnt);
+ return mnt;
}
const struct inode_operations nfs_mountpoint_inode_operations = {
- .follow_link = nfs_follow_mountpoint,
.getattr = nfs_getattr,
};
const struct inode_operations nfs_referral_inode_operations = {
- .follow_link = nfs_follow_mountpoint,
};
static void nfs_expire_automounts(struct work_struct *work)
diff --git a/include/linux/nfs4_acl.h b/fs/nfsd/acl.h
index c9c05a7..34e5c40 100644
--- a/include/linux/nfs4_acl.h
+++ b/fs/nfsd/acl.h
@@ -1,6 +1,4 @@
/*
- * include/linux/nfs4_acl.c
- *
* Common NFSv4 ACL handling definitions.
*
* Copyright (c) 2002 The Regents of the University of Michigan.
diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c
index c0fcb7a..8b31e5f 100644
--- a/fs/nfsd/export.c
+++ b/fs/nfsd/export.c
@@ -1,4 +1,3 @@
-#define MSNFS /* HACK HACK */
/*
* NFS exporting and validation.
*
@@ -1444,9 +1443,6 @@ static struct flags {
{ NFSEXP_NOSUBTREECHECK, {"no_subtree_check", ""}},
{ NFSEXP_NOAUTHNLM, {"insecure_locks", ""}},
{ NFSEXP_V4ROOT, {"v4root", ""}},
-#ifdef MSNFS
- { NFSEXP_MSNFS, {"msnfs", ""}},
-#endif
{ 0, {"", ""}}
};
diff --git a/include/linux/nfsd_idmap.h b/fs/nfsd/idmap.h
index d4a2ac1..2f3be13 100644
--- a/include/linux/nfsd_idmap.h
+++ b/fs/nfsd/idmap.h
@@ -1,6 +1,4 @@
/*
- * include/linux/nfsd_idmap.h
- *
* Mapping of UID to name and vice versa.
*
* Copyright (c) 2002, 2003 The Regents of the University of
@@ -56,8 +54,8 @@ static inline void nfsd_idmap_shutdown(void)
}
#endif
-int nfsd_map_name_to_uid(struct svc_rqst *, const char *, size_t, __u32 *);
-int nfsd_map_name_to_gid(struct svc_rqst *, const char *, size_t, __u32 *);
+__be32 nfsd_map_name_to_uid(struct svc_rqst *, const char *, size_t, __u32 *);
+__be32 nfsd_map_name_to_gid(struct svc_rqst *, const char *, size_t, __u32 *);
int nfsd_map_uid_to_name(struct svc_rqst *, __u32, char *);
int nfsd_map_gid_to_name(struct svc_rqst *, __u32, char *);
diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c
index 5b7e302..2247fc9 100644
--- a/fs/nfsd/nfs3proc.c
+++ b/fs/nfsd/nfs3proc.c
@@ -151,10 +151,10 @@ nfsd3_proc_read(struct svc_rqst *rqstp, struct nfsd3_readargs *argp,
__be32 nfserr;
u32 max_blocksize = svc_max_payload(rqstp);
- dprintk("nfsd: READ(3) %s %lu bytes at %lu\n",
+ dprintk("nfsd: READ(3) %s %lu bytes at %Lu\n",
SVCFH_fmt(&argp->fh),
(unsigned long) argp->count,
- (unsigned long) argp->offset);
+ (unsigned long long) argp->offset);
/* Obtain buffer pointer for payload.
* 1 (status) + 22 (post_op_attr) + 1 (count) + 1 (eof)
@@ -191,10 +191,10 @@ nfsd3_proc_write(struct svc_rqst *rqstp, struct nfsd3_writeargs *argp,
__be32 nfserr;
unsigned long cnt = argp->len;
- dprintk("nfsd: WRITE(3) %s %d bytes at %ld%s\n",
+ dprintk("nfsd: WRITE(3) %s %d bytes at %Lu%s\n",
SVCFH_fmt(&argp->fh),
argp->len,
- (unsigned long) argp->offset,
+ (unsigned long long) argp->offset,
argp->stable? " stable" : "");
fh_copy(&resp->fh, &argp->fh);
diff --git a/fs/nfsd/nfs4acl.c b/fs/nfsd/nfs4acl.c
index e480526..ad88f1c 100644
--- a/fs/nfsd/nfs4acl.c
+++ b/fs/nfsd/nfs4acl.c
@@ -36,7 +36,7 @@
#include <linux/slab.h>
#include <linux/nfs_fs.h>
-#include <linux/nfs4_acl.h>
+#include "acl.h"
/* mode bit translations: */
diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c
index 21a63da..3be975e 100644
--- a/fs/nfsd/nfs4callback.c
+++ b/fs/nfsd/nfs4callback.c
@@ -628,10 +628,8 @@ static int max_cb_time(void)
return max(nfsd4_lease/10, (time_t)1) * HZ;
}
-/* Reference counting, callback cleanup, etc., all look racy as heck.
- * And why is cl_cb_set an atomic? */
-int setup_callback_client(struct nfs4_client *clp, struct nfs4_cb_conn *conn)
+static int setup_callback_client(struct nfs4_client *clp, struct nfs4_cb_conn *conn, struct nfsd4_session *ses)
{
struct rpc_timeout timeparms = {
.to_initval = max_cb_time(),
@@ -641,6 +639,7 @@ int setup_callback_client(struct nfs4_client *clp, struct nfs4_cb_conn *conn)
.net = &init_net,
.address = (struct sockaddr *) &conn->cb_addr,
.addrsize = conn->cb_addrlen,
+ .saddress = (struct sockaddr *) &conn->cb_saddr,
.timeout = &timeparms,
.program = &cb_program,
.version = 0,
@@ -657,6 +656,10 @@ int setup_callback_client(struct nfs4_client *clp, struct nfs4_cb_conn *conn)
args.protocol = XPRT_TRANSPORT_TCP;
clp->cl_cb_ident = conn->cb_ident;
} else {
+ if (!conn->cb_xprt)
+ return -EINVAL;
+ clp->cl_cb_conn.cb_xprt = conn->cb_xprt;
+ clp->cl_cb_session = ses;
args.bc_xprt = conn->cb_xprt;
args.prognumber = clp->cl_cb_session->se_cb_prog;
args.protocol = XPRT_TRANSPORT_BC_TCP;
@@ -679,14 +682,20 @@ static void warn_no_callback_path(struct nfs4_client *clp, int reason)
(int)clp->cl_name.len, clp->cl_name.data, reason);
}
+static void nfsd4_mark_cb_down(struct nfs4_client *clp, int reason)
+{
+ clp->cl_cb_state = NFSD4_CB_DOWN;
+ warn_no_callback_path(clp, reason);
+}
+
static void nfsd4_cb_probe_done(struct rpc_task *task, void *calldata)
{
struct nfs4_client *clp = container_of(calldata, struct nfs4_client, cl_cb_null);
if (task->tk_status)
- warn_no_callback_path(clp, task->tk_status);
+ nfsd4_mark_cb_down(clp, task->tk_status);
else
- atomic_set(&clp->cl_cb_set, 1);
+ clp->cl_cb_state = NFSD4_CB_UP;
}
static const struct rpc_call_ops nfsd4_cb_probe_ops = {
@@ -709,6 +718,11 @@ int set_callback_cred(void)
static struct workqueue_struct *callback_wq;
+static void run_nfsd4_cb(struct nfsd4_callback *cb)
+{
+ queue_work(callback_wq, &cb->cb_work);
+}
+
static void do_probe_callback(struct nfs4_client *clp)
{
struct nfsd4_callback *cb = &clp->cl_cb_null;
@@ -723,7 +737,7 @@ static void do_probe_callback(struct nfs4_client *clp)
cb->cb_ops = &nfsd4_cb_probe_ops;
- queue_work(callback_wq, &cb->cb_work);
+ run_nfsd4_cb(cb);
}
/*
@@ -732,14 +746,21 @@ static void do_probe_callback(struct nfs4_client *clp)
*/
void nfsd4_probe_callback(struct nfs4_client *clp)
{
+ /* XXX: atomicity? Also, should we be using cl_cb_flags? */
+ clp->cl_cb_state = NFSD4_CB_UNKNOWN;
set_bit(NFSD4_CLIENT_CB_UPDATE, &clp->cl_cb_flags);
do_probe_callback(clp);
}
-void nfsd4_change_callback(struct nfs4_client *clp, struct nfs4_cb_conn *conn)
+void nfsd4_probe_callback_sync(struct nfs4_client *clp)
{
- BUG_ON(atomic_read(&clp->cl_cb_set));
+ nfsd4_probe_callback(clp);
+ flush_workqueue(callback_wq);
+}
+void nfsd4_change_callback(struct nfs4_client *clp, struct nfs4_cb_conn *conn)
+{
+ clp->cl_cb_state = NFSD4_CB_UNKNOWN;
spin_lock(&clp->cl_lock);
memcpy(&clp->cl_cb_conn, conn, sizeof(struct nfs4_cb_conn));
spin_unlock(&clp->cl_lock);
@@ -750,24 +771,14 @@ void nfsd4_change_callback(struct nfs4_client *clp, struct nfs4_cb_conn *conn)
* If the slot is available, then mark it busy. Otherwise, set the
* thread for sleeping on the callback RPC wait queue.
*/
-static int nfsd41_cb_setup_sequence(struct nfs4_client *clp,
- struct rpc_task *task)
+static bool nfsd41_cb_get_slot(struct nfs4_client *clp, struct rpc_task *task)
{
- u32 *ptr = (u32 *)clp->cl_cb_session->se_sessionid.data;
- int status = 0;
-
- dprintk("%s: %u:%u:%u:%u\n", __func__,
- ptr[0], ptr[1], ptr[2], ptr[3]);
-
if (test_and_set_bit(0, &clp->cl_cb_slot_busy) != 0) {
rpc_sleep_on(&clp->cl_cb_waitq, task, NULL);
dprintk("%s slot is busy\n", __func__);
- status = -EAGAIN;
- goto out;
+ return false;
}
-out:
- dprintk("%s status=%d\n", __func__, status);
- return status;
+ return true;
}
/*
@@ -780,20 +791,19 @@ static void nfsd4_cb_prepare(struct rpc_task *task, void *calldata)
struct nfs4_delegation *dp = container_of(cb, struct nfs4_delegation, dl_recall);
struct nfs4_client *clp = dp->dl_client;
u32 minorversion = clp->cl_minorversion;
- int status = 0;
cb->cb_minorversion = minorversion;
if (minorversion) {
- status = nfsd41_cb_setup_sequence(clp, task);
- if (status) {
- if (status != -EAGAIN) {
- /* terminate rpc task */
- task->tk_status = status;
- task->tk_action = NULL;
- }
+ if (!nfsd41_cb_get_slot(clp, task))
return;
- }
}
+ spin_lock(&clp->cl_lock);
+ if (list_empty(&cb->cb_per_client)) {
+ /* This is the first call, not a restart */
+ cb->cb_done = false;
+ list_add(&cb->cb_per_client, &clp->cl_callbacks);
+ }
+ spin_unlock(&clp->cl_lock);
rpc_call_start(task);
}
@@ -829,15 +839,18 @@ static void nfsd4_cb_recall_done(struct rpc_task *task, void *calldata)
nfsd4_cb_done(task, calldata);
- if (current_rpc_client == NULL) {
- /* We're shutting down; give up. */
- /* XXX: err, or is it ok just to fall through
- * and rpc_restart_call? */
+ if (current_rpc_client != task->tk_client) {
+ /* We're shutting down or changing cl_cb_client; leave
+ * it to nfsd4_process_cb_update to restart the call if
+ * necessary. */
return;
}
+ if (cb->cb_done)
+ return;
switch (task->tk_status) {
case 0:
+ cb->cb_done = true;
return;
case -EBADHANDLE:
case -NFS4ERR_BAD_STATEID:
@@ -846,32 +859,30 @@ static void nfsd4_cb_recall_done(struct rpc_task *task, void *calldata)
break;
default:
/* Network partition? */
- atomic_set(&clp->cl_cb_set, 0);
- warn_no_callback_path(clp, task->tk_status);
- if (current_rpc_client != task->tk_client) {
- /* queue a callback on the new connection: */
- atomic_inc(&dp->dl_count);
- nfsd4_cb_recall(dp);
- return;
- }
+ nfsd4_mark_cb_down(clp, task->tk_status);
}
if (dp->dl_retries--) {
rpc_delay(task, 2*HZ);
task->tk_status = 0;
rpc_restart_call_prepare(task);
return;
- } else {
- atomic_set(&clp->cl_cb_set, 0);
- warn_no_callback_path(clp, task->tk_status);
}
+ nfsd4_mark_cb_down(clp, task->tk_status);
+ cb->cb_done = true;
}
static void nfsd4_cb_recall_release(void *calldata)
{
struct nfsd4_callback *cb = calldata;
+ struct nfs4_client *clp = cb->cb_clp;
struct nfs4_delegation *dp = container_of(cb, struct nfs4_delegation, dl_recall);
- nfs4_put_delegation(dp);
+ if (cb->cb_done) {
+ spin_lock(&clp->cl_lock);
+ list_del(&cb->cb_per_client);
+ spin_unlock(&clp->cl_lock);
+ nfs4_put_delegation(dp);
+ }
}
static const struct rpc_call_ops nfsd4_cb_recall_ops = {
@@ -906,16 +917,33 @@ void nfsd4_shutdown_callback(struct nfs4_client *clp)
flush_workqueue(callback_wq);
}
-void nfsd4_release_cb(struct nfsd4_callback *cb)
+static void nfsd4_release_cb(struct nfsd4_callback *cb)
{
if (cb->cb_ops->rpc_release)
cb->cb_ops->rpc_release(cb);
}
-void nfsd4_process_cb_update(struct nfsd4_callback *cb)
+/* requires cl_lock: */
+static struct nfsd4_conn * __nfsd4_find_backchannel(struct nfs4_client *clp)
+{
+ struct nfsd4_session *s;
+ struct nfsd4_conn *c;
+
+ list_for_each_entry(s, &clp->cl_sessions, se_perclnt) {
+ list_for_each_entry(c, &s->se_conns, cn_persession) {
+ if (c->cn_flags & NFS4_CDFC4_BACK)
+ return c;
+ }
+ }
+ return NULL;
+}
+
+static void nfsd4_process_cb_update(struct nfsd4_callback *cb)
{
struct nfs4_cb_conn conn;
struct nfs4_client *clp = cb->cb_clp;
+ struct nfsd4_session *ses = NULL;
+ struct nfsd4_conn *c;
int err;
/*
@@ -926,6 +954,10 @@ void nfsd4_process_cb_update(struct nfsd4_callback *cb)
rpc_shutdown_client(clp->cl_cb_client);
clp->cl_cb_client = NULL;
}
+ if (clp->cl_cb_conn.cb_xprt) {
+ svc_xprt_put(clp->cl_cb_conn.cb_xprt);
+ clp->cl_cb_conn.cb_xprt = NULL;
+ }
if (test_bit(NFSD4_CLIENT_KILL, &clp->cl_cb_flags))
return;
spin_lock(&clp->cl_lock);
@@ -936,11 +968,22 @@ void nfsd4_process_cb_update(struct nfsd4_callback *cb)
BUG_ON(!clp->cl_cb_flags);
clear_bit(NFSD4_CLIENT_CB_UPDATE, &clp->cl_cb_flags);
memcpy(&conn, &cb->cb_clp->cl_cb_conn, sizeof(struct nfs4_cb_conn));
+ c = __nfsd4_find_backchannel(clp);
+ if (c) {
+ svc_xprt_get(c->cn_xprt);
+ conn.cb_xprt = c->cn_xprt;
+ ses = c->cn_session;
+ }
spin_unlock(&clp->cl_lock);
- err = setup_callback_client(clp, &conn);
- if (err)
+ err = setup_callback_client(clp, &conn, ses);
+ if (err) {
warn_no_callback_path(clp, err);
+ return;
+ }
+ /* Yay, the callback channel's back! Restart any callbacks: */
+ list_for_each_entry(cb, &clp->cl_callbacks, cb_per_client)
+ run_nfsd4_cb(cb);
}
void nfsd4_do_callback_rpc(struct work_struct *w)
@@ -965,10 +1008,11 @@ void nfsd4_do_callback_rpc(struct work_struct *w)
void nfsd4_cb_recall(struct nfs4_delegation *dp)
{
struct nfsd4_callback *cb = &dp->dl_recall;
+ struct nfs4_client *clp = dp->dl_client;
dp->dl_retries = 1;
cb->cb_op = dp;
- cb->cb_clp = dp->dl_client;
+ cb->cb_clp = clp;
cb->cb_msg.rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_RECALL];
cb->cb_msg.rpc_argp = cb;
cb->cb_msg.rpc_resp = cb;
@@ -977,5 +1021,8 @@ void nfsd4_cb_recall(struct nfs4_delegation *dp)
cb->cb_ops = &nfsd4_cb_recall_ops;
dp->dl_retries = 1;
- queue_work(callback_wq, &dp->dl_recall.cb_work);
+ INIT_LIST_HEAD(&cb->cb_per_client);
+ cb->cb_done = true;
+
+ run_nfsd4_cb(&dp->dl_recall);
}
diff --git a/fs/nfsd/nfs4idmap.c b/fs/nfsd/nfs4idmap.c
index f0695e8..6d2c397 100644
--- a/fs/nfsd/nfs4idmap.c
+++ b/fs/nfsd/nfs4idmap.c
@@ -33,10 +33,11 @@
*/
#include <linux/module.h>
-#include <linux/nfsd_idmap.h>
#include <linux/seq_file.h>
#include <linux/sched.h>
#include <linux/slab.h>
+#include "idmap.h"
+#include "nfsd.h"
/*
* Cache entry
@@ -514,7 +515,7 @@ rqst_authname(struct svc_rqst *rqstp)
return clp->name;
}
-static int
+static __be32
idmap_name_to_id(struct svc_rqst *rqstp, int type, const char *name, u32 namelen,
uid_t *id)
{
@@ -524,15 +525,15 @@ idmap_name_to_id(struct svc_rqst *rqstp, int type, const char *name, u32 namelen
int ret;
if (namelen + 1 > sizeof(key.name))
- return -EINVAL;
+ return nfserr_badowner;
memcpy(key.name, name, namelen);
key.name[namelen] = '\0';
strlcpy(key.authname, rqst_authname(rqstp), sizeof(key.authname));
ret = idmap_lookup(rqstp, nametoid_lookup, &key, &nametoid_cache, &item);
if (ret == -ENOENT)
- ret = -ESRCH; /* nfserr_badname */
+ return nfserr_badowner;
if (ret)
- return ret;
+ return nfserrno(ret);
*id = item->id;
cache_put(&item->h, &nametoid_cache);
return 0;
@@ -560,14 +561,14 @@ idmap_id_to_name(struct svc_rqst *rqstp, int type, uid_t id, char *name)
return ret;
}
-int
+__be32
nfsd_map_name_to_uid(struct svc_rqst *rqstp, const char *name, size_t namelen,
__u32 *id)
{
return idmap_name_to_id(rqstp, IDMAP_TYPE_USER, name, namelen, id);
}
-int
+__be32
nfsd_map_name_to_gid(struct svc_rqst *rqstp, const char *name, size_t namelen,
__u32 *id)
{
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
index 0cdfd02..db52546 100644
--- a/fs/nfsd/nfs4proc.c
+++ b/fs/nfsd/nfs4proc.c
@@ -604,9 +604,7 @@ nfsd4_link(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
return status;
}
-static __be32
-nfsd4_lookupp(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
- void *arg)
+static __be32 nfsd4_do_lookupp(struct svc_rqst *rqstp, struct svc_fh *fh)
{
struct svc_fh tmp_fh;
__be32 ret;
@@ -615,13 +613,19 @@ nfsd4_lookupp(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
ret = exp_pseudoroot(rqstp, &tmp_fh);
if (ret)
return ret;
- if (tmp_fh.fh_dentry == cstate->current_fh.fh_dentry) {
+ if (tmp_fh.fh_dentry == fh->fh_dentry) {
fh_put(&tmp_fh);
return nfserr_noent;
}
fh_put(&tmp_fh);
- return nfsd_lookup(rqstp, &cstate->current_fh,
- "..", 2, &cstate->current_fh);
+ return nfsd_lookup(rqstp, fh, "..", 2, fh);
+}
+
+static __be32
+nfsd4_lookupp(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
+ void *arg)
+{
+ return nfsd4_do_lookupp(rqstp, &cstate->current_fh);
}
static __be32
@@ -769,10 +773,36 @@ nfsd4_secinfo(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
} else
secinfo->si_exp = exp;
dput(dentry);
+ if (cstate->minorversion)
+ /* See rfc 5661 section 2.6.3.1.1.8 */
+ fh_put(&cstate->current_fh);
return err;
}
static __be32
+nfsd4_secinfo_no_name(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
+ struct nfsd4_secinfo_no_name *sin)
+{
+ __be32 err;
+
+ switch (sin->sin_style) {
+ case NFS4_SECINFO_STYLE4_CURRENT_FH:
+ break;
+ case NFS4_SECINFO_STYLE4_PARENT:
+ err = nfsd4_do_lookupp(rqstp, &cstate->current_fh);
+ if (err)
+ return err;
+ break;
+ default:
+ return nfserr_inval;
+ }
+ exp_get(cstate->current_fh.fh_export);
+ sin->sin_exp = cstate->current_fh.fh_export;
+ fh_put(&cstate->current_fh);
+ return nfs_ok;
+}
+
+static __be32
nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
struct nfsd4_setattr *setattr)
{
@@ -974,8 +1004,8 @@ static const char *nfsd4_op_name(unsigned opnum);
* Also note, enforced elsewhere:
* - SEQUENCE other than as first op results in
* NFS4ERR_SEQUENCE_POS. (Enforced in nfsd4_sequence().)
- * - BIND_CONN_TO_SESSION must be the only op in its compound
- * (Will be enforced in nfsd4_bind_conn_to_session().)
+ * - BIND_CONN_TO_SESSION must be the only op in its compound.
+ * (Enforced in nfsd4_bind_conn_to_session().)
* - DESTROY_SESSION must be the final operation in a compound, if
* sessionid's in SEQUENCE and DESTROY_SESSION are the same.
* (Enforced in nfsd4_destroy_session().)
@@ -1126,10 +1156,6 @@ encode_op:
nfsd4_increment_op_stats(op->opnum);
}
- if (!rqstp->rq_usedeferral && status == nfserr_dropit) {
- dprintk("%s Dropit - send NFS4ERR_DELAY\n", __func__);
- status = nfserr_jukebox;
- }
resp->cstate.status = status;
fh_put(&resp->cstate.current_fh);
@@ -1300,6 +1326,11 @@ static struct nfsd4_operation nfsd4_ops[] = {
.op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP,
.op_name = "OP_EXCHANGE_ID",
},
+ [OP_BIND_CONN_TO_SESSION] = {
+ .op_func = (nfsd4op_func)nfsd4_bind_conn_to_session,
+ .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP,
+ .op_name = "OP_BIND_CONN_TO_SESSION",
+ },
[OP_CREATE_SESSION] = {
.op_func = (nfsd4op_func)nfsd4_create_session,
.op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP,
@@ -1320,6 +1351,10 @@ static struct nfsd4_operation nfsd4_ops[] = {
.op_flags = ALLOWED_WITHOUT_FH,
.op_name = "OP_RECLAIM_COMPLETE",
},
+ [OP_SECINFO_NO_NAME] = {
+ .op_func = (nfsd4op_func)nfsd4_secinfo_no_name,
+ .op_name = "OP_SECINFO_NO_NAME",
+ },
};
static const char *nfsd4_op_name(unsigned opnum)
diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c
index 7e26caa..ffb59ef 100644
--- a/fs/nfsd/nfs4recover.c
+++ b/fs/nfsd/nfs4recover.c
@@ -302,7 +302,6 @@ purge_old(struct dentry *parent, struct dentry *child)
{
int status;
- /* note: we currently use this path only for minorversion 0 */
if (nfs4_has_reclaimed_state(child->d_name.name, false))
return 0;
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index fbd18c3..d98d021 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -230,7 +230,8 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_stateid *stp, struct svc_f
dp->dl_client = clp;
get_nfs4_file(fp);
dp->dl_file = fp;
- nfs4_file_get_access(fp, O_RDONLY);
+ dp->dl_vfs_file = find_readable_file(fp);
+ get_file(dp->dl_vfs_file);
dp->dl_flock = NULL;
dp->dl_type = type;
dp->dl_stateid.si_boot = boot_time;
@@ -252,6 +253,7 @@ nfs4_put_delegation(struct nfs4_delegation *dp)
if (atomic_dec_and_test(&dp->dl_count)) {
dprintk("NFSD: freeing dp %p\n",dp);
put_nfs4_file(dp->dl_file);
+ fput(dp->dl_vfs_file);
kmem_cache_free(deleg_slab, dp);
num_delegations--;
}
@@ -265,12 +267,10 @@ nfs4_put_delegation(struct nfs4_delegation *dp)
static void
nfs4_close_delegation(struct nfs4_delegation *dp)
{
- struct file *filp = find_readable_file(dp->dl_file);
-
dprintk("NFSD: close_delegation dp %p\n",dp);
+ /* XXX: do we even need this check?: */
if (dp->dl_flock)
- vfs_setlease(filp, F_UNLCK, &dp->dl_flock);
- nfs4_file_put_access(dp->dl_file, O_RDONLY);
+ vfs_setlease(dp->dl_vfs_file, F_UNLCK, &dp->dl_flock);
}
/* Called under the state lock. */
@@ -642,6 +642,7 @@ static void nfsd4_conn_lost(struct svc_xpt_user *u)
free_conn(c);
}
spin_unlock(&clp->cl_lock);
+ nfsd4_probe_callback(clp);
}
static struct nfsd4_conn *alloc_conn(struct svc_rqst *rqstp, u32 flags)
@@ -679,15 +680,12 @@ static int nfsd4_register_conn(struct nfsd4_conn *conn)
return register_xpt_user(conn->cn_xprt, &conn->cn_xpt_user);
}
-static __be32 nfsd4_new_conn(struct svc_rqst *rqstp, struct nfsd4_session *ses)
+static __be32 nfsd4_new_conn(struct svc_rqst *rqstp, struct nfsd4_session *ses, u32 dir)
{
struct nfsd4_conn *conn;
- u32 flags = NFS4_CDFC4_FORE;
int ret;
- if (ses->se_flags & SESSION4_BACK_CHAN)
- flags |= NFS4_CDFC4_BACK;
- conn = alloc_conn(rqstp, flags);
+ conn = alloc_conn(rqstp, dir);
if (!conn)
return nfserr_jukebox;
nfsd4_hash_conn(conn, ses);
@@ -698,6 +696,17 @@ static __be32 nfsd4_new_conn(struct svc_rqst *rqstp, struct nfsd4_session *ses)
return nfs_ok;
}
+static __be32 nfsd4_new_conn_from_crses(struct svc_rqst *rqstp, struct nfsd4_session *ses)
+{
+ u32 dir = NFS4_CDFC4_FORE;
+
+ if (ses->se_flags & SESSION4_BACK_CHAN)
+ dir |= NFS4_CDFC4_BACK;
+
+ return nfsd4_new_conn(rqstp, ses, dir);
+}
+
+/* must be called under client_lock */
static void nfsd4_del_conns(struct nfsd4_session *s)
{
struct nfs4_client *clp = s->se_client;
@@ -749,6 +758,8 @@ static struct nfsd4_session *alloc_init_session(struct svc_rqst *rqstp, struct n
*/
slotsize = nfsd4_sanitize_slot_size(fchan->maxresp_cached);
numslots = nfsd4_get_drc_mem(slotsize, fchan->maxreqs);
+ if (numslots < 1)
+ return NULL;
new = alloc_session(slotsize, numslots);
if (!new) {
@@ -769,25 +780,30 @@ static struct nfsd4_session *alloc_init_session(struct svc_rqst *rqstp, struct n
idx = hash_sessionid(&new->se_sessionid);
spin_lock(&client_lock);
list_add(&new->se_hash, &sessionid_hashtbl[idx]);
+ spin_lock(&clp->cl_lock);
list_add(&new->se_perclnt, &clp->cl_sessions);
+ spin_unlock(&clp->cl_lock);
spin_unlock(&client_lock);
- status = nfsd4_new_conn(rqstp, new);
+ status = nfsd4_new_conn_from_crses(rqstp, new);
/* whoops: benny points out, status is ignored! (err, or bogus) */
if (status) {
free_session(&new->se_ref);
return NULL;
}
- if (!clp->cl_cb_session && (cses->flags & SESSION4_BACK_CHAN)) {
+ if (cses->flags & SESSION4_BACK_CHAN) {
struct sockaddr *sa = svc_addr(rqstp);
-
- clp->cl_cb_session = new;
- clp->cl_cb_conn.cb_xprt = rqstp->rq_xprt;
- svc_xprt_get(rqstp->rq_xprt);
+ /*
+ * This is a little silly; with sessions there's no real
+ * use for the callback address. Use the peer address
+ * as a reasonable default for now, but consider fixing
+ * the rpc client not to require an address in the
+ * future:
+ */
rpc_copy_addr((struct sockaddr *)&clp->cl_cb_conn.cb_addr, sa);
clp->cl_cb_conn.cb_addrlen = svc_addr_len(sa);
- nfsd4_probe_callback(clp);
}
+ nfsd4_probe_callback(clp);
return new;
}
@@ -817,7 +833,9 @@ static void
unhash_session(struct nfsd4_session *ses)
{
list_del(&ses->se_hash);
+ spin_lock(&ses->se_client->cl_lock);
list_del(&ses->se_perclnt);
+ spin_unlock(&ses->se_client->cl_lock);
}
/* must be called under the client_lock */
@@ -923,8 +941,10 @@ unhash_client_locked(struct nfs4_client *clp)
mark_client_expired(clp);
list_del(&clp->cl_lru);
+ spin_lock(&clp->cl_lock);
list_for_each_entry(ses, &clp->cl_sessions, se_perclnt)
list_del_init(&ses->se_hash);
+ spin_unlock(&clp->cl_lock);
}
static void
@@ -1051,12 +1071,13 @@ static struct nfs4_client *create_client(struct xdr_netobj name, char *recdir,
memcpy(clp->cl_recdir, recdir, HEXDIR_LEN);
atomic_set(&clp->cl_refcount, 0);
- atomic_set(&clp->cl_cb_set, 0);
+ clp->cl_cb_state = NFSD4_CB_UNKNOWN;
INIT_LIST_HEAD(&clp->cl_idhash);
INIT_LIST_HEAD(&clp->cl_strhash);
INIT_LIST_HEAD(&clp->cl_openowners);
INIT_LIST_HEAD(&clp->cl_delegations);
INIT_LIST_HEAD(&clp->cl_lru);
+ INIT_LIST_HEAD(&clp->cl_callbacks);
spin_lock_init(&clp->cl_lock);
INIT_WORK(&clp->cl_cb_null.cb_work, nfsd4_do_callback_rpc);
clp->cl_time = get_seconds();
@@ -1132,54 +1153,55 @@ find_unconfirmed_client(clientid_t *clid)
return NULL;
}
-/*
- * Return 1 iff clp's clientid establishment method matches the use_exchange_id
- * parameter. Matching is based on the fact the at least one of the
- * EXCHGID4_FLAG_USE_{NON_PNFS,PNFS_MDS,PNFS_DS} flags must be set for v4.1
- *
- * FIXME: we need to unify the clientid namespaces for nfsv4.x
- * and correctly deal with client upgrade/downgrade in EXCHANGE_ID
- * and SET_CLIENTID{,_CONFIRM}
- */
-static inline int
-match_clientid_establishment(struct nfs4_client *clp, bool use_exchange_id)
+static bool clp_used_exchangeid(struct nfs4_client *clp)
{
- bool has_exchange_flags = (clp->cl_exchange_flags != 0);
- return use_exchange_id == has_exchange_flags;
-}
+ return clp->cl_exchange_flags != 0;
+}
static struct nfs4_client *
-find_confirmed_client_by_str(const char *dname, unsigned int hashval,
- bool use_exchange_id)
+find_confirmed_client_by_str(const char *dname, unsigned int hashval)
{
struct nfs4_client *clp;
list_for_each_entry(clp, &conf_str_hashtbl[hashval], cl_strhash) {
- if (same_name(clp->cl_recdir, dname) &&
- match_clientid_establishment(clp, use_exchange_id))
+ if (same_name(clp->cl_recdir, dname))
return clp;
}
return NULL;
}
static struct nfs4_client *
-find_unconfirmed_client_by_str(const char *dname, unsigned int hashval,
- bool use_exchange_id)
+find_unconfirmed_client_by_str(const char *dname, unsigned int hashval)
{
struct nfs4_client *clp;
list_for_each_entry(clp, &unconf_str_hashtbl[hashval], cl_strhash) {
- if (same_name(clp->cl_recdir, dname) &&
- match_clientid_establishment(clp, use_exchange_id))
+ if (same_name(clp->cl_recdir, dname))
return clp;
}
return NULL;
}
+static void rpc_svcaddr2sockaddr(struct sockaddr *sa, unsigned short family, union svc_addr_u *svcaddr)
+{
+ switch (family) {
+ case AF_INET:
+ ((struct sockaddr_in *)sa)->sin_family = AF_INET;
+ ((struct sockaddr_in *)sa)->sin_addr = svcaddr->addr;
+ return;
+ case AF_INET6:
+ ((struct sockaddr_in6 *)sa)->sin6_family = AF_INET6;
+ ((struct sockaddr_in6 *)sa)->sin6_addr = svcaddr->addr6;
+ return;
+ }
+}
+
static void
-gen_callback(struct nfs4_client *clp, struct nfsd4_setclientid *se, u32 scopeid)
+gen_callback(struct nfs4_client *clp, struct nfsd4_setclientid *se, struct svc_rqst *rqstp)
{
struct nfs4_cb_conn *conn = &clp->cl_cb_conn;
+ struct sockaddr *sa = svc_addr(rqstp);
+ u32 scopeid = rpc_get_scope_id(sa);
unsigned short expected_family;
/* Currently, we only support tcp and tcp6 for the callback channel */
@@ -1205,6 +1227,7 @@ gen_callback(struct nfs4_client *clp, struct nfsd4_setclientid *se, u32 scopeid)
conn->cb_prog = se->se_callback_prog;
conn->cb_ident = se->se_callback_ident;
+ rpc_svcaddr2sockaddr((struct sockaddr *)&conn->cb_saddr, expected_family, &rqstp->rq_daddr);
return;
out_err:
conn->cb_addr.ss_family = AF_UNSPEC;
@@ -1344,7 +1367,7 @@ nfsd4_exchange_id(struct svc_rqst *rqstp,
case SP4_NONE:
break;
case SP4_SSV:
- return nfserr_encr_alg_unsupp;
+ return nfserr_serverfault;
default:
BUG(); /* checked by xdr code */
case SP4_MACH_CRED:
@@ -1361,8 +1384,12 @@ nfsd4_exchange_id(struct svc_rqst *rqstp,
nfs4_lock_state();
status = nfs_ok;
- conf = find_confirmed_client_by_str(dname, strhashval, true);
+ conf = find_confirmed_client_by_str(dname, strhashval);
if (conf) {
+ if (!clp_used_exchangeid(conf)) {
+ status = nfserr_clid_inuse; /* XXX: ? */
+ goto out;
+ }
if (!same_verf(&verf, &conf->cl_verifier)) {
/* 18.35.4 case 8 */
if (exid->flags & EXCHGID4_FLAG_UPD_CONFIRMED_REC_A) {
@@ -1403,7 +1430,7 @@ nfsd4_exchange_id(struct svc_rqst *rqstp,
goto out;
}
- unconf = find_unconfirmed_client_by_str(dname, strhashval, true);
+ unconf = find_unconfirmed_client_by_str(dname, strhashval);
if (unconf) {
/*
* Possible retry or client restart. Per 18.35.4 case 4,
@@ -1560,6 +1587,8 @@ nfsd4_create_session(struct svc_rqst *rqstp,
status = nfs_ok;
memcpy(cr_ses->sessionid.data, new->se_sessionid.data,
NFS4_MAX_SESSIONID_LEN);
+ memcpy(&cr_ses->fore_channel, &new->se_fchannel,
+ sizeof(struct nfsd4_channel_attrs));
cs_slot->sl_seqid++;
cr_ses->seqid = cs_slot->sl_seqid;
@@ -1581,6 +1610,45 @@ static bool nfsd4_last_compound_op(struct svc_rqst *rqstp)
return argp->opcnt == resp->opcnt;
}
+static __be32 nfsd4_map_bcts_dir(u32 *dir)
+{
+ switch (*dir) {
+ case NFS4_CDFC4_FORE:
+ case NFS4_CDFC4_BACK:
+ return nfs_ok;
+ case NFS4_CDFC4_FORE_OR_BOTH:
+ case NFS4_CDFC4_BACK_OR_BOTH:
+ *dir = NFS4_CDFC4_BOTH;
+ return nfs_ok;
+ };
+ return nfserr_inval;
+}
+
+__be32 nfsd4_bind_conn_to_session(struct svc_rqst *rqstp,
+ struct nfsd4_compound_state *cstate,
+ struct nfsd4_bind_conn_to_session *bcts)
+{
+ __be32 status;
+
+ if (!nfsd4_last_compound_op(rqstp))
+ return nfserr_not_only_op;
+ spin_lock(&client_lock);
+ cstate->session = find_in_sessionid_hashtbl(&bcts->sessionid);
+ /* Sorta weird: we only need the refcnt'ing because new_conn acquires
+ * client_lock iself: */
+ if (cstate->session) {
+ nfsd4_get_session(cstate->session);
+ atomic_inc(&cstate->session->se_client->cl_refcount);
+ }
+ spin_unlock(&client_lock);
+ if (!cstate->session)
+ return nfserr_badsession;
+
+ status = nfsd4_map_bcts_dir(&bcts->dir);
+ nfsd4_new_conn(rqstp, cstate->session, bcts->dir);
+ return nfs_ok;
+}
+
static bool nfsd4_compound_in_session(struct nfsd4_session *session, struct nfs4_sessionid *sid)
{
if (!session)
@@ -1619,8 +1687,7 @@ nfsd4_destroy_session(struct svc_rqst *r,
spin_unlock(&client_lock);
nfs4_lock_state();
- /* wait for callbacks */
- nfsd4_shutdown_callback(ses->se_client);
+ nfsd4_probe_callback_sync(ses->se_client);
nfs4_unlock_state();
nfsd4_del_conns(ses);
@@ -1733,8 +1800,12 @@ nfsd4_sequence(struct svc_rqst *rqstp,
out:
/* Hold a session reference until done processing the compound. */
if (cstate->session) {
+ struct nfs4_client *clp = session->se_client;
+
nfsd4_get_session(cstate->session);
- atomic_inc(&session->se_client->cl_refcount);
+ atomic_inc(&clp->cl_refcount);
+ if (clp->cl_cb_state == NFSD4_CB_DOWN)
+ seq->status_flags |= SEQ4_STATUS_CB_PATH_DOWN;
}
kfree(conn);
spin_unlock(&client_lock);
@@ -1775,7 +1846,6 @@ __be32
nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
struct nfsd4_setclientid *setclid)
{
- struct sockaddr *sa = svc_addr(rqstp);
struct xdr_netobj clname = {
.len = setclid->se_namelen,
.data = setclid->se_name,
@@ -1801,10 +1871,12 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
strhashval = clientstr_hashval(dname);
nfs4_lock_state();
- conf = find_confirmed_client_by_str(dname, strhashval, false);
+ conf = find_confirmed_client_by_str(dname, strhashval);
if (conf) {
/* RFC 3530 14.2.33 CASE 0: */
status = nfserr_clid_inuse;
+ if (clp_used_exchangeid(conf))
+ goto out;
if (!same_creds(&conf->cl_cred, &rqstp->rq_cred)) {
char addr_str[INET6_ADDRSTRLEN];
rpc_ntop((struct sockaddr *) &conf->cl_addr, addr_str,
@@ -1819,7 +1891,7 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
* has a description of SETCLIENTID request processing consisting
* of 5 bullet points, labeled as CASE0 - CASE4 below.
*/
- unconf = find_unconfirmed_client_by_str(dname, strhashval, false);
+ unconf = find_unconfirmed_client_by_str(dname, strhashval);
status = nfserr_resource;
if (!conf) {
/*
@@ -1876,7 +1948,7 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
* for consistent minorversion use throughout:
*/
new->cl_minorversion = 0;
- gen_callback(new, setclid, rpc_get_scope_id(sa));
+ gen_callback(new, setclid, rqstp);
add_to_unconfirmed(new, strhashval);
setclid->se_clientid.cl_boot = new->cl_clientid.cl_boot;
setclid->se_clientid.cl_id = new->cl_clientid.cl_id;
@@ -1935,7 +2007,6 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp,
if (!same_creds(&conf->cl_cred, &unconf->cl_cred))
status = nfserr_clid_inuse;
else {
- atomic_set(&conf->cl_cb_set, 0);
nfsd4_change_callback(conf, &unconf->cl_cb_conn);
nfsd4_probe_callback(conf);
expire_client(unconf);
@@ -1964,7 +2035,7 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp,
unsigned int hash =
clientstr_hashval(unconf->cl_recdir);
conf = find_confirmed_client_by_str(unconf->cl_recdir,
- hash, false);
+ hash);
if (conf) {
nfsd4_remove_clid_dir(conf);
expire_client(conf);
@@ -2300,41 +2371,6 @@ void nfsd_break_deleg_cb(struct file_lock *fl)
nfsd4_cb_recall(dp);
}
-/*
- * The file_lock is being reapd.
- *
- * Called by locks_free_lock() with lock_flocks() held.
- */
-static
-void nfsd_release_deleg_cb(struct file_lock *fl)
-{
- struct nfs4_delegation *dp = (struct nfs4_delegation *)fl->fl_owner;
-
- dprintk("NFSD nfsd_release_deleg_cb: fl %p dp %p dl_count %d\n", fl,dp, atomic_read(&dp->dl_count));
-
- if (!(fl->fl_flags & FL_LEASE) || !dp)
- return;
- dp->dl_flock = NULL;
-}
-
-/*
- * Called from setlease() with lock_flocks() held
- */
-static
-int nfsd_same_client_deleg_cb(struct file_lock *onlist, struct file_lock *try)
-{
- struct nfs4_delegation *onlistd =
- (struct nfs4_delegation *)onlist->fl_owner;
- struct nfs4_delegation *tryd =
- (struct nfs4_delegation *)try->fl_owner;
-
- if (onlist->fl_lmops != try->fl_lmops)
- return 0;
-
- return onlistd->dl_client == tryd->dl_client;
-}
-
-
static
int nfsd_change_deleg_cb(struct file_lock **onlist, int arg)
{
@@ -2346,8 +2382,6 @@ int nfsd_change_deleg_cb(struct file_lock **onlist, int arg)
static const struct lock_manager_operations nfsd_lease_mng_ops = {
.fl_break = nfsd_break_deleg_cb,
- .fl_release_private = nfsd_release_deleg_cb,
- .fl_mylease = nfsd_same_client_deleg_cb,
.fl_change = nfsd_change_deleg_cb,
};
@@ -2514,8 +2548,6 @@ static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct nfs4_file
if (!fp->fi_fds[oflag]) {
status = nfsd_open(rqstp, cur_fh, S_IFREG, access,
&fp->fi_fds[oflag]);
- if (status == nfserr_dropit)
- status = nfserr_jukebox;
if (status)
return status;
}
@@ -2596,6 +2628,19 @@ nfs4_set_claim_prev(struct nfsd4_open *open)
open->op_stateowner->so_client->cl_firststate = 1;
}
+/* Should we give out recallable state?: */
+static bool nfsd4_cb_channel_good(struct nfs4_client *clp)
+{
+ if (clp->cl_cb_state == NFSD4_CB_UP)
+ return true;
+ /*
+ * In the sessions case, since we don't have to establish a
+ * separate connection for callbacks, we assume it's OK
+ * until we hear otherwise:
+ */
+ return clp->cl_minorversion && clp->cl_cb_state == NFSD4_CB_UNKNOWN;
+}
+
/*
* Attempt to hand out a delegation.
*/
@@ -2604,10 +2649,11 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_sta
{
struct nfs4_delegation *dp;
struct nfs4_stateowner *sop = stp->st_stateowner;
- int cb_up = atomic_read(&sop->so_client->cl_cb_set);
+ int cb_up;
struct file_lock *fl;
int status, flag = 0;
+ cb_up = nfsd4_cb_channel_good(sop->so_client);
flag = NFS4_OPEN_DELEGATE_NONE;
open->op_recall = 0;
switch (open->op_claim_type) {
@@ -2655,7 +2701,7 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_sta
dp->dl_flock = fl;
/* vfs_setlease checks to see if delegation should be handed out.
- * the lock_manager callbacks fl_mylease and fl_change are used
+ * the lock_manager callback fl_change is used
*/
if ((status = vfs_setlease(fl->fl_file, fl->fl_type, &fl))) {
dprintk("NFSD: setlease failed [%d], no delegation\n", status);
@@ -2794,7 +2840,7 @@ nfsd4_renew(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
renew_client(clp);
status = nfserr_cb_path_down;
if (!list_empty(&clp->cl_delegations)
- && !atomic_read(&clp->cl_cb_set))
+ && clp->cl_cb_state != NFSD4_CB_UP)
goto out;
status = nfs_ok;
out:
@@ -3081,9 +3127,10 @@ nfs4_preprocess_stateid_op(struct nfsd4_compound_state *cstate,
if (status)
goto out;
renew_client(dp->dl_client);
- if (filpp)
+ if (filpp) {
*filpp = find_readable_file(dp->dl_file);
- BUG_ON(!*filpp);
+ BUG_ON(!*filpp);
+ }
} else { /* open or lock stateid */
stp = find_stateid(stateid, flags);
if (!stp)
@@ -4107,7 +4154,7 @@ nfs4_has_reclaimed_state(const char *name, bool use_exchange_id)
unsigned int strhashval = clientstr_hashval(name);
struct nfs4_client *clp;
- clp = find_confirmed_client_by_str(name, strhashval, use_exchange_id);
+ clp = find_confirmed_client_by_str(name, strhashval);
return clp ? 1 : 0;
}
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index f35a94a..956629b 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -44,13 +44,14 @@
#include <linux/namei.h>
#include <linux/statfs.h>
#include <linux/utsname.h>
-#include <linux/nfsd_idmap.h>
-#include <linux/nfs4_acl.h>
#include <linux/sunrpc/svcauth_gss.h>
+#include "idmap.h"
+#include "acl.h"
#include "xdr4.h"
#include "vfs.h"
+
#define NFSDDBG_FACILITY NFSDDBG_XDR
/*
@@ -288,17 +289,17 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval,
len += XDR_QUADLEN(dummy32) << 2;
READMEM(buf, dummy32);
ace->whotype = nfs4_acl_get_whotype(buf, dummy32);
- host_err = 0;
+ status = nfs_ok;
if (ace->whotype != NFS4_ACL_WHO_NAMED)
ace->who = 0;
else if (ace->flag & NFS4_ACE_IDENTIFIER_GROUP)
- host_err = nfsd_map_name_to_gid(argp->rqstp,
+ status = nfsd_map_name_to_gid(argp->rqstp,
buf, dummy32, &ace->who);
else
- host_err = nfsd_map_name_to_uid(argp->rqstp,
+ status = nfsd_map_name_to_uid(argp->rqstp,
buf, dummy32, &ace->who);
- if (host_err)
- goto out_nfserr;
+ if (status)
+ return status;
}
} else
*acl = NULL;
@@ -420,6 +421,21 @@ nfsd4_decode_access(struct nfsd4_compoundargs *argp, struct nfsd4_access *access
DECODE_TAIL;
}
+static __be32 nfsd4_decode_bind_conn_to_session(struct nfsd4_compoundargs *argp, struct nfsd4_bind_conn_to_session *bcts)
+{
+ DECODE_HEAD;
+ u32 dummy;
+
+ READ_BUF(NFS4_MAX_SESSIONID_LEN + 8);
+ COPYMEM(bcts->sessionid.data, NFS4_MAX_SESSIONID_LEN);
+ READ32(bcts->dir);
+ /* XXX: Perhaps Tom Tucker could help us figure out how we
+ * should be using ctsa_use_conn_in_rdma_mode: */
+ READ32(dummy);
+
+ DECODE_TAIL;
+}
+
static __be32
nfsd4_decode_close(struct nfsd4_compoundargs *argp, struct nfsd4_close *close)
{
@@ -847,6 +863,17 @@ nfsd4_decode_secinfo(struct nfsd4_compoundargs *argp,
}
static __be32
+nfsd4_decode_secinfo_no_name(struct nfsd4_compoundargs *argp,
+ struct nfsd4_secinfo_no_name *sin)
+{
+ DECODE_HEAD;
+
+ READ_BUF(4);
+ READ32(sin->sin_style);
+ DECODE_TAIL;
+}
+
+static __be32
nfsd4_decode_setattr(struct nfsd4_compoundargs *argp, struct nfsd4_setattr *setattr)
{
__be32 status;
@@ -1005,7 +1032,7 @@ static __be32
nfsd4_decode_exchange_id(struct nfsd4_compoundargs *argp,
struct nfsd4_exchange_id *exid)
{
- int dummy;
+ int dummy, tmp;
DECODE_HEAD;
READ_BUF(NFS4_VERIFIER_SIZE);
@@ -1053,15 +1080,23 @@ nfsd4_decode_exchange_id(struct nfsd4_compoundargs *argp,
/* ssp_hash_algs<> */
READ_BUF(4);
- READ32(dummy);
- READ_BUF(dummy);
- p += XDR_QUADLEN(dummy);
+ READ32(tmp);
+ while (tmp--) {
+ READ_BUF(4);
+ READ32(dummy);
+ READ_BUF(dummy);
+ p += XDR_QUADLEN(dummy);
+ }
/* ssp_encr_algs<> */
READ_BUF(4);
- READ32(dummy);
- READ_BUF(dummy);
- p += XDR_QUADLEN(dummy);
+ READ32(tmp);
+ while (tmp--) {
+ READ_BUF(4);
+ READ32(dummy);
+ READ_BUF(dummy);
+ p += XDR_QUADLEN(dummy);
+ }
/* ssp_window and ssp_num_gss_handles */
READ_BUF(8);
@@ -1339,7 +1374,7 @@ static nfsd4_dec nfsd41_dec_ops[] = {
/* new operations for NFSv4.1 */
[OP_BACKCHANNEL_CTL] = (nfsd4_dec)nfsd4_decode_notsupp,
- [OP_BIND_CONN_TO_SESSION]= (nfsd4_dec)nfsd4_decode_notsupp,
+ [OP_BIND_CONN_TO_SESSION]= (nfsd4_dec)nfsd4_decode_bind_conn_to_session,
[OP_EXCHANGE_ID] = (nfsd4_dec)nfsd4_decode_exchange_id,
[OP_CREATE_SESSION] = (nfsd4_dec)nfsd4_decode_create_session,
[OP_DESTROY_SESSION] = (nfsd4_dec)nfsd4_decode_destroy_session,
@@ -1350,7 +1385,7 @@ static nfsd4_dec nfsd41_dec_ops[] = {
[OP_LAYOUTCOMMIT] = (nfsd4_dec)nfsd4_decode_notsupp,
[OP_LAYOUTGET] = (nfsd4_dec)nfsd4_decode_notsupp,
[OP_LAYOUTRETURN] = (nfsd4_dec)nfsd4_decode_notsupp,
- [OP_SECINFO_NO_NAME] = (nfsd4_dec)nfsd4_decode_notsupp,
+ [OP_SECINFO_NO_NAME] = (nfsd4_dec)nfsd4_decode_secinfo_no_name,
[OP_SEQUENCE] = (nfsd4_dec)nfsd4_decode_sequence,
[OP_SET_SSV] = (nfsd4_dec)nfsd4_decode_notsupp,
[OP_TEST_STATEID] = (nfsd4_dec)nfsd4_decode_notsupp,
@@ -2309,8 +2344,6 @@ nfsd4_encode_dirent(void *ccdv, const char *name, int namlen,
case nfserr_resource:
nfserr = nfserr_toosmall;
goto fail;
- case nfserr_dropit:
- goto fail;
case nfserr_noent:
goto skip_entry;
default:
@@ -2365,6 +2398,21 @@ nfsd4_encode_access(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_
return nfserr;
}
+static __be32 nfsd4_encode_bind_conn_to_session(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_bind_conn_to_session *bcts)
+{
+ __be32 *p;
+
+ if (!nfserr) {
+ RESERVE_SPACE(NFS4_MAX_SESSIONID_LEN + 8);
+ WRITEMEM(bcts->sessionid.data, NFS4_MAX_SESSIONID_LEN);
+ WRITE32(bcts->dir);
+ /* XXX: ? */
+ WRITE32(0);
+ ADJUST_ARGS();
+ }
+ return nfserr;
+}
+
static __be32
nfsd4_encode_close(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_close *close)
{
@@ -2826,11 +2874,10 @@ nfsd4_encode_rename(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_
}
static __be32
-nfsd4_encode_secinfo(struct nfsd4_compoundres *resp, __be32 nfserr,
- struct nfsd4_secinfo *secinfo)
+nfsd4_do_encode_secinfo(struct nfsd4_compoundres *resp,
+ __be32 nfserr,struct svc_export *exp)
{
int i = 0;
- struct svc_export *exp = secinfo->si_exp;
u32 nflavs;
struct exp_flavor_info *flavs;
struct exp_flavor_info def_flavs[2];
@@ -2892,6 +2939,20 @@ out:
return nfserr;
}
+static __be32
+nfsd4_encode_secinfo(struct nfsd4_compoundres *resp, __be32 nfserr,
+ struct nfsd4_secinfo *secinfo)
+{
+ return nfsd4_do_encode_secinfo(resp, nfserr, secinfo->si_exp);
+}
+
+static __be32
+nfsd4_encode_secinfo_no_name(struct nfsd4_compoundres *resp, __be32 nfserr,
+ struct nfsd4_secinfo_no_name *secinfo)
+{
+ return nfsd4_do_encode_secinfo(resp, nfserr, secinfo->sin_exp);
+}
+
/*
* The SETATTR encode routine is special -- it always encodes a bitmap,
* regardless of the error status.
@@ -3076,13 +3137,9 @@ nfsd4_encode_sequence(struct nfsd4_compoundres *resp, int nfserr,
WRITE32(seq->seqid);
WRITE32(seq->slotid);
WRITE32(seq->maxslots);
- /*
- * FIXME: for now:
- * target_maxslots = maxslots
- * status_flags = 0
- */
+ /* For now: target_maxslots = maxslots */
WRITE32(seq->maxslots);
- WRITE32(0);
+ WRITE32(seq->status_flags);
ADJUST_ARGS();
resp->cstate.datap = p; /* DRC cache data pointer */
@@ -3143,7 +3200,7 @@ static nfsd4_enc nfsd4_enc_ops[] = {
/* NFSv4.1 operations */
[OP_BACKCHANNEL_CTL] = (nfsd4_enc)nfsd4_encode_noop,
- [OP_BIND_CONN_TO_SESSION] = (nfsd4_enc)nfsd4_encode_noop,
+ [OP_BIND_CONN_TO_SESSION] = (nfsd4_enc)nfsd4_encode_bind_conn_to_session,
[OP_EXCHANGE_ID] = (nfsd4_enc)nfsd4_encode_exchange_id,
[OP_CREATE_SESSION] = (nfsd4_enc)nfsd4_encode_create_session,
[OP_DESTROY_SESSION] = (nfsd4_enc)nfsd4_encode_destroy_session,
@@ -3154,7 +3211,7 @@ static nfsd4_enc nfsd4_enc_ops[] = {
[OP_LAYOUTCOMMIT] = (nfsd4_enc)nfsd4_encode_noop,
[OP_LAYOUTGET] = (nfsd4_enc)nfsd4_encode_noop,
[OP_LAYOUTRETURN] = (nfsd4_enc)nfsd4_encode_noop,
- [OP_SECINFO_NO_NAME] = (nfsd4_enc)nfsd4_encode_noop,
+ [OP_SECINFO_NO_NAME] = (nfsd4_enc)nfsd4_encode_secinfo_no_name,
[OP_SEQUENCE] = (nfsd4_enc)nfsd4_encode_sequence,
[OP_SET_SSV] = (nfsd4_enc)nfsd4_encode_noop,
[OP_TEST_STATEID] = (nfsd4_enc)nfsd4_encode_noop,
diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c
index 4514ebb..33b3e2b 100644
--- a/fs/nfsd/nfsctl.c
+++ b/fs/nfsd/nfsctl.c
@@ -8,12 +8,12 @@
#include <linux/namei.h>
#include <linux/ctype.h>
-#include <linux/nfsd_idmap.h>
#include <linux/sunrpc/svcsock.h>
#include <linux/nfsd/syscall.h>
#include <linux/lockd/lockd.h>
#include <linux/sunrpc/clnt.h>
+#include "idmap.h"
#include "nfsd.h"
#include "cache.h"
@@ -127,6 +127,7 @@ static ssize_t nfsctl_transaction_write(struct file *file, const char __user *bu
static ssize_t nfsctl_transaction_read(struct file *file, char __user *buf, size_t size, loff_t *pos)
{
+#ifdef CONFIG_NFSD_DEPRECATED
static int warned;
if (file->f_dentry->d_name.name[0] == '.' && !warned) {
printk(KERN_INFO
@@ -135,6 +136,7 @@ static ssize_t nfsctl_transaction_read(struct file *file, char __user *buf, size
current->comm, file->f_dentry->d_name.name);
warned = 1;
}
+#endif
if (! file->private_data) {
/* An attempt to read a transaction file without writing
* causes a 0-byte write so that the file can return
diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h
index 6b641cf..7ecfa24 100644
--- a/fs/nfsd/nfsd.h
+++ b/fs/nfsd/nfsd.h
@@ -158,6 +158,7 @@ void nfsd_lockd_shutdown(void);
#define nfserr_attrnotsupp cpu_to_be32(NFSERR_ATTRNOTSUPP)
#define nfserr_bad_xdr cpu_to_be32(NFSERR_BAD_XDR)
#define nfserr_openmode cpu_to_be32(NFSERR_OPENMODE)
+#define nfserr_badowner cpu_to_be32(NFSERR_BADOWNER)
#define nfserr_locks_held cpu_to_be32(NFSERR_LOCKS_HELD)
#define nfserr_op_illegal cpu_to_be32(NFSERR_OP_ILLEGAL)
#define nfserr_grace cpu_to_be32(NFSERR_GRACE)
diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c
index 08e1726..e15dc45 100644
--- a/fs/nfsd/nfsproc.c
+++ b/fs/nfsd/nfsproc.c
@@ -735,9 +735,9 @@ nfserrno (int errno)
{ nfserr_stale, -ESTALE },
{ nfserr_jukebox, -ETIMEDOUT },
{ nfserr_jukebox, -ERESTARTSYS },
- { nfserr_dropit, -EAGAIN },
- { nfserr_dropit, -ENOMEM },
- { nfserr_badname, -ESRCH },
+ { nfserr_jukebox, -EAGAIN },
+ { nfserr_jukebox, -EWOULDBLOCK },
+ { nfserr_jukebox, -ENOMEM },
{ nfserr_io, -ETXTBSY },
{ nfserr_notsupp, -EOPNOTSUPP },
{ nfserr_toosmall, -ETOOSMALL },
diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c
index 2bae1d8..18743c4 100644
--- a/fs/nfsd/nfssvc.c
+++ b/fs/nfsd/nfssvc.c
@@ -608,7 +608,7 @@ nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp)
/* Now call the procedure handler, and encode NFS status. */
nfserr = proc->pc_func(rqstp, rqstp->rq_argp, rqstp->rq_resp);
nfserr = map_new_errors(rqstp->rq_vers, nfserr);
- if (nfserr == nfserr_dropit) {
+ if (nfserr == nfserr_dropit || rqstp->rq_dropme) {
dprintk("nfsd: Dropping request; may be revisited later\n");
nfsd_cache_update(rqstp, RC_NOCACHE, NULL);
return 0;
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index 39adc27..3074656 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -68,10 +68,12 @@ typedef struct {
struct nfsd4_callback {
void *cb_op;
struct nfs4_client *cb_clp;
+ struct list_head cb_per_client;
u32 cb_minorversion;
struct rpc_message cb_msg;
const struct rpc_call_ops *cb_ops;
struct work_struct cb_work;
+ bool cb_done;
};
struct nfs4_delegation {
@@ -81,6 +83,7 @@ struct nfs4_delegation {
atomic_t dl_count; /* ref count */
struct nfs4_client *dl_client;
struct nfs4_file *dl_file;
+ struct file *dl_vfs_file;
struct file_lock *dl_flock;
u32 dl_type;
time_t dl_time;
@@ -95,6 +98,7 @@ struct nfs4_delegation {
struct nfs4_cb_conn {
/* SETCLIENTID info */
struct sockaddr_storage cb_addr;
+ struct sockaddr_storage cb_saddr;
size_t cb_addrlen;
u32 cb_prog; /* used only in 4.0 case;
per-session otherwise */
@@ -146,6 +150,11 @@ struct nfsd4_create_session {
u32 gid;
};
+struct nfsd4_bind_conn_to_session {
+ struct nfs4_sessionid sessionid;
+ u32 dir;
+};
+
/* The single slot clientid cache structure */
struct nfsd4_clid_slot {
u32 sl_seqid;
@@ -235,9 +244,13 @@ struct nfs4_client {
unsigned long cl_cb_flags;
struct rpc_clnt *cl_cb_client;
u32 cl_cb_ident;
- atomic_t cl_cb_set;
+#define NFSD4_CB_UP 0
+#define NFSD4_CB_UNKNOWN 1
+#define NFSD4_CB_DOWN 2
+ int cl_cb_state;
struct nfsd4_callback cl_cb_null;
struct nfsd4_session *cl_cb_session;
+ struct list_head cl_callbacks; /* list of in-progress callbacks */
/* for all client information that callback code might need: */
spinlock_t cl_lock;
@@ -454,6 +467,7 @@ extern __be32 nfs4_check_open_reclaim(clientid_t *clid);
extern void nfs4_free_stateowner(struct kref *kref);
extern int set_callback_cred(void);
extern void nfsd4_probe_callback(struct nfs4_client *clp);
+extern void nfsd4_probe_callback_sync(struct nfs4_client *clp);
extern void nfsd4_change_callback(struct nfs4_client *clp, struct nfs4_cb_conn *);
extern void nfsd4_do_callback_rpc(struct work_struct *);
extern void nfsd4_cb_recall(struct nfs4_delegation *dp);
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index 230b79f..641117f 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -1,4 +1,3 @@
-#define MSNFS /* HACK HACK */
/*
* File operations used by nfsd. Some of these have been ripped from
* other parts of the kernel because they weren't exported, others
@@ -35,8 +34,8 @@
#endif /* CONFIG_NFSD_V3 */
#ifdef CONFIG_NFSD_V4
-#include <linux/nfs4_acl.h>
-#include <linux/nfsd_idmap.h>
+#include "acl.h"
+#include "idmap.h"
#endif /* CONFIG_NFSD_V4 */
#include "nfsd.h"
@@ -88,8 +87,9 @@ nfsd_cross_mnt(struct svc_rqst *rqstp, struct dentry **dpp,
.dentry = dget(dentry)};
int err = 0;
- while (d_mountpoint(path.dentry) && follow_down(&path))
- ;
+ err = follow_down(&path, false);
+ if (err < 0)
+ goto out;
exp2 = rqst_exp_get_by_name(rqstp, &path);
if (IS_ERR(exp2)) {
@@ -273,6 +273,13 @@ out:
return err;
}
+static int nfsd_break_lease(struct inode *inode)
+{
+ if (!S_ISREG(inode->i_mode))
+ return 0;
+ return break_lease(inode, O_WRONLY | O_NONBLOCK);
+}
+
/*
* Commit metadata changes to stable storage.
*/
@@ -375,16 +382,6 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap,
goto out;
}
- /*
- * If we are changing the size of the file, then
- * we need to break all leases.
- */
- host_err = break_lease(inode, O_WRONLY | O_NONBLOCK);
- if (host_err == -EWOULDBLOCK)
- host_err = -ETIMEDOUT;
- if (host_err) /* ENOMEM or EWOULDBLOCK */
- goto out_nfserr;
-
host_err = get_write_access(inode);
if (host_err)
goto out_nfserr;
@@ -425,7 +422,11 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap,
err = nfserr_notsync;
if (!check_guard || guardtime == inode->i_ctime.tv_sec) {
+ host_err = nfsd_break_lease(inode);
+ if (host_err)
+ goto out_nfserr;
fh_lock(fhp);
+
host_err = notify_change(dentry, iap);
err = nfserrno(host_err);
fh_unlock(fhp);
@@ -752,8 +753,6 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
*/
if (!(access & NFSD_MAY_NOT_BREAK_LEASE))
host_err = break_lease(inode, O_NONBLOCK | ((access & NFSD_MAY_WRITE) ? O_WRONLY : 0));
- if (host_err == -EWOULDBLOCK)
- host_err = -ETIMEDOUT;
if (host_err) /* NOMEM or WOULDBLOCK */
goto out_nfserr;
@@ -874,15 +873,6 @@ static int nfsd_direct_splice_actor(struct pipe_inode_info *pipe,
return __splice_from_pipe(pipe, sd, nfsd_splice_actor);
}
-static inline int svc_msnfs(struct svc_fh *ffhp)
-{
-#ifdef MSNFS
- return (ffhp->fh_export->ex_flags & NFSEXP_MSNFS);
-#else
- return 0;
-#endif
-}
-
static __be32
nfsd_vfs_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
loff_t offset, struct kvec *vec, int vlen, unsigned long *count)
@@ -895,9 +885,6 @@ nfsd_vfs_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
err = nfserr_perm;
inode = file->f_path.dentry->d_inode;
- if (svc_msnfs(fhp) && !lock_may_read(inode, offset, *count))
- goto out;
-
if (file->f_op->splice_read && rqstp->rq_splice_ok) {
struct splice_desc sd = {
.len = 0,
@@ -922,7 +909,6 @@ nfsd_vfs_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
fsnotify_access(file);
} else
err = nfserrno(host_err);
-out:
return err;
}
@@ -987,14 +973,6 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
int stable = *stablep;
int use_wgather;
-#ifdef MSNFS
- err = nfserr_perm;
-
- if ((fhp->fh_export->ex_flags & NFSEXP_MSNFS) &&
- (!lock_may_write(file->f_path.dentry->d_inode, offset, *cnt)))
- goto out;
-#endif
-
dentry = file->f_path.dentry;
inode = dentry->d_inode;
exp = fhp->fh_export;
@@ -1045,7 +1023,6 @@ out_nfserr:
err = 0;
else
err = nfserrno(host_err);
-out:
return err;
}
@@ -1665,6 +1642,12 @@ nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp,
err = nfserrno(host_err);
goto out_dput;
}
+ err = nfserr_noent;
+ if (!dold->d_inode)
+ goto out_drop_write;
+ host_err = nfsd_break_lease(dold->d_inode);
+ if (host_err)
+ goto out_drop_write;
host_err = vfs_link(dold, dirp, dnew);
if (!host_err) {
err = nfserrno(commit_metadata(ffhp));
@@ -1676,6 +1659,7 @@ nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp,
else
err = nfserrno(host_err);
}
+out_drop_write:
mnt_drop_write(tfhp->fh_export->ex_path.mnt);
out_dput:
dput(dnew);
@@ -1750,12 +1734,6 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen,
if (ndentry == trap)
goto out_dput_new;
- if (svc_msnfs(ffhp) &&
- ((odentry->d_count > 1) || (ndentry->d_count > 1))) {
- host_err = -EPERM;
- goto out_dput_new;
- }
-
host_err = -EXDEV;
if (ffhp->fh_export->ex_path.mnt != tfhp->fh_export->ex_path.mnt)
goto out_dput_new;
@@ -1763,15 +1741,17 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen,
if (host_err)
goto out_dput_new;
+ host_err = nfsd_break_lease(odentry->d_inode);
+ if (host_err)
+ goto out_drop_write;
host_err = vfs_rename(fdir, odentry, tdir, ndentry);
if (!host_err) {
host_err = commit_metadata(tfhp);
if (!host_err)
host_err = commit_metadata(ffhp);
}
-
+out_drop_write:
mnt_drop_write(ffhp->fh_export->ex_path.mnt);
-
out_dput_new:
dput(ndentry);
out_dput_old:
@@ -1834,18 +1814,14 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
if (host_err)
goto out_nfserr;
- if (type != S_IFDIR) { /* It's UNLINK */
-#ifdef MSNFS
- if ((fhp->fh_export->ex_flags & NFSEXP_MSNFS) &&
- (rdentry->d_count > 1)) {
- host_err = -EPERM;
- } else
-#endif
+ host_err = nfsd_break_lease(rdentry->d_inode);
+ if (host_err)
+ goto out_put;
+ if (type != S_IFDIR)
host_err = vfs_unlink(dirp, rdentry);
- } else { /* It's RMDIR */
+ else
host_err = vfs_rmdir(dirp, rdentry);
- }
-
+out_put:
dput(rdentry);
if (!host_err)
diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h
index 60fce3d..366401e 100644
--- a/fs/nfsd/xdr4.h
+++ b/fs/nfsd/xdr4.h
@@ -311,6 +311,11 @@ struct nfsd4_secinfo {
struct svc_export *si_exp; /* response */
};
+struct nfsd4_secinfo_no_name {
+ u32 sin_style; /* request */
+ struct svc_export *sin_exp; /* response */
+};
+
struct nfsd4_setattr {
stateid_t sa_stateid; /* request */
u32 sa_bmval[3]; /* request */
@@ -373,8 +378,8 @@ struct nfsd4_sequence {
u32 cachethis; /* request */
#if 0
u32 target_maxslots; /* response */
- u32 status_flags; /* response */
#endif /* not yet */
+ u32 status_flags; /* response */
};
struct nfsd4_destroy_session {
@@ -422,6 +427,7 @@ struct nfsd4_op {
/* NFSv4.1 */
struct nfsd4_exchange_id exchange_id;
+ struct nfsd4_bind_conn_to_session bind_conn_to_session;
struct nfsd4_create_session create_session;
struct nfsd4_destroy_session destroy_session;
struct nfsd4_sequence sequence;
@@ -518,6 +524,7 @@ extern __be32 nfsd4_replay_cache_entry(struct nfsd4_compoundres *resp,
struct nfsd4_sequence *seq);
extern __be32 nfsd4_exchange_id(struct svc_rqst *rqstp,
struct nfsd4_compound_state *, struct nfsd4_exchange_id *);
+extern __be32 nfsd4_bind_conn_to_session(struct svc_rqst *, struct nfsd4_compound_state *, struct nfsd4_bind_conn_to_session *);
extern __be32 nfsd4_create_session(struct svc_rqst *,
struct nfsd4_compound_state *,
struct nfsd4_create_session *);
diff --git a/fs/ocfs2/Kconfig b/fs/ocfs2/Kconfig
index ab152c0..77a8de5 100644
--- a/fs/ocfs2/Kconfig
+++ b/fs/ocfs2/Kconfig
@@ -1,7 +1,6 @@
config OCFS2_FS
tristate "OCFS2 file system support"
- depends on NET && SYSFS
- select CONFIGFS_FS
+ depends on NET && SYSFS && CONFIGFS_FS
select JBD2
select CRC32
select QUOTA
diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c
index 63e3fca..a665195 100644
--- a/fs/ocfs2/file.c
+++ b/fs/ocfs2/file.c
@@ -1989,20 +1989,20 @@ int ocfs2_change_file_space(struct file *file, unsigned int cmd,
return __ocfs2_change_file_space(file, inode, file->f_pos, cmd, sr, 0);
}
-static long ocfs2_fallocate(struct inode *inode, int mode, loff_t offset,
+static long ocfs2_fallocate(struct file *file, int mode, loff_t offset,
loff_t len)
{
+ struct inode *inode = file->f_path.dentry->d_inode;
struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
struct ocfs2_space_resv sr;
int change_size = 1;
int cmd = OCFS2_IOC_RESVSP64;
+ if (mode & ~(FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE))
+ return -EOPNOTSUPP;
if (!ocfs2_writes_unwritten_extents(osb))
return -EOPNOTSUPP;
- if (S_ISDIR(inode->i_mode))
- return -ENODEV;
-
if (mode & FALLOC_FL_KEEP_SIZE)
change_size = 0;
@@ -2610,7 +2610,6 @@ const struct inode_operations ocfs2_file_iops = {
.getxattr = generic_getxattr,
.listxattr = ocfs2_listxattr,
.removexattr = generic_removexattr,
- .fallocate = ocfs2_fallocate,
.fiemap = ocfs2_fiemap,
};
@@ -2642,6 +2641,7 @@ const struct file_operations ocfs2_fops = {
.flock = ocfs2_flock,
.splice_read = ocfs2_file_splice_read,
.splice_write = ocfs2_file_splice_write,
+ .fallocate = ocfs2_fallocate,
};
const struct file_operations ocfs2_dops = {
diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c
index 06d1f74..38f986d 100644
--- a/fs/ocfs2/super.c
+++ b/fs/ocfs2/super.c
@@ -993,8 +993,7 @@ static void ocfs2_disable_quotas(struct ocfs2_super *osb)
}
/* Handle quota on quotactl */
-static int ocfs2_quota_on(struct super_block *sb, int type, int format_id,
- char *path)
+static int ocfs2_quota_on(struct super_block *sb, int type, int format_id)
{
unsigned int feature[MAXQUOTAS] = { OCFS2_FEATURE_RO_COMPAT_USRQUOTA,
OCFS2_FEATURE_RO_COMPAT_GRPQUOTA};
@@ -1013,7 +1012,7 @@ static int ocfs2_quota_off(struct super_block *sb, int type)
}
static const struct quotactl_ops ocfs2_quotactl_ops = {
- .quota_on = ocfs2_quota_on,
+ .quota_on_meta = ocfs2_quota_on,
.quota_off = ocfs2_quota_off,
.quota_sync = dquot_quota_sync,
.get_info = dquot_get_dqinfo,
diff --git a/fs/open.c b/fs/open.c
index 5b6ef7e..e52389e 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -255,10 +255,10 @@ int do_fallocate(struct file *file, int mode, loff_t offset, loff_t len)
if (((offset + len) > inode->i_sb->s_maxbytes) || ((offset + len) < 0))
return -EFBIG;
- if (!inode->i_op->fallocate)
+ if (!file->f_op->fallocate)
return -EOPNOTSUPP;
- return inode->i_op->fallocate(inode, mode, offset, len);
+ return file->f_op->fallocate(file, mode, offset, len);
}
SYSCALL_DEFINE(fallocate)(int fd, int mode, loff_t offset, loff_t len)
diff --git a/fs/pipe.c b/fs/pipe.c
index e2e95fb..da42f7d 100644
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -441,7 +441,7 @@ redo:
break;
}
if (do_wakeup) {
- wake_up_interruptible_sync_poll(&pipe->wait, POLLOUT);
+ wake_up_interruptible_sync_poll(&pipe->wait, POLLOUT | POLLWRNORM);
kill_fasync(&pipe->fasync_writers, SIGIO, POLL_OUT);
}
pipe_wait(pipe);
@@ -450,7 +450,7 @@ redo:
/* Signal writers asynchronously that there is more room. */
if (do_wakeup) {
- wake_up_interruptible_sync_poll(&pipe->wait, POLLOUT);
+ wake_up_interruptible_sync_poll(&pipe->wait, POLLOUT | POLLWRNORM);
kill_fasync(&pipe->fasync_writers, SIGIO, POLL_OUT);
}
if (ret > 0)
@@ -612,7 +612,7 @@ redo2:
break;
}
if (do_wakeup) {
- wake_up_interruptible_sync_poll(&pipe->wait, POLLIN);
+ wake_up_interruptible_sync_poll(&pipe->wait, POLLIN | POLLRDNORM);
kill_fasync(&pipe->fasync_readers, SIGIO, POLL_IN);
do_wakeup = 0;
}
@@ -623,7 +623,7 @@ redo2:
out:
mutex_unlock(&inode->i_mutex);
if (do_wakeup) {
- wake_up_interruptible_sync_poll(&pipe->wait, POLLIN);
+ wake_up_interruptible_sync_poll(&pipe->wait, POLLIN | POLLRDNORM);
kill_fasync(&pipe->fasync_readers, SIGIO, POLL_IN);
}
if (ret > 0)
@@ -715,7 +715,7 @@ pipe_release(struct inode *inode, int decr, int decw)
if (!pipe->readers && !pipe->writers) {
free_pipe_info(inode);
} else {
- wake_up_interruptible_sync_poll(&pipe->wait, POLLIN | POLLOUT);
+ wake_up_interruptible_sync_poll(&pipe->wait, POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM | POLLERR | POLLHUP);
kill_fasync(&pipe->fasync_readers, SIGIO, POLL_IN);
kill_fasync(&pipe->fasync_writers, SIGIO, POLL_OUT);
}
@@ -1292,7 +1292,7 @@ static int __init init_pipe_fs(void)
static void __exit exit_pipe_fs(void)
{
unregister_filesystem(&pipe_fs_type);
- mntput_long(pipe_mnt);
+ mntput(pipe_mnt);
}
fs_initcall(init_pipe_fs);
diff --git a/fs/proc/Kconfig b/fs/proc/Kconfig
index 6a00688..15af622 100644
--- a/fs/proc/Kconfig
+++ b/fs/proc/Kconfig
@@ -1,5 +1,5 @@
config PROC_FS
- bool "/proc file system support" if EMBEDDED
+ bool "/proc file system support" if EXPERT
default y
help
This is a virtual file system providing information about the status
@@ -40,7 +40,7 @@ config PROC_VMCORE
Exports the dump image of crashed kernel in ELF format.
config PROC_SYSCTL
- bool "Sysctl support (/proc/sys)" if EMBEDDED
+ bool "Sysctl support (/proc/sys)" if EXPERT
depends on PROC_FS
select SYSCTL
default y
@@ -61,7 +61,7 @@ config PROC_SYSCTL
config PROC_PAGE_MONITOR
default y
depends on PROC_FS && MMU
- bool "Enable /proc page monitoring" if EMBEDDED
+ bool "Enable /proc page monitoring" if EXPERT
help
Various /proc files exist to monitor process memory utilization:
/proc/pid/smaps, /proc/pid/clear_refs, /proc/pid/pagemap,
diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c
index 84becd3..a2a622e 100644
--- a/fs/quota/dquot.c
+++ b/fs/quota/dquot.c
@@ -2189,8 +2189,8 @@ int dquot_resume(struct super_block *sb, int type)
}
EXPORT_SYMBOL(dquot_resume);
-int dquot_quota_on_path(struct super_block *sb, int type, int format_id,
- struct path *path)
+int dquot_quota_on(struct super_block *sb, int type, int format_id,
+ struct path *path)
{
int error = security_quota_on(path->dentry);
if (error)
@@ -2204,20 +2204,6 @@ int dquot_quota_on_path(struct super_block *sb, int type, int format_id,
DQUOT_LIMITS_ENABLED);
return error;
}
-EXPORT_SYMBOL(dquot_quota_on_path);
-
-int dquot_quota_on(struct super_block *sb, int type, int format_id, char *name)
-{
- struct path path;
- int error;
-
- error = kern_path(name, LOOKUP_FOLLOW, &path);
- if (!error) {
- error = dquot_quota_on_path(sb, type, format_id, &path);
- path_put(&path);
- }
- return error;
-}
EXPORT_SYMBOL(dquot_quota_on);
/*
diff --git a/fs/quota/quota.c b/fs/quota/quota.c
index b299961..b34bdb2 100644
--- a/fs/quota/quota.c
+++ b/fs/quota/quota.c
@@ -64,18 +64,15 @@ static int quota_sync_all(int type)
}
static int quota_quotaon(struct super_block *sb, int type, int cmd, qid_t id,
- void __user *addr)
+ struct path *path)
{
- char *pathname;
- int ret = -ENOSYS;
-
- pathname = getname(addr);
- if (IS_ERR(pathname))
- return PTR_ERR(pathname);
- if (sb->s_qcop->quota_on)
- ret = sb->s_qcop->quota_on(sb, type, id, pathname);
- putname(pathname);
- return ret;
+ if (!sb->s_qcop->quota_on && !sb->s_qcop->quota_on_meta)
+ return -ENOSYS;
+ if (sb->s_qcop->quota_on_meta)
+ return sb->s_qcop->quota_on_meta(sb, type, id);
+ if (IS_ERR(path))
+ return PTR_ERR(path);
+ return sb->s_qcop->quota_on(sb, type, id, path);
}
static int quota_getfmt(struct super_block *sb, int type, void __user *addr)
@@ -241,7 +238,7 @@ static int quota_getxquota(struct super_block *sb, int type, qid_t id,
/* Copy parameters and call proper function */
static int do_quotactl(struct super_block *sb, int type, int cmd, qid_t id,
- void __user *addr)
+ void __user *addr, struct path *path)
{
int ret;
@@ -256,7 +253,7 @@ static int do_quotactl(struct super_block *sb, int type, int cmd, qid_t id,
switch (cmd) {
case Q_QUOTAON:
- return quota_quotaon(sb, type, cmd, id, addr);
+ return quota_quotaon(sb, type, cmd, id, path);
case Q_QUOTAOFF:
if (!sb->s_qcop->quota_off)
return -ENOSYS;
@@ -335,6 +332,7 @@ SYSCALL_DEFINE4(quotactl, unsigned int, cmd, const char __user *, special,
{
uint cmds, type;
struct super_block *sb = NULL;
+ struct path path, *pathp = NULL;
int ret;
cmds = cmd >> SUBCMDSHIFT;
@@ -351,12 +349,27 @@ SYSCALL_DEFINE4(quotactl, unsigned int, cmd, const char __user *, special,
return -ENODEV;
}
+ /*
+ * Path for quotaon has to be resolved before grabbing superblock
+ * because that gets s_umount sem which is also possibly needed by path
+ * resolution (think about autofs) and thus deadlocks could arise.
+ */
+ if (cmds == Q_QUOTAON) {
+ ret = user_path_at(AT_FDCWD, addr, LOOKUP_FOLLOW, &path);
+ if (ret)
+ pathp = ERR_PTR(ret);
+ else
+ pathp = &path;
+ }
+
sb = quotactl_block(special);
if (IS_ERR(sb))
return PTR_ERR(sb);
- ret = do_quotactl(sb, type, cmds, id, addr);
+ ret = do_quotactl(sb, type, cmds, id, addr, pathp);
drop_super(sb);
+ if (pathp && !IS_ERR(pathp))
+ path_put(pathp);
return ret;
}
diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c
index 2575682..0aab04f 100644
--- a/fs/reiserfs/super.c
+++ b/fs/reiserfs/super.c
@@ -632,7 +632,7 @@ static int reiserfs_acquire_dquot(struct dquot *);
static int reiserfs_release_dquot(struct dquot *);
static int reiserfs_mark_dquot_dirty(struct dquot *);
static int reiserfs_write_info(struct super_block *, int);
-static int reiserfs_quota_on(struct super_block *, int, int, char *);
+static int reiserfs_quota_on(struct super_block *, int, int, struct path *);
static const struct dquot_operations reiserfs_quota_operations = {
.write_dquot = reiserfs_write_dquot,
@@ -2048,25 +2048,21 @@ static int reiserfs_quota_on_mount(struct super_block *sb, int type)
* Standard function to be called on quota_on
*/
static int reiserfs_quota_on(struct super_block *sb, int type, int format_id,
- char *name)
+ struct path *path)
{
int err;
- struct path path;
struct inode *inode;
struct reiserfs_transaction_handle th;
if (!(REISERFS_SB(sb)->s_mount_opt & (1 << REISERFS_QUOTA)))
return -EINVAL;
- err = kern_path(name, LOOKUP_FOLLOW, &path);
- if (err)
- return err;
/* Quotafile not on the same filesystem? */
- if (path.mnt->mnt_sb != sb) {
+ if (path->mnt->mnt_sb != sb) {
err = -EXDEV;
goto out;
}
- inode = path.dentry->d_inode;
+ inode = path->dentry->d_inode;
/* We must not pack tails for quota files on reiserfs for quota IO to work */
if (!(REISERFS_I(inode)->i_flags & i_nopack_mask)) {
err = reiserfs_unpack(inode, NULL);
@@ -2082,7 +2078,7 @@ static int reiserfs_quota_on(struct super_block *sb, int type, int format_id,
/* Journaling quota? */
if (REISERFS_SB(sb)->s_qf_names[type]) {
/* Quotafile not of fs root? */
- if (path.dentry->d_parent != sb->s_root)
+ if (path->dentry->d_parent != sb->s_root)
reiserfs_warning(sb, "super-6521",
"Quota file not on filesystem root. "
"Journalled quota will not work.");
@@ -2101,9 +2097,8 @@ static int reiserfs_quota_on(struct super_block *sb, int type, int format_id,
if (err)
goto out;
}
- err = dquot_quota_on_path(sb, type, format_id, &path);
+ err = dquot_quota_on(sb, type, format_id, path);
out:
- path_put(&path);
return err;
}
diff --git a/fs/squashfs/Kconfig b/fs/squashfs/Kconfig
index e5f63da..aa68a8a 100644
--- a/fs/squashfs/Kconfig
+++ b/fs/squashfs/Kconfig
@@ -29,7 +29,6 @@ config SQUASHFS
config SQUASHFS_XATTR
bool "Squashfs XATTR support"
depends on SQUASHFS
- default n
help
Saying Y here includes support for extended attributes (xattrs).
Xattrs are name:value pairs associated with inodes by
@@ -40,7 +39,6 @@ config SQUASHFS_XATTR
config SQUASHFS_LZO
bool "Include support for LZO compressed file systems"
depends on SQUASHFS
- default n
select LZO_DECOMPRESS
help
Saying Y here includes support for reading Squashfs file systems
@@ -53,10 +51,24 @@ config SQUASHFS_LZO
If unsure, say N.
+config SQUASHFS_XZ
+ bool "Include support for XZ compressed file systems"
+ depends on SQUASHFS
+ select XZ_DEC
+ help
+ Saying Y here includes support for reading Squashfs file systems
+ compressed with XZ compresssion. XZ gives better compression than
+ the default zlib compression, at the expense of greater CPU and
+ memory overhead.
+
+ XZ is not the standard compression used in Squashfs and so most
+ file systems will be readable without selecting this option.
+
+ If unsure, say N.
+
config SQUASHFS_EMBEDDED
bool "Additional option for memory-constrained systems"
depends on SQUASHFS
- default n
help
Saying Y here allows you to specify cache size.
diff --git a/fs/squashfs/Makefile b/fs/squashfs/Makefile
index 7672bac..cecf2be 100644
--- a/fs/squashfs/Makefile
+++ b/fs/squashfs/Makefile
@@ -7,3 +7,4 @@ squashfs-y += block.o cache.o dir.o export.o file.o fragment.o id.o inode.o
squashfs-y += namei.o super.o symlink.o zlib_wrapper.o decompressor.o
squashfs-$(CONFIG_SQUASHFS_XATTR) += xattr.o xattr_id.o
squashfs-$(CONFIG_SQUASHFS_LZO) += lzo_wrapper.o
+squashfs-$(CONFIG_SQUASHFS_XZ) += xz_wrapper.o
diff --git a/fs/squashfs/block.c b/fs/squashfs/block.c
index 653c030..2fb2882 100644
--- a/fs/squashfs/block.c
+++ b/fs/squashfs/block.c
@@ -34,7 +34,6 @@
#include "squashfs_fs.h"
#include "squashfs_fs_sb.h"
-#include "squashfs_fs_i.h"
#include "squashfs.h"
#include "decompressor.h"
diff --git a/fs/squashfs/cache.c b/fs/squashfs/cache.c
index 57314be..26b15ae 100644
--- a/fs/squashfs/cache.c
+++ b/fs/squashfs/cache.c
@@ -55,7 +55,6 @@
#include "squashfs_fs.h"
#include "squashfs_fs_sb.h"
-#include "squashfs_fs_i.h"
#include "squashfs.h"
/*
diff --git a/fs/squashfs/decompressor.c b/fs/squashfs/decompressor.c
index 24af9ce..a5940e5 100644
--- a/fs/squashfs/decompressor.c
+++ b/fs/squashfs/decompressor.c
@@ -27,7 +27,6 @@
#include "squashfs_fs.h"
#include "squashfs_fs_sb.h"
-#include "squashfs_fs_i.h"
#include "decompressor.h"
#include "squashfs.h"
@@ -41,23 +40,26 @@ static const struct squashfs_decompressor squashfs_lzma_unsupported_comp_ops = {
};
#ifndef CONFIG_SQUASHFS_LZO
-static const struct squashfs_decompressor squashfs_lzo_unsupported_comp_ops = {
+static const struct squashfs_decompressor squashfs_lzo_comp_ops = {
NULL, NULL, NULL, LZO_COMPRESSION, "lzo", 0
};
#endif
+#ifndef CONFIG_SQUASHFS_XZ
+static const struct squashfs_decompressor squashfs_xz_comp_ops = {
+ NULL, NULL, NULL, XZ_COMPRESSION, "xz", 0
+};
+#endif
+
static const struct squashfs_decompressor squashfs_unknown_comp_ops = {
NULL, NULL, NULL, 0, "unknown", 0
};
static const struct squashfs_decompressor *decompressor[] = {
&squashfs_zlib_comp_ops,
- &squashfs_lzma_unsupported_comp_ops,
-#ifdef CONFIG_SQUASHFS_LZO
&squashfs_lzo_comp_ops,
-#else
- &squashfs_lzo_unsupported_comp_ops,
-#endif
+ &squashfs_xz_comp_ops,
+ &squashfs_lzma_unsupported_comp_ops,
&squashfs_unknown_comp_ops
};
diff --git a/fs/squashfs/decompressor.h b/fs/squashfs/decompressor.h
index 7425f80..3b305a7 100644
--- a/fs/squashfs/decompressor.h
+++ b/fs/squashfs/decompressor.h
@@ -52,4 +52,13 @@ static inline int squashfs_decompress(struct squashfs_sb_info *msblk,
return msblk->decompressor->decompress(msblk, buffer, bh, b, offset,
length, srclength, pages);
}
+
+#ifdef CONFIG_SQUASHFS_XZ
+extern const struct squashfs_decompressor squashfs_xz_comp_ops;
+#endif
+
+#ifdef CONFIG_SQUASHFS_LZO
+extern const struct squashfs_decompressor squashfs_lzo_comp_ops;
+#endif
+
#endif
diff --git a/fs/squashfs/fragment.c b/fs/squashfs/fragment.c
index 7c90bbd..7eef571 100644
--- a/fs/squashfs/fragment.c
+++ b/fs/squashfs/fragment.c
@@ -39,7 +39,6 @@
#include "squashfs_fs.h"
#include "squashfs_fs_sb.h"
-#include "squashfs_fs_i.h"
#include "squashfs.h"
/*
diff --git a/fs/squashfs/id.c b/fs/squashfs/id.c
index b7f64bc..d8f3245 100644
--- a/fs/squashfs/id.c
+++ b/fs/squashfs/id.c
@@ -37,7 +37,6 @@
#include "squashfs_fs.h"
#include "squashfs_fs_sb.h"
-#include "squashfs_fs_i.h"
#include "squashfs.h"
/*
diff --git a/fs/squashfs/lzo_wrapper.c b/fs/squashfs/lzo_wrapper.c
index 5d87789..7da759e 100644
--- a/fs/squashfs/lzo_wrapper.c
+++ b/fs/squashfs/lzo_wrapper.c
@@ -29,7 +29,6 @@
#include "squashfs_fs.h"
#include "squashfs_fs_sb.h"
-#include "squashfs_fs_i.h"
#include "squashfs.h"
#include "decompressor.h"
diff --git a/fs/squashfs/squashfs.h b/fs/squashfs/squashfs.h
index 5d45569..ba729d8 100644
--- a/fs/squashfs/squashfs.h
+++ b/fs/squashfs/squashfs.h
@@ -27,11 +27,6 @@
#define WARNING(s, args...) pr_warning("SQUASHFS: "s, ## args)
-static inline struct squashfs_inode_info *squashfs_i(struct inode *inode)
-{
- return list_entry(inode, struct squashfs_inode_info, vfs_inode);
-}
-
/* block.c */
extern int squashfs_read_data(struct super_block *, void **, u64, int, u64 *,
int, int);
@@ -104,6 +99,3 @@ extern const struct xattr_handler *squashfs_xattr_handlers[];
/* zlib_wrapper.c */
extern const struct squashfs_decompressor squashfs_zlib_comp_ops;
-
-/* lzo_wrapper.c */
-extern const struct squashfs_decompressor squashfs_lzo_comp_ops;
diff --git a/fs/squashfs/squashfs_fs.h b/fs/squashfs/squashfs_fs.h
index c5137fc..39533fe 100644
--- a/fs/squashfs/squashfs_fs.h
+++ b/fs/squashfs/squashfs_fs.h
@@ -238,6 +238,7 @@ struct meta_index {
#define ZLIB_COMPRESSION 1
#define LZMA_COMPRESSION 2
#define LZO_COMPRESSION 3
+#define XZ_COMPRESSION 4
struct squashfs_super_block {
__le32 s_magic;
diff --git a/fs/squashfs/squashfs_fs_i.h b/fs/squashfs/squashfs_fs_i.h
index d3e3a37..359baef 100644
--- a/fs/squashfs/squashfs_fs_i.h
+++ b/fs/squashfs/squashfs_fs_i.h
@@ -45,4 +45,10 @@ struct squashfs_inode_info {
};
struct inode vfs_inode;
};
+
+
+static inline struct squashfs_inode_info *squashfs_i(struct inode *inode)
+{
+ return list_entry(inode, struct squashfs_inode_info, vfs_inode);
+}
#endif
diff --git a/fs/squashfs/xattr_id.c b/fs/squashfs/xattr_id.c
index d33be5d..05385db 100644
--- a/fs/squashfs/xattr_id.c
+++ b/fs/squashfs/xattr_id.c
@@ -32,7 +32,6 @@
#include "squashfs_fs.h"
#include "squashfs_fs_sb.h"
-#include "squashfs_fs_i.h"
#include "squashfs.h"
#include "xattr.h"
diff --git a/fs/squashfs/xz_wrapper.c b/fs/squashfs/xz_wrapper.c
new file mode 100644
index 0000000..856756c
--- /dev/null
+++ b/fs/squashfs/xz_wrapper.c
@@ -0,0 +1,153 @@
+/*
+ * Squashfs - a compressed read only filesystem for Linux
+ *
+ * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
+ * Phillip Lougher <phillip@lougher.demon.co.uk>
+ *
+ * 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,
+ * or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * xz_wrapper.c
+ */
+
+
+#include <linux/mutex.h>
+#include <linux/buffer_head.h>
+#include <linux/slab.h>
+#include <linux/xz.h>
+
+#include "squashfs_fs.h"
+#include "squashfs_fs_sb.h"
+#include "squashfs_fs_i.h"
+#include "squashfs.h"
+#include "decompressor.h"
+
+struct squashfs_xz {
+ struct xz_dec *state;
+ struct xz_buf buf;
+};
+
+static void *squashfs_xz_init(struct squashfs_sb_info *msblk)
+{
+ int block_size = max_t(int, msblk->block_size, SQUASHFS_METADATA_SIZE);
+
+ struct squashfs_xz *stream = kmalloc(sizeof(*stream), GFP_KERNEL);
+ if (stream == NULL)
+ goto failed;
+
+ stream->state = xz_dec_init(XZ_PREALLOC, block_size);
+ if (stream->state == NULL)
+ goto failed;
+
+ return stream;
+
+failed:
+ ERROR("Failed to allocate xz workspace\n");
+ kfree(stream);
+ return NULL;
+}
+
+
+static void squashfs_xz_free(void *strm)
+{
+ struct squashfs_xz *stream = strm;
+
+ if (stream) {
+ xz_dec_end(stream->state);
+ kfree(stream);
+ }
+}
+
+
+static int squashfs_xz_uncompress(struct squashfs_sb_info *msblk, void **buffer,
+ struct buffer_head **bh, int b, int offset, int length, int srclength,
+ int pages)
+{
+ enum xz_ret xz_err;
+ int avail, total = 0, k = 0, page = 0;
+ struct squashfs_xz *stream = msblk->stream;
+
+ mutex_lock(&msblk->read_data_mutex);
+
+ xz_dec_reset(stream->state);
+ stream->buf.in_pos = 0;
+ stream->buf.in_size = 0;
+ stream->buf.out_pos = 0;
+ stream->buf.out_size = PAGE_CACHE_SIZE;
+ stream->buf.out = buffer[page++];
+
+ do {
+ if (stream->buf.in_pos == stream->buf.in_size && k < b) {
+ avail = min(length, msblk->devblksize - offset);
+ length -= avail;
+ wait_on_buffer(bh[k]);
+ if (!buffer_uptodate(bh[k]))
+ goto release_mutex;
+
+ if (avail == 0) {
+ offset = 0;
+ put_bh(bh[k++]);
+ continue;
+ }
+
+ stream->buf.in = bh[k]->b_data + offset;
+ stream->buf.in_size = avail;
+ stream->buf.in_pos = 0;
+ offset = 0;
+ }
+
+ if (stream->buf.out_pos == stream->buf.out_size
+ && page < pages) {
+ stream->buf.out = buffer[page++];
+ stream->buf.out_pos = 0;
+ total += PAGE_CACHE_SIZE;
+ }
+
+ xz_err = xz_dec_run(stream->state, &stream->buf);
+
+ if (stream->buf.in_pos == stream->buf.in_size && k < b)
+ put_bh(bh[k++]);
+ } while (xz_err == XZ_OK);
+
+ if (xz_err != XZ_STREAM_END) {
+ ERROR("xz_dec_run error, data probably corrupt\n");
+ goto release_mutex;
+ }
+
+ if (k < b) {
+ ERROR("xz_uncompress error, input remaining\n");
+ goto release_mutex;
+ }
+
+ total += stream->buf.out_pos;
+ mutex_unlock(&msblk->read_data_mutex);
+ return total;
+
+release_mutex:
+ mutex_unlock(&msblk->read_data_mutex);
+
+ for (; k < b; k++)
+ put_bh(bh[k]);
+
+ return -EIO;
+}
+
+const struct squashfs_decompressor squashfs_xz_comp_ops = {
+ .init = squashfs_xz_init,
+ .free = squashfs_xz_free,
+ .decompress = squashfs_xz_uncompress,
+ .id = XZ_COMPRESSION,
+ .name = "xz",
+ .supported = 1
+};
diff --git a/fs/squashfs/zlib_wrapper.c b/fs/squashfs/zlib_wrapper.c
index 7a60387..818a5e0 100644
--- a/fs/squashfs/zlib_wrapper.c
+++ b/fs/squashfs/zlib_wrapper.c
@@ -29,7 +29,6 @@
#include "squashfs_fs.h"
#include "squashfs_fs_sb.h"
-#include "squashfs_fs_i.h"
#include "squashfs.h"
#include "decompressor.h"
@@ -66,8 +65,8 @@ static int zlib_uncompress(struct squashfs_sb_info *msblk, void **buffer,
struct buffer_head **bh, int b, int offset, int length, int srclength,
int pages)
{
- int zlib_err = 0, zlib_init = 0;
- int avail, bytes, k = 0, page = 0;
+ int zlib_err, zlib_init = 0;
+ int k = 0, page = 0;
z_stream *stream = msblk->stream;
mutex_lock(&msblk->read_data_mutex);
@@ -75,11 +74,10 @@ static int zlib_uncompress(struct squashfs_sb_info *msblk, void **buffer,
stream->avail_out = 0;
stream->avail_in = 0;
- bytes = length;
do {
if (stream->avail_in == 0 && k < b) {
- avail = min(bytes, msblk->devblksize - offset);
- bytes -= avail;
+ int avail = min(length, msblk->devblksize - offset);
+ length -= avail;
wait_on_buffer(bh[k]);
if (!buffer_uptodate(bh[k]))
goto release_mutex;
@@ -128,6 +126,11 @@ static int zlib_uncompress(struct squashfs_sb_info *msblk, void **buffer,
goto release_mutex;
}
+ if (k < b) {
+ ERROR("zlib_uncompress error, data remaining\n");
+ goto release_mutex;
+ }
+
length = stream->total_out;
mutex_unlock(&msblk->read_data_mutex);
return length;
diff --git a/fs/stat.c b/fs/stat.c
index 12e90e2..d5c61cf 100644
--- a/fs/stat.c
+++ b/fs/stat.c
@@ -75,11 +75,13 @@ int vfs_fstatat(int dfd, const char __user *filename, struct kstat *stat,
int error = -EINVAL;
int lookup_flags = 0;
- if ((flag & ~AT_SYMLINK_NOFOLLOW) != 0)
+ if ((flag & ~(AT_SYMLINK_NOFOLLOW | AT_NO_AUTOMOUNT)) != 0)
goto out;
if (!(flag & AT_SYMLINK_NOFOLLOW))
lookup_flags |= LOOKUP_FOLLOW;
+ if (flag & AT_NO_AUTOMOUNT)
+ lookup_flags |= LOOKUP_NO_AUTOMOUNT;
error = user_path_at(dfd, filename, lookup_flags, &path);
if (error)
diff --git a/fs/super.c b/fs/super.c
index 4f6a357..74e149e 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -1141,7 +1141,7 @@ static struct vfsmount *fs_set_subtype(struct vfsmount *mnt, const char *fstype)
return mnt;
err:
- mntput_long(mnt);
+ mntput(mnt);
return ERR_PTR(err);
}
diff --git a/fs/sysfs/Kconfig b/fs/sysfs/Kconfig
index f4b6758..8c41fea 100644
--- a/fs/sysfs/Kconfig
+++ b/fs/sysfs/Kconfig
@@ -1,5 +1,5 @@
config SYSFS
- bool "sysfs file system support" if EMBEDDED
+ bool "sysfs file system support" if EXPERT
default y
help
The sysfs filesystem is a virtual filesystem that the kernel uses to
diff --git a/fs/xfs/Makefile b/fs/xfs/Makefile
index 0dce969..faca449 100644
--- a/fs/xfs/Makefile
+++ b/fs/xfs/Makefile
@@ -98,6 +98,7 @@ xfs-y += $(addprefix $(XFS_LINUX)/, \
kmem.o \
xfs_aops.o \
xfs_buf.o \
+ xfs_discard.o \
xfs_export.o \
xfs_file.o \
xfs_fs_subr.o \
diff --git a/fs/xfs/linux-2.6/xfs_buf.c b/fs/xfs/linux-2.6/xfs_buf.c
index 92f1f2a..ac1c7e8 100644
--- a/fs/xfs/linux-2.6/xfs_buf.c
+++ b/fs/xfs/linux-2.6/xfs_buf.c
@@ -896,7 +896,6 @@ xfs_buf_rele(
trace_xfs_buf_rele(bp, _RET_IP_);
if (!pag) {
- ASSERT(!bp->b_relse);
ASSERT(list_empty(&bp->b_lru));
ASSERT(RB_EMPTY_NODE(&bp->b_rbnode));
if (atomic_dec_and_test(&bp->b_hold))
@@ -908,11 +907,7 @@ xfs_buf_rele(
ASSERT(atomic_read(&bp->b_hold) > 0);
if (atomic_dec_and_lock(&bp->b_hold, &pag->pag_buf_lock)) {
- if (bp->b_relse) {
- atomic_inc(&bp->b_hold);
- spin_unlock(&pag->pag_buf_lock);
- bp->b_relse(bp);
- } else if (!(bp->b_flags & XBF_STALE) &&
+ if (!(bp->b_flags & XBF_STALE) &&
atomic_read(&bp->b_lru_ref)) {
xfs_buf_lru_add(bp);
spin_unlock(&pag->pag_buf_lock);
diff --git a/fs/xfs/linux-2.6/xfs_buf.h b/fs/xfs/linux-2.6/xfs_buf.h
index a76c242..cbe6595 100644
--- a/fs/xfs/linux-2.6/xfs_buf.h
+++ b/fs/xfs/linux-2.6/xfs_buf.h
@@ -152,8 +152,6 @@ typedef struct xfs_buftarg {
struct xfs_buf;
typedef void (*xfs_buf_iodone_t)(struct xfs_buf *);
-typedef void (*xfs_buf_relse_t)(struct xfs_buf *);
-typedef int (*xfs_buf_bdstrat_t)(struct xfs_buf *);
#define XB_PAGES 2
@@ -183,7 +181,6 @@ typedef struct xfs_buf {
void *b_addr; /* virtual address of buffer */
struct work_struct b_iodone_work;
xfs_buf_iodone_t b_iodone; /* I/O completion function */
- xfs_buf_relse_t b_relse; /* releasing function */
struct completion b_iowait; /* queue for I/O waiters */
void *b_fspriv;
void *b_fspriv2;
@@ -323,7 +320,6 @@ void xfs_buf_stale(struct xfs_buf *bp);
#define XFS_BUF_FSPRIVATE2(bp, type) ((type)(bp)->b_fspriv2)
#define XFS_BUF_SET_FSPRIVATE2(bp, val) ((bp)->b_fspriv2 = (void*)(val))
#define XFS_BUF_SET_START(bp) do { } while (0)
-#define XFS_BUF_SET_BRELSE_FUNC(bp, func) ((bp)->b_relse = (func))
#define XFS_BUF_PTR(bp) (xfs_caddr_t)((bp)->b_addr)
#define XFS_BUF_SET_PTR(bp, val, cnt) xfs_buf_associate_memory(bp, val, cnt)
@@ -360,8 +356,7 @@ xfs_buf_set_ref(
static inline void xfs_buf_relse(xfs_buf_t *bp)
{
- if (!bp->b_relse)
- xfs_buf_unlock(bp);
+ xfs_buf_unlock(bp);
xfs_buf_rele(bp);
}
diff --git a/fs/xfs/linux-2.6/xfs_discard.c b/fs/xfs/linux-2.6/xfs_discard.c
new file mode 100644
index 0000000..05201ae
--- /dev/null
+++ b/fs/xfs/linux-2.6/xfs_discard.c
@@ -0,0 +1,191 @@
+/*
+ * Copyright (C) 2010 Red Hat, Inc.
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would 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 the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#include "xfs.h"
+#include "xfs_sb.h"
+#include "xfs_inum.h"
+#include "xfs_log.h"
+#include "xfs_ag.h"
+#include "xfs_mount.h"
+#include "xfs_quota.h"
+#include "xfs_trans.h"
+#include "xfs_alloc_btree.h"
+#include "xfs_bmap_btree.h"
+#include "xfs_ialloc_btree.h"
+#include "xfs_btree.h"
+#include "xfs_inode.h"
+#include "xfs_alloc.h"
+#include "xfs_error.h"
+#include "xfs_discard.h"
+#include "xfs_trace.h"
+
+STATIC int
+xfs_trim_extents(
+ struct xfs_mount *mp,
+ xfs_agnumber_t agno,
+ xfs_fsblock_t start,
+ xfs_fsblock_t len,
+ xfs_fsblock_t minlen,
+ __uint64_t *blocks_trimmed)
+{
+ struct block_device *bdev = mp->m_ddev_targp->bt_bdev;
+ struct xfs_btree_cur *cur;
+ struct xfs_buf *agbp;
+ struct xfs_perag *pag;
+ int error;
+ int i;
+
+ pag = xfs_perag_get(mp, agno);
+
+ error = xfs_alloc_read_agf(mp, NULL, agno, 0, &agbp);
+ if (error || !agbp)
+ goto out_put_perag;
+
+ cur = xfs_allocbt_init_cursor(mp, NULL, agbp, agno, XFS_BTNUM_CNT);
+
+ /*
+ * Force out the log. This means any transactions that might have freed
+ * space before we took the AGF buffer lock are now on disk, and the
+ * volatile disk cache is flushed.
+ */
+ xfs_log_force(mp, XFS_LOG_SYNC);
+
+ /*
+ * Look up the longest btree in the AGF and start with it.
+ */
+ error = xfs_alloc_lookup_le(cur, 0,
+ XFS_BUF_TO_AGF(agbp)->agf_longest, &i);
+ if (error)
+ goto out_del_cursor;
+
+ /*
+ * Loop until we are done with all extents that are large
+ * enough to be worth discarding.
+ */
+ while (i) {
+ xfs_agblock_t fbno;
+ xfs_extlen_t flen;
+
+ error = xfs_alloc_get_rec(cur, &fbno, &flen, &i);
+ if (error)
+ goto out_del_cursor;
+ XFS_WANT_CORRUPTED_GOTO(i == 1, out_del_cursor);
+ ASSERT(flen <= XFS_BUF_TO_AGF(agbp)->agf_longest);
+
+ /*
+ * Too small? Give up.
+ */
+ if (flen < minlen) {
+ trace_xfs_discard_toosmall(mp, agno, fbno, flen);
+ goto out_del_cursor;
+ }
+
+ /*
+ * If the extent is entirely outside of the range we are
+ * supposed to discard skip it. Do not bother to trim
+ * down partially overlapping ranges for now.
+ */
+ if (XFS_AGB_TO_FSB(mp, agno, fbno) + flen < start ||
+ XFS_AGB_TO_FSB(mp, agno, fbno) >= start + len) {
+ trace_xfs_discard_exclude(mp, agno, fbno, flen);
+ goto next_extent;
+ }
+
+ /*
+ * If any blocks in the range are still busy, skip the
+ * discard and try again the next time.
+ */
+ if (xfs_alloc_busy_search(mp, agno, fbno, flen)) {
+ trace_xfs_discard_busy(mp, agno, fbno, flen);
+ goto next_extent;
+ }
+
+ trace_xfs_discard_extent(mp, agno, fbno, flen);
+ error = -blkdev_issue_discard(bdev,
+ XFS_AGB_TO_DADDR(mp, agno, fbno),
+ XFS_FSB_TO_BB(mp, flen),
+ GFP_NOFS, 0);
+ if (error)
+ goto out_del_cursor;
+ *blocks_trimmed += flen;
+
+next_extent:
+ error = xfs_btree_decrement(cur, 0, &i);
+ if (error)
+ goto out_del_cursor;
+ }
+
+out_del_cursor:
+ xfs_btree_del_cursor(cur, error ? XFS_BTREE_ERROR : XFS_BTREE_NOERROR);
+ xfs_buf_relse(agbp);
+out_put_perag:
+ xfs_perag_put(pag);
+ return error;
+}
+
+int
+xfs_ioc_trim(
+ struct xfs_mount *mp,
+ struct fstrim_range __user *urange)
+{
+ struct request_queue *q = mp->m_ddev_targp->bt_bdev->bd_disk->queue;
+ unsigned int granularity = q->limits.discard_granularity;
+ struct fstrim_range range;
+ xfs_fsblock_t start, len, minlen;
+ xfs_agnumber_t start_agno, end_agno, agno;
+ __uint64_t blocks_trimmed = 0;
+ int error, last_error = 0;
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -XFS_ERROR(EPERM);
+ if (copy_from_user(&range, urange, sizeof(range)))
+ return -XFS_ERROR(EFAULT);
+
+ /*
+ * Truncating down the len isn't actually quite correct, but using
+ * XFS_B_TO_FSB would mean we trivially get overflows for values
+ * of ULLONG_MAX or slightly lower. And ULLONG_MAX is the default
+ * used by the fstrim application. In the end it really doesn't
+ * matter as trimming blocks is an advisory interface.
+ */
+ start = XFS_B_TO_FSBT(mp, range.start);
+ len = XFS_B_TO_FSBT(mp, range.len);
+ minlen = XFS_B_TO_FSB(mp, max_t(u64, granularity, range.minlen));
+
+ start_agno = XFS_FSB_TO_AGNO(mp, start);
+ if (start_agno >= mp->m_sb.sb_agcount)
+ return -XFS_ERROR(EINVAL);
+
+ end_agno = XFS_FSB_TO_AGNO(mp, start + len);
+ if (end_agno >= mp->m_sb.sb_agcount)
+ end_agno = mp->m_sb.sb_agcount - 1;
+
+ for (agno = start_agno; agno <= end_agno; agno++) {
+ error = -xfs_trim_extents(mp, agno, start, len, minlen,
+ &blocks_trimmed);
+ if (error)
+ last_error = error;
+ }
+
+ if (last_error)
+ return last_error;
+
+ range.len = XFS_FSB_TO_B(mp, blocks_trimmed);
+ if (copy_to_user(urange, &range, sizeof(range)))
+ return -XFS_ERROR(EFAULT);
+ return 0;
+}
diff --git a/fs/xfs/linux-2.6/xfs_discard.h b/fs/xfs/linux-2.6/xfs_discard.h
new file mode 100644
index 0000000..e82b6dd
--- /dev/null
+++ b/fs/xfs/linux-2.6/xfs_discard.h
@@ -0,0 +1,8 @@
+#ifndef XFS_DISCARD_H
+#define XFS_DISCARD_H 1
+
+struct fstrim_range;
+
+extern int xfs_ioc_trim(struct xfs_mount *, struct fstrim_range __user *);
+
+#endif /* XFS_DISCARD_H */
diff --git a/fs/xfs/linux-2.6/xfs_file.c b/fs/xfs/linux-2.6/xfs_file.c
index ba8ad42..a55c1b4 100644
--- a/fs/xfs/linux-2.6/xfs_file.c
+++ b/fs/xfs/linux-2.6/xfs_file.c
@@ -37,10 +37,45 @@
#include "xfs_trace.h"
#include <linux/dcache.h>
+#include <linux/falloc.h>
static const struct vm_operations_struct xfs_file_vm_ops;
/*
+ * Locking primitives for read and write IO paths to ensure we consistently use
+ * and order the inode->i_mutex, ip->i_lock and ip->i_iolock.
+ */
+static inline void
+xfs_rw_ilock(
+ struct xfs_inode *ip,
+ int type)
+{
+ if (type & XFS_IOLOCK_EXCL)
+ mutex_lock(&VFS_I(ip)->i_mutex);
+ xfs_ilock(ip, type);
+}
+
+static inline void
+xfs_rw_iunlock(
+ struct xfs_inode *ip,
+ int type)
+{
+ xfs_iunlock(ip, type);
+ if (type & XFS_IOLOCK_EXCL)
+ mutex_unlock(&VFS_I(ip)->i_mutex);
+}
+
+static inline void
+xfs_rw_ilock_demote(
+ struct xfs_inode *ip,
+ int type)
+{
+ xfs_ilock_demote(ip, type);
+ if (type & XFS_IOLOCK_EXCL)
+ mutex_unlock(&VFS_I(ip)->i_mutex);
+}
+
+/*
* xfs_iozero
*
* xfs_iozero clears the specified range of buffer supplied,
@@ -262,22 +297,21 @@ xfs_file_aio_read(
if (XFS_FORCED_SHUTDOWN(mp))
return -EIO;
- if (unlikely(ioflags & IO_ISDIRECT))
- mutex_lock(&inode->i_mutex);
- xfs_ilock(ip, XFS_IOLOCK_SHARED);
-
if (unlikely(ioflags & IO_ISDIRECT)) {
+ xfs_rw_ilock(ip, XFS_IOLOCK_EXCL);
+
if (inode->i_mapping->nrpages) {
ret = -xfs_flushinval_pages(ip,
(iocb->ki_pos & PAGE_CACHE_MASK),
-1, FI_REMAPF_LOCKED);
+ if (ret) {
+ xfs_rw_iunlock(ip, XFS_IOLOCK_EXCL);
+ return ret;
+ }
}
- mutex_unlock(&inode->i_mutex);
- if (ret) {
- xfs_iunlock(ip, XFS_IOLOCK_SHARED);
- return ret;
- }
- }
+ xfs_rw_ilock_demote(ip, XFS_IOLOCK_EXCL);
+ } else
+ xfs_rw_ilock(ip, XFS_IOLOCK_SHARED);
trace_xfs_file_read(ip, size, iocb->ki_pos, ioflags);
@@ -285,7 +319,7 @@ xfs_file_aio_read(
if (ret > 0)
XFS_STATS_ADD(xs_read_bytes, ret);
- xfs_iunlock(ip, XFS_IOLOCK_SHARED);
+ xfs_rw_iunlock(ip, XFS_IOLOCK_SHARED);
return ret;
}
@@ -309,7 +343,7 @@ xfs_file_splice_read(
if (XFS_FORCED_SHUTDOWN(ip->i_mount))
return -EIO;
- xfs_ilock(ip, XFS_IOLOCK_SHARED);
+ xfs_rw_ilock(ip, XFS_IOLOCK_SHARED);
trace_xfs_file_splice_read(ip, count, *ppos, ioflags);
@@ -317,10 +351,61 @@ xfs_file_splice_read(
if (ret > 0)
XFS_STATS_ADD(xs_read_bytes, ret);
- xfs_iunlock(ip, XFS_IOLOCK_SHARED);
+ xfs_rw_iunlock(ip, XFS_IOLOCK_SHARED);
return ret;
}
+STATIC void
+xfs_aio_write_isize_update(
+ struct inode *inode,
+ loff_t *ppos,
+ ssize_t bytes_written)
+{
+ struct xfs_inode *ip = XFS_I(inode);
+ xfs_fsize_t isize = i_size_read(inode);
+
+ if (bytes_written > 0)
+ XFS_STATS_ADD(xs_write_bytes, bytes_written);
+
+ if (unlikely(bytes_written < 0 && bytes_written != -EFAULT &&
+ *ppos > isize))
+ *ppos = isize;
+
+ if (*ppos > ip->i_size) {
+ xfs_rw_ilock(ip, XFS_ILOCK_EXCL);
+ if (*ppos > ip->i_size)
+ ip->i_size = *ppos;
+ xfs_rw_iunlock(ip, XFS_ILOCK_EXCL);
+ }
+}
+
+/*
+ * If this was a direct or synchronous I/O that failed (such as ENOSPC) then
+ * part of the I/O may have been written to disk before the error occured. In
+ * this case the on-disk file size may have been adjusted beyond the in-memory
+ * file size and now needs to be truncated back.
+ */
+STATIC void
+xfs_aio_write_newsize_update(
+ struct xfs_inode *ip)
+{
+ if (ip->i_new_size) {
+ xfs_rw_ilock(ip, XFS_ILOCK_EXCL);
+ ip->i_new_size = 0;
+ if (ip->i_d.di_size > ip->i_size)
+ ip->i_d.di_size = ip->i_size;
+ xfs_rw_iunlock(ip, XFS_ILOCK_EXCL);
+ }
+}
+
+/*
+ * xfs_file_splice_write() does not use xfs_rw_ilock() because
+ * generic_file_splice_write() takes the i_mutex itself. This, in theory,
+ * couuld cause lock inversions between the aio_write path and the splice path
+ * if someone is doing concurrent splice(2) based writes and write(2) based
+ * writes to the same inode. The only real way to fix this is to re-implement
+ * the generic code here with correct locking orders.
+ */
STATIC ssize_t
xfs_file_splice_write(
struct pipe_inode_info *pipe,
@@ -331,7 +416,7 @@ xfs_file_splice_write(
{
struct inode *inode = outfilp->f_mapping->host;
struct xfs_inode *ip = XFS_I(inode);
- xfs_fsize_t isize, new_size;
+ xfs_fsize_t new_size;
int ioflags = 0;
ssize_t ret;
@@ -355,27 +440,9 @@ xfs_file_splice_write(
trace_xfs_file_splice_write(ip, count, *ppos, ioflags);
ret = generic_file_splice_write(pipe, outfilp, ppos, count, flags);
- if (ret > 0)
- XFS_STATS_ADD(xs_write_bytes, ret);
-
- isize = i_size_read(inode);
- if (unlikely(ret < 0 && ret != -EFAULT && *ppos > isize))
- *ppos = isize;
-
- if (*ppos > ip->i_size) {
- xfs_ilock(ip, XFS_ILOCK_EXCL);
- if (*ppos > ip->i_size)
- ip->i_size = *ppos;
- xfs_iunlock(ip, XFS_ILOCK_EXCL);
- }
- if (ip->i_new_size) {
- xfs_ilock(ip, XFS_ILOCK_EXCL);
- ip->i_new_size = 0;
- if (ip->i_d.di_size > ip->i_size)
- ip->i_d.di_size = ip->i_size;
- xfs_iunlock(ip, XFS_ILOCK_EXCL);
- }
+ xfs_aio_write_isize_update(inode, ppos, ret);
+ xfs_aio_write_newsize_update(ip);
xfs_iunlock(ip, XFS_IOLOCK_EXCL);
return ret;
}
@@ -562,247 +629,314 @@ out_lock:
return error;
}
+/*
+ * Common pre-write limit and setup checks.
+ *
+ * Returns with iolock held according to @iolock.
+ */
STATIC ssize_t
-xfs_file_aio_write(
- struct kiocb *iocb,
- const struct iovec *iovp,
- unsigned long nr_segs,
- loff_t pos)
+xfs_file_aio_write_checks(
+ struct file *file,
+ loff_t *pos,
+ size_t *count,
+ int *iolock)
{
- struct file *file = iocb->ki_filp;
- struct address_space *mapping = file->f_mapping;
- struct inode *inode = mapping->host;
+ struct inode *inode = file->f_mapping->host;
struct xfs_inode *ip = XFS_I(inode);
- struct xfs_mount *mp = ip->i_mount;
- ssize_t ret = 0, error = 0;
- int ioflags = 0;
- xfs_fsize_t isize, new_size;
- int iolock;
- size_t ocount = 0, count;
- int need_i_mutex;
+ xfs_fsize_t new_size;
+ int error = 0;
- XFS_STATS_INC(xs_write_calls);
+ error = generic_write_checks(file, pos, count, S_ISBLK(inode->i_mode));
+ if (error) {
+ xfs_rw_iunlock(ip, XFS_ILOCK_EXCL | *iolock);
+ *iolock = 0;
+ return error;
+ }
- BUG_ON(iocb->ki_pos != pos);
+ new_size = *pos + *count;
+ if (new_size > ip->i_size)
+ ip->i_new_size = new_size;
- if (unlikely(file->f_flags & O_DIRECT))
- ioflags |= IO_ISDIRECT;
- if (file->f_mode & FMODE_NOCMTIME)
- ioflags |= IO_INVIS;
+ if (likely(!(file->f_mode & FMODE_NOCMTIME)))
+ file_update_time(file);
+
+ /*
+ * If the offset is beyond the size of the file, we need to zero any
+ * blocks that fall between the existing EOF and the start of this
+ * write.
+ */
+ if (*pos > ip->i_size)
+ error = -xfs_zero_eof(ip, *pos, ip->i_size);
- error = generic_segment_checks(iovp, &nr_segs, &ocount, VERIFY_READ);
+ xfs_rw_iunlock(ip, XFS_ILOCK_EXCL);
if (error)
return error;
- count = ocount;
- if (count == 0)
- return 0;
-
- xfs_wait_for_freeze(mp, SB_FREEZE_WRITE);
+ /*
+ * If we're writing the file then make sure to clear the setuid and
+ * setgid bits if the process is not being run by root. This keeps
+ * people from modifying setuid and setgid binaries.
+ */
+ return file_remove_suid(file);
- if (XFS_FORCED_SHUTDOWN(mp))
- return -EIO;
+}
-relock:
- if (ioflags & IO_ISDIRECT) {
- iolock = XFS_IOLOCK_SHARED;
- need_i_mutex = 0;
- } else {
- iolock = XFS_IOLOCK_EXCL;
- need_i_mutex = 1;
- mutex_lock(&inode->i_mutex);
+/*
+ * xfs_file_dio_aio_write - handle direct IO writes
+ *
+ * Lock the inode appropriately to prepare for and issue a direct IO write.
+ * By separating it from the buffered write path we remove all the tricky to
+ * follow locking changes and looping.
+ *
+ * If there are cached pages or we're extending the file, we need IOLOCK_EXCL
+ * until we're sure the bytes at the new EOF have been zeroed and/or the cached
+ * pages are flushed out.
+ *
+ * In most cases the direct IO writes will be done holding IOLOCK_SHARED
+ * allowing them to be done in parallel with reads and other direct IO writes.
+ * However, if the IO is not aligned to filesystem blocks, the direct IO layer
+ * needs to do sub-block zeroing and that requires serialisation against other
+ * direct IOs to the same block. In this case we need to serialise the
+ * submission of the unaligned IOs so that we don't get racing block zeroing in
+ * the dio layer. To avoid the problem with aio, we also need to wait for
+ * outstanding IOs to complete so that unwritten extent conversion is completed
+ * before we try to map the overlapping block. This is currently implemented by
+ * hitting it with a big hammer (i.e. xfs_ioend_wait()).
+ *
+ * Returns with locks held indicated by @iolock and errors indicated by
+ * negative return values.
+ */
+STATIC ssize_t
+xfs_file_dio_aio_write(
+ struct kiocb *iocb,
+ const struct iovec *iovp,
+ unsigned long nr_segs,
+ loff_t pos,
+ size_t ocount,
+ int *iolock)
+{
+ struct file *file = iocb->ki_filp;
+ struct address_space *mapping = file->f_mapping;
+ struct inode *inode = mapping->host;
+ struct xfs_inode *ip = XFS_I(inode);
+ struct xfs_mount *mp = ip->i_mount;
+ ssize_t ret = 0;
+ size_t count = ocount;
+ int unaligned_io = 0;
+ struct xfs_buftarg *target = XFS_IS_REALTIME_INODE(ip) ?
+ mp->m_rtdev_targp : mp->m_ddev_targp;
+
+ *iolock = 0;
+ if ((pos & target->bt_smask) || (count & target->bt_smask))
+ return -XFS_ERROR(EINVAL);
+
+ if ((pos & mp->m_blockmask) || ((pos + count) & mp->m_blockmask))
+ unaligned_io = 1;
+
+ if (unaligned_io || mapping->nrpages || pos > ip->i_size)
+ *iolock = XFS_IOLOCK_EXCL;
+ else
+ *iolock = XFS_IOLOCK_SHARED;
+ xfs_rw_ilock(ip, XFS_ILOCK_EXCL | *iolock);
+
+ ret = xfs_file_aio_write_checks(file, &pos, &count, iolock);
+ if (ret)
+ return ret;
+
+ if (mapping->nrpages) {
+ WARN_ON(*iolock != XFS_IOLOCK_EXCL);
+ ret = -xfs_flushinval_pages(ip, (pos & PAGE_CACHE_MASK), -1,
+ FI_REMAPF_LOCKED);
+ if (ret)
+ return ret;
}
- xfs_ilock(ip, XFS_ILOCK_EXCL|iolock);
-
-start:
- error = -generic_write_checks(file, &pos, &count,
- S_ISBLK(inode->i_mode));
- if (error) {
- xfs_iunlock(ip, XFS_ILOCK_EXCL|iolock);
- goto out_unlock_mutex;
+ /*
+ * If we are doing unaligned IO, wait for all other IO to drain,
+ * otherwise demote the lock if we had to flush cached pages
+ */
+ if (unaligned_io)
+ xfs_ioend_wait(ip);
+ else if (*iolock == XFS_IOLOCK_EXCL) {
+ xfs_rw_ilock_demote(ip, XFS_IOLOCK_EXCL);
+ *iolock = XFS_IOLOCK_SHARED;
}
- if (ioflags & IO_ISDIRECT) {
- xfs_buftarg_t *target =
- XFS_IS_REALTIME_INODE(ip) ?
- mp->m_rtdev_targp : mp->m_ddev_targp;
+ trace_xfs_file_direct_write(ip, count, iocb->ki_pos, 0);
+ ret = generic_file_direct_write(iocb, iovp,
+ &nr_segs, pos, &iocb->ki_pos, count, ocount);
- if ((pos & target->bt_smask) || (count & target->bt_smask)) {
- xfs_iunlock(ip, XFS_ILOCK_EXCL|iolock);
- return XFS_ERROR(-EINVAL);
- }
+ /* No fallback to buffered IO on errors for XFS. */
+ ASSERT(ret < 0 || ret == count);
+ return ret;
+}
- if (!need_i_mutex && (mapping->nrpages || pos > ip->i_size)) {
- xfs_iunlock(ip, XFS_ILOCK_EXCL|iolock);
- iolock = XFS_IOLOCK_EXCL;
- need_i_mutex = 1;
- mutex_lock(&inode->i_mutex);
- xfs_ilock(ip, XFS_ILOCK_EXCL|iolock);
- goto start;
- }
- }
+STATIC ssize_t
+xfs_file_buffered_aio_write(
+ struct kiocb *iocb,
+ const struct iovec *iovp,
+ unsigned long nr_segs,
+ loff_t pos,
+ size_t ocount,
+ int *iolock)
+{
+ struct file *file = iocb->ki_filp;
+ struct address_space *mapping = file->f_mapping;
+ struct inode *inode = mapping->host;
+ struct xfs_inode *ip = XFS_I(inode);
+ ssize_t ret;
+ int enospc = 0;
+ size_t count = ocount;
- new_size = pos + count;
- if (new_size > ip->i_size)
- ip->i_new_size = new_size;
+ *iolock = XFS_IOLOCK_EXCL;
+ xfs_rw_ilock(ip, XFS_ILOCK_EXCL | *iolock);
- if (likely(!(ioflags & IO_INVIS)))
- file_update_time(file);
+ ret = xfs_file_aio_write_checks(file, &pos, &count, iolock);
+ if (ret)
+ return ret;
+ /* We can write back this queue in page reclaim */
+ current->backing_dev_info = mapping->backing_dev_info;
+
+write_retry:
+ trace_xfs_file_buffered_write(ip, count, iocb->ki_pos, 0);
+ ret = generic_file_buffered_write(iocb, iovp, nr_segs,
+ pos, &iocb->ki_pos, count, ret);
/*
- * If the offset is beyond the size of the file, we have a couple
- * of things to do. First, if there is already space allocated
- * we need to either create holes or zero the disk or ...
- *
- * If there is a page where the previous size lands, we need
- * to zero it out up to the new size.
+ * if we just got an ENOSPC, flush the inode now we aren't holding any
+ * page locks and retry *once*
*/
-
- if (pos > ip->i_size) {
- error = xfs_zero_eof(ip, pos, ip->i_size);
- if (error) {
- xfs_iunlock(ip, XFS_ILOCK_EXCL);
- goto out_unlock_internal;
- }
+ if (ret == -ENOSPC && !enospc) {
+ ret = -xfs_flush_pages(ip, 0, -1, 0, FI_NONE);
+ if (ret)
+ return ret;
+ enospc = 1;
+ goto write_retry;
}
- xfs_iunlock(ip, XFS_ILOCK_EXCL);
+ current->backing_dev_info = NULL;
+ return ret;
+}
- /*
- * If we're writing the file then make sure to clear the
- * setuid and setgid bits if the process is not being run
- * by root. This keeps people from modifying setuid and
- * setgid binaries.
- */
- error = -file_remove_suid(file);
- if (unlikely(error))
- goto out_unlock_internal;
+STATIC ssize_t
+xfs_file_aio_write(
+ struct kiocb *iocb,
+ const struct iovec *iovp,
+ unsigned long nr_segs,
+ loff_t pos)
+{
+ struct file *file = iocb->ki_filp;
+ struct address_space *mapping = file->f_mapping;
+ struct inode *inode = mapping->host;
+ struct xfs_inode *ip = XFS_I(inode);
+ ssize_t ret;
+ int iolock;
+ size_t ocount = 0;
- /* We can write back this queue in page reclaim */
- current->backing_dev_info = mapping->backing_dev_info;
+ XFS_STATS_INC(xs_write_calls);
- if ((ioflags & IO_ISDIRECT)) {
- if (mapping->nrpages) {
- WARN_ON(need_i_mutex == 0);
- error = xfs_flushinval_pages(ip,
- (pos & PAGE_CACHE_MASK),
- -1, FI_REMAPF_LOCKED);
- if (error)
- goto out_unlock_internal;
- }
+ BUG_ON(iocb->ki_pos != pos);
- if (need_i_mutex) {
- /* demote the lock now the cached pages are gone */
- xfs_ilock_demote(ip, XFS_IOLOCK_EXCL);
- mutex_unlock(&inode->i_mutex);
+ ret = generic_segment_checks(iovp, &nr_segs, &ocount, VERIFY_READ);
+ if (ret)
+ return ret;
- iolock = XFS_IOLOCK_SHARED;
- need_i_mutex = 0;
- }
+ if (ocount == 0)
+ return 0;
- trace_xfs_file_direct_write(ip, count, iocb->ki_pos, ioflags);
- ret = generic_file_direct_write(iocb, iovp,
- &nr_segs, pos, &iocb->ki_pos, count, ocount);
+ xfs_wait_for_freeze(ip->i_mount, SB_FREEZE_WRITE);
- /*
- * direct-io write to a hole: fall through to buffered I/O
- * for completing the rest of the request.
- */
- if (ret >= 0 && ret != count) {
- XFS_STATS_ADD(xs_write_bytes, ret);
+ if (XFS_FORCED_SHUTDOWN(ip->i_mount))
+ return -EIO;
- pos += ret;
- count -= ret;
+ if (unlikely(file->f_flags & O_DIRECT))
+ ret = xfs_file_dio_aio_write(iocb, iovp, nr_segs, pos,
+ ocount, &iolock);
+ else
+ ret = xfs_file_buffered_aio_write(iocb, iovp, nr_segs, pos,
+ ocount, &iolock);
- ioflags &= ~IO_ISDIRECT;
- xfs_iunlock(ip, iolock);
- goto relock;
- }
- } else {
- int enospc = 0;
- ssize_t ret2 = 0;
+ xfs_aio_write_isize_update(inode, &iocb->ki_pos, ret);
-write_retry:
- trace_xfs_file_buffered_write(ip, count, iocb->ki_pos, ioflags);
- ret2 = generic_file_buffered_write(iocb, iovp, nr_segs,
- pos, &iocb->ki_pos, count, ret);
- /*
- * if we just got an ENOSPC, flush the inode now we
- * aren't holding any page locks and retry *once*
- */
- if (ret2 == -ENOSPC && !enospc) {
- error = xfs_flush_pages(ip, 0, -1, 0, FI_NONE);
- if (error)
- goto out_unlock_internal;
- enospc = 1;
- goto write_retry;
- }
- ret = ret2;
- }
+ if (ret <= 0)
+ goto out_unlock;
- current->backing_dev_info = NULL;
+ /* Handle various SYNC-type writes */
+ if ((file->f_flags & O_DSYNC) || IS_SYNC(inode)) {
+ loff_t end = pos + ret - 1;
+ int error, error2;
- isize = i_size_read(inode);
- if (unlikely(ret < 0 && ret != -EFAULT && iocb->ki_pos > isize))
- iocb->ki_pos = isize;
+ xfs_rw_iunlock(ip, iolock);
+ error = filemap_write_and_wait_range(mapping, pos, end);
+ xfs_rw_ilock(ip, iolock);
- if (iocb->ki_pos > ip->i_size) {
- xfs_ilock(ip, XFS_ILOCK_EXCL);
- if (iocb->ki_pos > ip->i_size)
- ip->i_size = iocb->ki_pos;
- xfs_iunlock(ip, XFS_ILOCK_EXCL);
+ error2 = -xfs_file_fsync(file,
+ (file->f_flags & __O_SYNC) ? 0 : 1);
+ if (error)
+ ret = error;
+ else if (error2)
+ ret = error2;
}
- error = -ret;
- if (ret <= 0)
- goto out_unlock_internal;
+out_unlock:
+ xfs_aio_write_newsize_update(ip);
+ xfs_rw_iunlock(ip, iolock);
+ return ret;
+}
- XFS_STATS_ADD(xs_write_bytes, ret);
+STATIC long
+xfs_file_fallocate(
+ struct file *file,
+ int mode,
+ loff_t offset,
+ loff_t len)
+{
+ struct inode *inode = file->f_path.dentry->d_inode;
+ long error;
+ loff_t new_size = 0;
+ xfs_flock64_t bf;
+ xfs_inode_t *ip = XFS_I(inode);
+ int cmd = XFS_IOC_RESVSP;
- /* Handle various SYNC-type writes */
- if ((file->f_flags & O_DSYNC) || IS_SYNC(inode)) {
- loff_t end = pos + ret - 1;
- int error2;
+ if (mode & ~(FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE))
+ return -EOPNOTSUPP;
- xfs_iunlock(ip, iolock);
- if (need_i_mutex)
- mutex_unlock(&inode->i_mutex);
+ bf.l_whence = 0;
+ bf.l_start = offset;
+ bf.l_len = len;
- error2 = filemap_write_and_wait_range(mapping, pos, end);
- if (!error)
- error = error2;
- if (need_i_mutex)
- mutex_lock(&inode->i_mutex);
- xfs_ilock(ip, iolock);
+ xfs_ilock(ip, XFS_IOLOCK_EXCL);
- error2 = -xfs_file_fsync(file,
- (file->f_flags & __O_SYNC) ? 0 : 1);
- if (!error)
- error = error2;
+ if (mode & FALLOC_FL_PUNCH_HOLE)
+ cmd = XFS_IOC_UNRESVSP;
+
+ /* check the new inode size is valid before allocating */
+ if (!(mode & FALLOC_FL_KEEP_SIZE) &&
+ offset + len > i_size_read(inode)) {
+ new_size = offset + len;
+ error = inode_newsize_ok(inode, new_size);
+ if (error)
+ goto out_unlock;
}
- out_unlock_internal:
- if (ip->i_new_size) {
- xfs_ilock(ip, XFS_ILOCK_EXCL);
- ip->i_new_size = 0;
- /*
- * If this was a direct or synchronous I/O that failed (such
- * as ENOSPC) then part of the I/O may have been written to
- * disk before the error occured. In this case the on-disk
- * file size may have been adjusted beyond the in-memory file
- * size and now needs to be truncated back.
- */
- if (ip->i_d.di_size > ip->i_size)
- ip->i_d.di_size = ip->i_size;
- xfs_iunlock(ip, XFS_ILOCK_EXCL);
+ error = -xfs_change_file_space(ip, cmd, &bf, 0, XFS_ATTR_NOLOCK);
+ if (error)
+ goto out_unlock;
+
+ /* Change file size if needed */
+ if (new_size) {
+ struct iattr iattr;
+
+ iattr.ia_valid = ATTR_SIZE;
+ iattr.ia_size = new_size;
+ error = -xfs_setattr(ip, &iattr, XFS_ATTR_NOLOCK);
}
- xfs_iunlock(ip, iolock);
- out_unlock_mutex:
- if (need_i_mutex)
- mutex_unlock(&inode->i_mutex);
- return -error;
+
+out_unlock:
+ xfs_iunlock(ip, XFS_IOLOCK_EXCL);
+ return error;
}
+
STATIC int
xfs_file_open(
struct inode *inode,
@@ -921,6 +1055,7 @@ const struct file_operations xfs_file_operations = {
.open = xfs_file_open,
.release = xfs_file_release,
.fsync = xfs_file_fsync,
+ .fallocate = xfs_file_fallocate,
};
const struct file_operations xfs_dir_file_operations = {
diff --git a/fs/xfs/linux-2.6/xfs_ioctl.c b/fs/xfs/linux-2.6/xfs_ioctl.c
index ad442d9..b06ede1 100644
--- a/fs/xfs/linux-2.6/xfs_ioctl.c
+++ b/fs/xfs/linux-2.6/xfs_ioctl.c
@@ -39,6 +39,7 @@
#include "xfs_dfrag.h"
#include "xfs_fsops.h"
#include "xfs_vnodeops.h"
+#include "xfs_discard.h"
#include "xfs_quota.h"
#include "xfs_inode_item.h"
#include "xfs_export.h"
@@ -1294,6 +1295,8 @@ xfs_file_ioctl(
trace_xfs_file_ioctl(ip);
switch (cmd) {
+ case FITRIM:
+ return xfs_ioc_trim(mp, arg);
case XFS_IOC_ALLOCSP:
case XFS_IOC_FREESP:
case XFS_IOC_RESVSP:
diff --git a/fs/xfs/linux-2.6/xfs_iops.c b/fs/xfs/linux-2.6/xfs_iops.c
index da54403..bd57278 100644
--- a/fs/xfs/linux-2.6/xfs_iops.c
+++ b/fs/xfs/linux-2.6/xfs_iops.c
@@ -46,7 +46,6 @@
#include <linux/namei.h>
#include <linux/posix_acl.h>
#include <linux/security.h>
-#include <linux/falloc.h>
#include <linux/fiemap.h>
#include <linux/slab.h>
@@ -505,61 +504,6 @@ xfs_vn_setattr(
return -xfs_setattr(XFS_I(dentry->d_inode), iattr, 0);
}
-STATIC long
-xfs_vn_fallocate(
- struct inode *inode,
- int mode,
- loff_t offset,
- loff_t len)
-{
- long error;
- loff_t new_size = 0;
- xfs_flock64_t bf;
- xfs_inode_t *ip = XFS_I(inode);
- int cmd = XFS_IOC_RESVSP;
-
- /* preallocation on directories not yet supported */
- error = -ENODEV;
- if (S_ISDIR(inode->i_mode))
- goto out_error;
-
- bf.l_whence = 0;
- bf.l_start = offset;
- bf.l_len = len;
-
- xfs_ilock(ip, XFS_IOLOCK_EXCL);
-
- if (mode & FALLOC_FL_PUNCH_HOLE)
- cmd = XFS_IOC_UNRESVSP;
-
- /* check the new inode size is valid before allocating */
- if (!(mode & FALLOC_FL_KEEP_SIZE) &&
- offset + len > i_size_read(inode)) {
- new_size = offset + len;
- error = inode_newsize_ok(inode, new_size);
- if (error)
- goto out_unlock;
- }
-
- error = -xfs_change_file_space(ip, cmd, &bf, 0, XFS_ATTR_NOLOCK);
- if (error)
- goto out_unlock;
-
- /* Change file size if needed */
- if (new_size) {
- struct iattr iattr;
-
- iattr.ia_valid = ATTR_SIZE;
- iattr.ia_size = new_size;
- error = -xfs_setattr(ip, &iattr, XFS_ATTR_NOLOCK);
- }
-
-out_unlock:
- xfs_iunlock(ip, XFS_IOLOCK_EXCL);
-out_error:
- return error;
-}
-
#define XFS_FIEMAP_FLAGS (FIEMAP_FLAG_SYNC|FIEMAP_FLAG_XATTR)
/*
@@ -653,7 +597,6 @@ static const struct inode_operations xfs_inode_operations = {
.getxattr = generic_getxattr,
.removexattr = generic_removexattr,
.listxattr = xfs_vn_listxattr,
- .fallocate = xfs_vn_fallocate,
.fiemap = xfs_vn_fiemap,
};
diff --git a/fs/xfs/linux-2.6/xfs_super.c b/fs/xfs/linux-2.6/xfs_super.c
index bd07f73..9731898 100644
--- a/fs/xfs/linux-2.6/xfs_super.c
+++ b/fs/xfs/linux-2.6/xfs_super.c
@@ -1414,7 +1414,7 @@ xfs_fs_freeze(
xfs_save_resvblks(mp);
xfs_quiesce_attr(mp);
- return -xfs_fs_log_dummy(mp, SYNC_WAIT);
+ return -xfs_fs_log_dummy(mp);
}
STATIC int
diff --git a/fs/xfs/linux-2.6/xfs_sync.c b/fs/xfs/linux-2.6/xfs_sync.c
index a02480d..e22f005 100644
--- a/fs/xfs/linux-2.6/xfs_sync.c
+++ b/fs/xfs/linux-2.6/xfs_sync.c
@@ -362,7 +362,7 @@ xfs_quiesce_data(
/* mark the log as covered if needed */
if (xfs_log_need_covered(mp))
- error2 = xfs_fs_log_dummy(mp, SYNC_WAIT);
+ error2 = xfs_fs_log_dummy(mp);
/* flush data-only devices */
if (mp->m_rtdev_targp)
@@ -503,13 +503,14 @@ xfs_sync_worker(
int error;
if (!(mp->m_flags & XFS_MOUNT_RDONLY)) {
- xfs_log_force(mp, 0);
- xfs_reclaim_inodes(mp, 0);
/* dgc: errors ignored here */
- error = xfs_qm_sync(mp, SYNC_TRYLOCK);
if (mp->m_super->s_frozen == SB_UNFROZEN &&
xfs_log_need_covered(mp))
- error = xfs_fs_log_dummy(mp, 0);
+ error = xfs_fs_log_dummy(mp);
+ else
+ xfs_log_force(mp, 0);
+ xfs_reclaim_inodes(mp, 0);
+ error = xfs_qm_sync(mp, SYNC_TRYLOCK);
}
mp->m_sync_seq++;
wake_up(&mp->m_wait_single_sync_task);
diff --git a/fs/xfs/linux-2.6/xfs_sysctl.c b/fs/xfs/linux-2.6/xfs_sysctl.c
index 7bb5092..ee3cee0 100644
--- a/fs/xfs/linux-2.6/xfs_sysctl.c
+++ b/fs/xfs/linux-2.6/xfs_sysctl.c
@@ -18,6 +18,7 @@
#include "xfs.h"
#include <linux/sysctl.h>
#include <linux/proc_fs.h>
+#include "xfs_error.h"
static struct ctl_table_header *xfs_table_header;
@@ -51,6 +52,26 @@ xfs_stats_clear_proc_handler(
return ret;
}
+
+STATIC int
+xfs_panic_mask_proc_handler(
+ ctl_table *ctl,
+ int write,
+ void __user *buffer,
+ size_t *lenp,
+ loff_t *ppos)
+{
+ int ret, *valp = ctl->data;
+
+ ret = proc_dointvec_minmax(ctl, write, buffer, lenp, ppos);
+ if (!ret && write) {
+ xfs_panic_mask = *valp;
+#ifdef DEBUG
+ xfs_panic_mask |= (XFS_PTAG_SHUTDOWN_CORRUPT | XFS_PTAG_LOGRES);
+#endif
+ }
+ return ret;
+}
#endif /* CONFIG_PROC_FS */
static ctl_table xfs_table[] = {
@@ -77,7 +98,7 @@ static ctl_table xfs_table[] = {
.data = &xfs_params.panic_mask.val,
.maxlen = sizeof(int),
.mode = 0644,
- .proc_handler = proc_dointvec_minmax,
+ .proc_handler = xfs_panic_mask_proc_handler,
.extra1 = &xfs_params.panic_mask.min,
.extra2 = &xfs_params.panic_mask.max
},
diff --git a/fs/xfs/linux-2.6/xfs_trace.h b/fs/xfs/linux-2.6/xfs_trace.h
index 647af2a..2d0bcb4 100644
--- a/fs/xfs/linux-2.6/xfs_trace.h
+++ b/fs/xfs/linux-2.6/xfs_trace.h
@@ -1759,6 +1759,39 @@ DEFINE_LOG_RECOVER_INO_ITEM(xfs_log_recover_inode_recover);
DEFINE_LOG_RECOVER_INO_ITEM(xfs_log_recover_inode_cancel);
DEFINE_LOG_RECOVER_INO_ITEM(xfs_log_recover_inode_skip);
+DECLARE_EVENT_CLASS(xfs_discard_class,
+ TP_PROTO(struct xfs_mount *mp, xfs_agnumber_t agno,
+ xfs_agblock_t agbno, xfs_extlen_t len),
+ TP_ARGS(mp, agno, agbno, len),
+ TP_STRUCT__entry(
+ __field(dev_t, dev)
+ __field(xfs_agnumber_t, agno)
+ __field(xfs_agblock_t, agbno)
+ __field(xfs_extlen_t, len)
+ ),
+ TP_fast_assign(
+ __entry->dev = mp->m_super->s_dev;
+ __entry->agno = agno;
+ __entry->agbno = agbno;
+ __entry->len = len;
+ ),
+ TP_printk("dev %d:%d agno %u agbno %u len %u\n",
+ MAJOR(__entry->dev), MINOR(__entry->dev),
+ __entry->agno,
+ __entry->agbno,
+ __entry->len)
+)
+
+#define DEFINE_DISCARD_EVENT(name) \
+DEFINE_EVENT(xfs_discard_class, name, \
+ TP_PROTO(struct xfs_mount *mp, xfs_agnumber_t agno, \
+ xfs_agblock_t agbno, xfs_extlen_t len), \
+ TP_ARGS(mp, agno, agbno, len))
+DEFINE_DISCARD_EVENT(xfs_discard_extent);
+DEFINE_DISCARD_EVENT(xfs_discard_toosmall);
+DEFINE_DISCARD_EVENT(xfs_discard_exclude);
+DEFINE_DISCARD_EVENT(xfs_discard_busy);
+
#endif /* _TRACE_XFS_H */
#undef TRACE_INCLUDE_PATH
diff --git a/fs/xfs/support/debug.c b/fs/xfs/support/debug.c
index 975aa10..0df8889 100644
--- a/fs/xfs/support/debug.c
+++ b/fs/xfs/support/debug.c
@@ -25,86 +25,78 @@
#include "xfs_mount.h"
#include "xfs_error.h"
-static char message[1024]; /* keep it off the stack */
-static DEFINE_SPINLOCK(xfs_err_lock);
-
-/* Translate from CE_FOO to KERN_FOO, err_level(CE_FOO) == KERN_FOO */
-#define XFS_MAX_ERR_LEVEL 7
-#define XFS_ERR_MASK ((1 << 3) - 1)
-static const char * const err_level[XFS_MAX_ERR_LEVEL+1] =
- {KERN_EMERG, KERN_ALERT, KERN_CRIT,
- KERN_ERR, KERN_WARNING, KERN_NOTICE,
- KERN_INFO, KERN_DEBUG};
-
void
-cmn_err(register int level, char *fmt, ...)
+cmn_err(
+ const char *lvl,
+ const char *fmt,
+ ...)
{
- char *fp = fmt;
- int len;
- ulong flags;
- va_list ap;
-
- level &= XFS_ERR_MASK;
- if (level > XFS_MAX_ERR_LEVEL)
- level = XFS_MAX_ERR_LEVEL;
- spin_lock_irqsave(&xfs_err_lock,flags);
- va_start(ap, fmt);
- if (*fmt == '!') fp++;
- len = vsnprintf(message, sizeof(message), fp, ap);
- if (len >= sizeof(message))
- len = sizeof(message) - 1;
- if (message[len-1] == '\n')
- message[len-1] = 0;
- printk("%s%s\n", err_level[level], message);
- va_end(ap);
- spin_unlock_irqrestore(&xfs_err_lock,flags);
- BUG_ON(level == CE_PANIC);
+ struct va_format vaf;
+ va_list args;
+
+ va_start(args, fmt);
+ vaf.fmt = fmt;
+ vaf.va = &args;
+
+ printk("%s%pV", lvl, &vaf);
+ va_end(args);
+
+ BUG_ON(strncmp(lvl, KERN_EMERG, strlen(KERN_EMERG)) == 0);
}
void
-xfs_fs_vcmn_err(
- int level,
+xfs_fs_cmn_err(
+ const char *lvl,
struct xfs_mount *mp,
- char *fmt,
- va_list ap)
+ const char *fmt,
+ ...)
{
- unsigned long flags;
- int len = 0;
+ struct va_format vaf;
+ va_list args;
- level &= XFS_ERR_MASK;
- if (level > XFS_MAX_ERR_LEVEL)
- level = XFS_MAX_ERR_LEVEL;
+ va_start(args, fmt);
+ vaf.fmt = fmt;
+ vaf.va = &args;
- spin_lock_irqsave(&xfs_err_lock,flags);
+ printk("%sFilesystem %s: %pV", lvl, mp->m_fsname, &vaf);
+ va_end(args);
- if (mp) {
- len = sprintf(message, "Filesystem \"%s\": ", mp->m_fsname);
+ BUG_ON(strncmp(lvl, KERN_EMERG, strlen(KERN_EMERG)) == 0);
+}
+
+/* All callers to xfs_cmn_err use CE_ALERT, so don't bother testing lvl */
+void
+xfs_cmn_err(
+ int panic_tag,
+ const char *lvl,
+ struct xfs_mount *mp,
+ const char *fmt,
+ ...)
+{
+ struct va_format vaf;
+ va_list args;
+ int do_panic = 0;
- /*
- * Skip the printk if we can't print anything useful
- * due to an over-long device name.
- */
- if (len >= sizeof(message))
- goto out;
+ if (xfs_panic_mask && (xfs_panic_mask & panic_tag)) {
+ printk(KERN_ALERT "XFS: Transforming an alert into a BUG.");
+ do_panic = 1;
}
- len = vsnprintf(message + len, sizeof(message) - len, fmt, ap);
- if (len >= sizeof(message))
- len = sizeof(message) - 1;
- if (message[len-1] == '\n')
- message[len-1] = 0;
+ va_start(args, fmt);
+ vaf.fmt = fmt;
+ vaf.va = &args;
- printk("%s%s\n", err_level[level], message);
- out:
- spin_unlock_irqrestore(&xfs_err_lock,flags);
+ printk(KERN_ALERT "Filesystem %s: %pV", mp->m_fsname, &vaf);
+ va_end(args);
- BUG_ON(level == CE_PANIC);
+ BUG_ON(do_panic);
}
void
assfail(char *expr, char *file, int line)
{
- printk("Assertion failed: %s, file: %s, line: %d\n", expr, file, line);
+ printk(KERN_CRIT "Assertion failed: %s, file: %s, line: %d\n", expr,
+ file, line);
BUG();
}
diff --git a/fs/xfs/support/debug.h b/fs/xfs/support/debug.h
index d2d2046..05699f6 100644
--- a/fs/xfs/support/debug.h
+++ b/fs/xfs/support/debug.h
@@ -20,15 +20,22 @@
#include <stdarg.h>
-#define CE_DEBUG 7 /* debug */
-#define CE_CONT 6 /* continuation */
-#define CE_NOTE 5 /* notice */
-#define CE_WARN 4 /* warning */
-#define CE_ALERT 1 /* alert */
-#define CE_PANIC 0 /* panic */
-
-extern void cmn_err(int, char *, ...)
- __attribute__ ((format (printf, 2, 3)));
+struct xfs_mount;
+
+#define CE_DEBUG KERN_DEBUG
+#define CE_CONT KERN_INFO
+#define CE_NOTE KERN_NOTICE
+#define CE_WARN KERN_WARNING
+#define CE_ALERT KERN_ALERT
+#define CE_PANIC KERN_EMERG
+
+void cmn_err(const char *lvl, const char *fmt, ...)
+ __attribute__ ((format (printf, 2, 3)));
+void xfs_fs_cmn_err( const char *lvl, struct xfs_mount *mp,
+ const char *fmt, ...) __attribute__ ((format (printf, 3, 4)));
+void xfs_cmn_err( int panic_tag, const char *lvl, struct xfs_mount *mp,
+ const char *fmt, ...) __attribute__ ((format (printf, 4, 5)));
+
extern void assfail(char *expr, char *f, int l);
#define ASSERT_ALWAYS(expr) \
diff --git a/fs/xfs/xfs_alloc.c b/fs/xfs/xfs_alloc.c
index fa8723f..f322798 100644
--- a/fs/xfs/xfs_alloc.c
+++ b/fs/xfs/xfs_alloc.c
@@ -41,10 +41,6 @@
#define XFSA_FIXUP_BNO_OK 1
#define XFSA_FIXUP_CNT_OK 2
-static int
-xfs_alloc_busy_search(struct xfs_mount *mp, xfs_agnumber_t agno,
- xfs_agblock_t bno, xfs_extlen_t len);
-
/*
* Prototypes for per-ag allocation routines
*/
@@ -94,7 +90,7 @@ xfs_alloc_lookup_ge(
* Lookup the first record less than or equal to [bno, len]
* in the btree given by cur.
*/
-STATIC int /* error */
+int /* error */
xfs_alloc_lookup_le(
struct xfs_btree_cur *cur, /* btree cursor */
xfs_agblock_t bno, /* starting block of extent */
@@ -127,7 +123,7 @@ xfs_alloc_update(
/*
* Get the data from the pointed-to record.
*/
-STATIC int /* error */
+int /* error */
xfs_alloc_get_rec(
struct xfs_btree_cur *cur, /* btree cursor */
xfs_agblock_t *bno, /* output: starting block of extent */
@@ -2615,7 +2611,7 @@ restart:
* will require a synchronous transaction, but it can still be
* used to distinguish between a partial or exact match.
*/
-static int
+int
xfs_alloc_busy_search(
struct xfs_mount *mp,
xfs_agnumber_t agno,
diff --git a/fs/xfs/xfs_alloc.h b/fs/xfs/xfs_alloc.h
index 895009a..0ab56b3 100644
--- a/fs/xfs/xfs_alloc.h
+++ b/fs/xfs/xfs_alloc.h
@@ -19,6 +19,7 @@
#define __XFS_ALLOC_H__
struct xfs_buf;
+struct xfs_btree_cur;
struct xfs_mount;
struct xfs_perag;
struct xfs_trans;
@@ -118,16 +119,16 @@ xfs_alloc_longest_free_extent(struct xfs_mount *mp,
struct xfs_perag *pag);
#ifdef __KERNEL__
-
void
-xfs_alloc_busy_insert(xfs_trans_t *tp,
- xfs_agnumber_t agno,
- xfs_agblock_t bno,
- xfs_extlen_t len);
+xfs_alloc_busy_insert(struct xfs_trans *tp, xfs_agnumber_t agno,
+ xfs_agblock_t bno, xfs_extlen_t len);
void
xfs_alloc_busy_clear(struct xfs_mount *mp, struct xfs_busy_extent *busyp);
+int
+xfs_alloc_busy_search(struct xfs_mount *mp, xfs_agnumber_t agno,
+ xfs_agblock_t bno, xfs_extlen_t len);
#endif /* __KERNEL__ */
/*
@@ -205,4 +206,18 @@ xfs_free_extent(
xfs_fsblock_t bno, /* starting block number of extent */
xfs_extlen_t len); /* length of extent */
+int /* error */
+xfs_alloc_lookup_le(
+ struct xfs_btree_cur *cur, /* btree cursor */
+ xfs_agblock_t bno, /* starting block of extent */
+ xfs_extlen_t len, /* length of extent */
+ int *stat); /* success/failure */
+
+int /* error */
+xfs_alloc_get_rec(
+ struct xfs_btree_cur *cur, /* btree cursor */
+ xfs_agblock_t *bno, /* output: starting block of extent */
+ xfs_extlen_t *len, /* output: length of extent */
+ int *stat); /* output: success/failure */
+
#endif /* __XFS_ALLOC_H__ */
diff --git a/fs/xfs/xfs_buf_item.c b/fs/xfs/xfs_buf_item.c
index ed2b65f..98c6f73 100644
--- a/fs/xfs/xfs_buf_item.c
+++ b/fs/xfs/xfs_buf_item.c
@@ -141,7 +141,6 @@ xfs_buf_item_log_check(
#define xfs_buf_item_log_check(x)
#endif
-STATIC void xfs_buf_error_relse(xfs_buf_t *bp);
STATIC void xfs_buf_do_callbacks(struct xfs_buf *bp);
/*
@@ -959,128 +958,76 @@ xfs_buf_do_callbacks(
*/
void
xfs_buf_iodone_callbacks(
- xfs_buf_t *bp)
+ struct xfs_buf *bp)
{
- xfs_log_item_t *lip;
- static ulong lasttime;
- static xfs_buftarg_t *lasttarg;
- xfs_mount_t *mp;
+ struct xfs_log_item *lip = bp->b_fspriv;
+ struct xfs_mount *mp = lip->li_mountp;
+ static ulong lasttime;
+ static xfs_buftarg_t *lasttarg;
- ASSERT(XFS_BUF_FSPRIVATE(bp, void *) != NULL);
- lip = XFS_BUF_FSPRIVATE(bp, xfs_log_item_t *);
+ if (likely(!XFS_BUF_GETERROR(bp)))
+ goto do_callbacks;
- if (XFS_BUF_GETERROR(bp) != 0) {
- /*
- * If we've already decided to shutdown the filesystem
- * because of IO errors, there's no point in giving this
- * a retry.
- */
- mp = lip->li_mountp;
- if (XFS_FORCED_SHUTDOWN(mp)) {
- ASSERT(XFS_BUF_TARGET(bp) == mp->m_ddev_targp);
- XFS_BUF_SUPER_STALE(bp);
- trace_xfs_buf_item_iodone(bp, _RET_IP_);
- xfs_buf_do_callbacks(bp);
- XFS_BUF_SET_FSPRIVATE(bp, NULL);
- XFS_BUF_CLR_IODONE_FUNC(bp);
- xfs_buf_ioend(bp, 0);
- return;
- }
+ /*
+ * If we've already decided to shutdown the filesystem because of
+ * I/O errors, there's no point in giving this a retry.
+ */
+ if (XFS_FORCED_SHUTDOWN(mp)) {
+ XFS_BUF_SUPER_STALE(bp);
+ trace_xfs_buf_item_iodone(bp, _RET_IP_);
+ goto do_callbacks;
+ }
- if ((XFS_BUF_TARGET(bp) != lasttarg) ||
- (time_after(jiffies, (lasttime + 5*HZ)))) {
- lasttime = jiffies;
- cmn_err(CE_ALERT, "Device %s, XFS metadata write error"
- " block 0x%llx in %s",
- XFS_BUFTARG_NAME(XFS_BUF_TARGET(bp)),
- (__uint64_t)XFS_BUF_ADDR(bp), mp->m_fsname);
- }
- lasttarg = XFS_BUF_TARGET(bp);
+ if (XFS_BUF_TARGET(bp) != lasttarg ||
+ time_after(jiffies, (lasttime + 5*HZ))) {
+ lasttime = jiffies;
+ cmn_err(CE_ALERT, "Device %s, XFS metadata write error"
+ " block 0x%llx in %s",
+ XFS_BUFTARG_NAME(XFS_BUF_TARGET(bp)),
+ (__uint64_t)XFS_BUF_ADDR(bp), mp->m_fsname);
+ }
+ lasttarg = XFS_BUF_TARGET(bp);
- if (XFS_BUF_ISASYNC(bp)) {
- /*
- * If the write was asynchronous then noone will be
- * looking for the error. Clear the error state
- * and write the buffer out again delayed write.
- *
- * XXXsup This is OK, so long as we catch these
- * before we start the umount; we don't want these
- * DELWRI metadata bufs to be hanging around.
- */
- XFS_BUF_ERROR(bp,0); /* errno of 0 unsets the flag */
-
- if (!(XFS_BUF_ISSTALE(bp))) {
- XFS_BUF_DELAYWRITE(bp);
- XFS_BUF_DONE(bp);
- XFS_BUF_SET_START(bp);
- }
- ASSERT(XFS_BUF_IODONE_FUNC(bp));
- trace_xfs_buf_item_iodone_async(bp, _RET_IP_);
- xfs_buf_relse(bp);
- } else {
- /*
- * If the write of the buffer was not asynchronous,
- * then we want to make sure to return the error
- * to the caller of bwrite(). Because of this we
- * cannot clear the B_ERROR state at this point.
- * Instead we install a callback function that
- * will be called when the buffer is released, and
- * that routine will clear the error state and
- * set the buffer to be written out again after
- * some delay.
- */
- /* We actually overwrite the existing b-relse
- function at times, but we're gonna be shutting down
- anyway. */
- XFS_BUF_SET_BRELSE_FUNC(bp,xfs_buf_error_relse);
+ /*
+ * If the write was asynchronous then noone will be looking for the
+ * error. Clear the error state and write the buffer out again.
+ *
+ * During sync or umount we'll write all pending buffers again
+ * synchronous, which will catch these errors if they keep hanging
+ * around.
+ */
+ if (XFS_BUF_ISASYNC(bp)) {
+ XFS_BUF_ERROR(bp, 0); /* errno of 0 unsets the flag */
+
+ if (!XFS_BUF_ISSTALE(bp)) {
+ XFS_BUF_DELAYWRITE(bp);
XFS_BUF_DONE(bp);
- XFS_BUF_FINISH_IOWAIT(bp);
+ XFS_BUF_SET_START(bp);
}
+ ASSERT(XFS_BUF_IODONE_FUNC(bp));
+ trace_xfs_buf_item_iodone_async(bp, _RET_IP_);
+ xfs_buf_relse(bp);
return;
}
- xfs_buf_do_callbacks(bp);
- XFS_BUF_SET_FSPRIVATE(bp, NULL);
- XFS_BUF_CLR_IODONE_FUNC(bp);
- xfs_buf_ioend(bp, 0);
-}
-
-/*
- * This is a callback routine attached to a buffer which gets an error
- * when being written out synchronously.
- */
-STATIC void
-xfs_buf_error_relse(
- xfs_buf_t *bp)
-{
- xfs_log_item_t *lip;
- xfs_mount_t *mp;
-
- lip = XFS_BUF_FSPRIVATE(bp, xfs_log_item_t *);
- mp = (xfs_mount_t *)lip->li_mountp;
- ASSERT(XFS_BUF_TARGET(bp) == mp->m_ddev_targp);
-
+ /*
+ * If the write of the buffer was synchronous, we want to make
+ * sure to return the error to the caller of xfs_bwrite().
+ */
XFS_BUF_STALE(bp);
XFS_BUF_DONE(bp);
XFS_BUF_UNDELAYWRITE(bp);
- XFS_BUF_ERROR(bp,0);
trace_xfs_buf_error_relse(bp, _RET_IP_);
+ xfs_force_shutdown(mp, SHUTDOWN_META_IO_ERROR);
- if (! XFS_FORCED_SHUTDOWN(mp))
- xfs_force_shutdown(mp, SHUTDOWN_META_IO_ERROR);
- /*
- * We have to unpin the pinned buffers so do the
- * callbacks.
- */
+do_callbacks:
xfs_buf_do_callbacks(bp);
XFS_BUF_SET_FSPRIVATE(bp, NULL);
XFS_BUF_CLR_IODONE_FUNC(bp);
- XFS_BUF_SET_BRELSE_FUNC(bp,NULL);
- xfs_buf_relse(bp);
+ xfs_buf_ioend(bp, 0);
}
-
/*
* This is the iodone() function for buffers which have been
* logged. It is called when they are eventually flushed out.
diff --git a/fs/xfs/xfs_error.c b/fs/xfs/xfs_error.c
index c78cc6a..4c7db74 100644
--- a/fs/xfs/xfs_error.c
+++ b/fs/xfs/xfs_error.c
@@ -152,37 +152,6 @@ xfs_errortag_clearall(xfs_mount_t *mp, int loud)
}
#endif /* DEBUG */
-
-void
-xfs_fs_cmn_err(int level, xfs_mount_t *mp, char *fmt, ...)
-{
- va_list ap;
-
- va_start(ap, fmt);
- xfs_fs_vcmn_err(level, mp, fmt, ap);
- va_end(ap);
-}
-
-void
-xfs_cmn_err(int panic_tag, int level, xfs_mount_t *mp, char *fmt, ...)
-{
- va_list ap;
-
-#ifdef DEBUG
- xfs_panic_mask |= (XFS_PTAG_SHUTDOWN_CORRUPT | XFS_PTAG_LOGRES);
-#endif
-
- if (xfs_panic_mask && (xfs_panic_mask & panic_tag)
- && (level & CE_ALERT)) {
- level &= ~CE_ALERT;
- level |= CE_PANIC;
- cmn_err(CE_ALERT, "XFS: Transforming an alert into a BUG.");
- }
- va_start(ap, fmt);
- xfs_fs_vcmn_err(level, mp, fmt, ap);
- va_end(ap);
-}
-
void
xfs_error_report(
const char *tag,
diff --git a/fs/xfs/xfs_error.h b/fs/xfs/xfs_error.h
index f338847..10dce54 100644
--- a/fs/xfs/xfs_error.h
+++ b/fs/xfs/xfs_error.h
@@ -136,8 +136,8 @@ extern int xfs_error_test(int, int *, char *, int, char *, unsigned long);
xfs_error_test((tag), (mp)->m_fixedfsid, "expr", __LINE__, __FILE__, \
(rf))))
-extern int xfs_errortag_add(int error_tag, xfs_mount_t *mp);
-extern int xfs_errortag_clearall(xfs_mount_t *mp, int loud);
+extern int xfs_errortag_add(int error_tag, struct xfs_mount *mp);
+extern int xfs_errortag_clearall(struct xfs_mount *mp, int loud);
#else
#define XFS_TEST_ERROR(expr, mp, tag, rf) (expr)
#define xfs_errortag_add(tag, mp) (ENOSYS)
@@ -162,21 +162,15 @@ extern int xfs_errortag_clearall(xfs_mount_t *mp, int loud);
struct xfs_mount;
-extern void xfs_fs_vcmn_err(int level, struct xfs_mount *mp,
- char *fmt, va_list ap)
- __attribute__ ((format (printf, 3, 0)));
-extern void xfs_cmn_err(int panic_tag, int level, struct xfs_mount *mp,
- char *fmt, ...)
- __attribute__ ((format (printf, 4, 5)));
-extern void xfs_fs_cmn_err(int level, struct xfs_mount *mp, char *fmt, ...)
- __attribute__ ((format (printf, 3, 4)));
-
extern void xfs_hex_dump(void *p, int length);
#define xfs_fs_repair_cmn_err(level, mp, fmt, args...) \
xfs_fs_cmn_err(level, mp, fmt " Unmount and run xfs_repair.", ## args)
#define xfs_fs_mount_cmn_err(f, fmt, args...) \
- ((f & XFS_MFSI_QUIET)? (void)0 : cmn_err(CE_WARN, "XFS: " fmt, ## args))
+ do { \
+ if (!(f & XFS_MFSI_QUIET)) \
+ cmn_err(CE_WARN, "XFS: " fmt, ## args); \
+ } while (0)
#endif /* __XFS_ERROR_H__ */
diff --git a/fs/xfs/xfs_fsops.c b/fs/xfs/xfs_fsops.c
index f56d30e..cec89dd 100644
--- a/fs/xfs/xfs_fsops.c
+++ b/fs/xfs/xfs_fsops.c
@@ -612,12 +612,13 @@ out:
*
* We cannot use an inode here for this - that will push dirty state back up
* into the VFS and then periodic inode flushing will prevent log covering from
- * making progress. Hence we log a field in the superblock instead.
+ * making progress. Hence we log a field in the superblock instead and use a
+ * synchronous transaction to ensure the superblock is immediately unpinned
+ * and can be written back.
*/
int
xfs_fs_log_dummy(
- xfs_mount_t *mp,
- int flags)
+ xfs_mount_t *mp)
{
xfs_trans_t *tp;
int error;
@@ -632,8 +633,7 @@ xfs_fs_log_dummy(
/* log the UUID because it is an unchanging field */
xfs_mod_sb(tp, XFS_SB_UUID);
- if (flags & SYNC_WAIT)
- xfs_trans_set_sync(tp);
+ xfs_trans_set_sync(tp);
return xfs_trans_commit(tp, 0);
}
diff --git a/fs/xfs/xfs_fsops.h b/fs/xfs/xfs_fsops.h
index a786c52..1b6a98b 100644
--- a/fs/xfs/xfs_fsops.h
+++ b/fs/xfs/xfs_fsops.h
@@ -25,6 +25,6 @@ extern int xfs_fs_counts(xfs_mount_t *mp, xfs_fsop_counts_t *cnt);
extern int xfs_reserve_blocks(xfs_mount_t *mp, __uint64_t *inval,
xfs_fsop_resblks_t *outval);
extern int xfs_fs_goingdown(xfs_mount_t *mp, __uint32_t inflags);
-extern int xfs_fs_log_dummy(xfs_mount_t *mp, int flags);
+extern int xfs_fs_log_dummy(struct xfs_mount *mp);
#endif /* __XFS_FSOPS_H__ */
diff --git a/fs/xfs/xfs_log.c b/fs/xfs/xfs_log.c
index 0bf24b1..ae6fef1f 100644
--- a/fs/xfs/xfs_log.c
+++ b/fs/xfs/xfs_log.c
@@ -377,7 +377,7 @@ xfs_log_mount(
cmn_err(CE_NOTE, "XFS mounting filesystem %s", mp->m_fsname);
else {
cmn_err(CE_NOTE,
- "!Mounting filesystem \"%s\" in no-recovery mode. Filesystem will be inconsistent.",
+ "Mounting filesystem \"%s\" in no-recovery mode. Filesystem will be inconsistent.",
mp->m_fsname);
ASSERT(mp->m_flags & XFS_MOUNT_RDONLY);
}
diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c
index 204d8e5..aa0ebb7 100644
--- a/fs/xfs/xfs_log_recover.c
+++ b/fs/xfs/xfs_log_recover.c
@@ -3800,7 +3800,7 @@ xlog_recover_finish(
log->l_flags &= ~XLOG_RECOVERY_NEEDED;
} else {
cmn_err(CE_DEBUG,
- "!Ending clean XFS mount for filesystem: %s\n",
+ "Ending clean XFS mount for filesystem: %s\n",
log->l_mp->m_fsname);
}
return 0;
diff --git a/fs/xfs/xfs_trans.c b/fs/xfs/xfs_trans.c
index f80a067..33dbc4e 100644
--- a/fs/xfs/xfs_trans.c
+++ b/fs/xfs/xfs_trans.c
@@ -1137,7 +1137,7 @@ out_undo_fdblocks:
if (blkdelta)
xfs_icsb_modify_counters(mp, XFS_SBS_FDBLOCKS, -blkdelta, rsvd);
out:
- ASSERT(error = 0);
+ ASSERT(error == 0);
return;
}
diff --git a/include/acpi/acexcep.h b/include/acpi/acexcep.h
index 17714be..5b6c391 100644
--- a/include/acpi/acexcep.h
+++ b/include/acpi/acexcep.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/include/acpi/acnames.h b/include/acpi/acnames.h
index 9cf736e..fc1575f 100644
--- a/include/acpi/acnames.h
+++ b/include/acpi/acnames.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/include/acpi/acoutput.h b/include/acpi/acoutput.h
index bc4a6de..ef1cef7 100644
--- a/include/acpi/acoutput.h
+++ b/include/acpi/acoutput.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/include/acpi/acpi.h b/include/acpi/acpi.h
index a091cab..de39915 100644
--- a/include/acpi/acpi.h
+++ b/include/acpi/acpi.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h
index 359ef11..78ca429 100644
--- a/include/acpi/acpi_bus.h
+++ b/include/acpi/acpi_bus.h
@@ -148,9 +148,7 @@ struct acpi_device_flags {
u32 suprise_removal_ok:1;
u32 power_manageable:1;
u32 performance_manageable:1;
- u32 wake_capable:1; /* Wakeup(_PRW) supported? */
- u32 force_power_state:1;
- u32 reserved:22;
+ u32 reserved:24;
};
/* File System */
@@ -242,20 +240,14 @@ struct acpi_device_perf {
struct acpi_device_wakeup_flags {
u8 valid:1; /* Can successfully enable wakeup? */
u8 run_wake:1; /* Run-Wake GPE devices */
- u8 always_enabled:1; /* Run-wake devices that are always enabled */
u8 notifier_present:1; /* Wake-up notify handler has been installed */
};
-struct acpi_device_wakeup_state {
- u8 enabled:1;
-};
-
struct acpi_device_wakeup {
acpi_handle gpe_device;
u64 gpe_number;
u64 sleep_state;
struct acpi_handle_list resources;
- struct acpi_device_wakeup_state state;
struct acpi_device_wakeup_flags flags;
int prepare_count;
int run_wake_count;
@@ -328,8 +320,8 @@ void acpi_bus_data_handler(acpi_handle handle, void *context);
acpi_status acpi_bus_get_status_handle(acpi_handle handle,
unsigned long long *sta);
int acpi_bus_get_status(struct acpi_device *device);
-int acpi_bus_get_power(acpi_handle handle, int *state);
int acpi_bus_set_power(acpi_handle handle, int state);
+int acpi_bus_update_power(acpi_handle handle, int *state_p);
bool acpi_bus_power_manageable(acpi_handle handle);
bool acpi_bus_can_wakeup(acpi_handle handle);
#ifdef CONFIG_ACPI_PROC_EVENT
diff --git a/include/acpi/acpiosxf.h b/include/acpi/acpiosxf.h
index 65b3f58..a3252a5 100644
--- a/include/acpi/acpiosxf.h
+++ b/include/acpi/acpiosxf.h
@@ -8,7 +8,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h
index 53b7cfd..e46ec95 100644
--- a/include/acpi/acpixf.h
+++ b/include/acpi/acpixf.h
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -47,7 +47,7 @@
/* Current ACPICA subsystem version in YYYYMMDD format */
-#define ACPI_CA_VERSION 0x20101013
+#define ACPI_CA_VERSION 0x20110112
#include "actypes.h"
#include "actbl.h"
@@ -229,6 +229,10 @@ acpi_status
acpi_install_initialization_handler(acpi_init_handler handler, u32 function);
acpi_status
+acpi_install_global_event_handler(ACPI_GBL_EVENT_HANDLER handler,
+ void *context);
+
+acpi_status
acpi_install_fixed_event_handler(u32 acpi_event,
acpi_event_handler handler, void *context);
@@ -258,11 +262,11 @@ acpi_remove_address_space_handler(acpi_handle device,
acpi_status
acpi_install_gpe_handler(acpi_handle gpe_device,
u32 gpe_number,
- u32 type, acpi_event_handler address, void *context);
+ u32 type, acpi_gpe_handler address, void *context);
acpi_status
acpi_remove_gpe_handler(acpi_handle gpe_device,
- u32 gpe_number, acpi_event_handler address);
+ u32 gpe_number, acpi_gpe_handler address);
#ifdef ACPI_FUTURE_USAGE
acpi_status acpi_install_exception_handler(acpi_exception_handler handler);
@@ -292,11 +296,13 @@ acpi_status acpi_enable_gpe(acpi_handle gpe_device, u32 gpe_number);
acpi_status acpi_disable_gpe(acpi_handle gpe_device, u32 gpe_number);
-acpi_status acpi_gpe_can_wake(acpi_handle gpe_device, u32 gpe_number);
-
acpi_status acpi_clear_gpe(acpi_handle gpe_device, u32 gpe_number);
-acpi_status acpi_gpe_wakeup(acpi_handle gpe_device, u32 gpe_number, u8 action);
+acpi_status
+acpi_setup_gpe_for_wake(acpi_handle parent_device,
+ acpi_handle gpe_device, u32 gpe_number);
+
+acpi_status acpi_set_gpe_wake_mask(acpi_handle gpe_device, u32 gpe_number, u8 action);
acpi_status
acpi_get_gpe_status(acpi_handle gpe_device,
@@ -315,7 +321,7 @@ acpi_install_gpe_block(acpi_handle gpe_device,
acpi_status acpi_remove_gpe_block(acpi_handle gpe_device);
-acpi_status acpi_update_gpes(void);
+acpi_status acpi_update_all_gpes(void);
/*
* Resource interfaces
diff --git a/include/acpi/acrestyp.h b/include/acpi/acrestyp.h
index e552635..0a66cc4 100644
--- a/include/acpi/acrestyp.h
+++ b/include/acpi/acrestyp.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/include/acpi/actbl.h b/include/acpi/actbl.h
index ad20016..7e42bfe 100644
--- a/include/acpi/actbl.h
+++ b/include/acpi/actbl.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/include/acpi/actbl1.h b/include/acpi/actbl1.h
index cd77aa7..7504bc9 100644
--- a/include/acpi/actbl1.h
+++ b/include/acpi/actbl1.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/include/acpi/actbl2.h b/include/acpi/actbl2.h
index d4136b2..0fc15df 100644
--- a/include/acpi/actbl2.h
+++ b/include/acpi/actbl2.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/include/acpi/actypes.h b/include/acpi/actypes.h
index 2b134b6..64f838b 100644
--- a/include/acpi/actypes.h
+++ b/include/acpi/actypes.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -656,33 +656,34 @@ typedef u32 acpi_event_status;
#define ACPI_GPE_MAX 0xFF
#define ACPI_NUM_GPE 256
-/* Actions for acpi_gpe_wakeup, acpi_hw_low_set_gpe */
+/* Actions for acpi_set_gpe_wake_mask, acpi_hw_low_set_gpe */
#define ACPI_GPE_ENABLE 0
#define ACPI_GPE_DISABLE 1
-#define ACPI_GPE_COND_ENABLE 2
+#define ACPI_GPE_CONDITIONAL_ENABLE 2
/*
* GPE info flags - Per GPE
- * +-------+---+-+-+
- * | 7:4 |3:2|1|0|
- * +-------+---+-+-+
- * | | | |
- * | | | +--- Interrupt type: edge or level triggered
- * | | +----- GPE can wake the system
- * | +-------- Type of dispatch:to method, handler, or none
- * +-------------- <Reserved>
+ * +-------+-+-+---+
+ * | 7:4 |3|2|1:0|
+ * +-------+-+-+---+
+ * | | | |
+ * | | | +-- Type of dispatch:to method, handler, notify, or none
+ * | | +----- Interrupt type: edge or level triggered
+ * | +------- Is a Wake GPE
+ * +------------ <Reserved>
*/
-#define ACPI_GPE_XRUPT_TYPE_MASK (u8) 0x01
-#define ACPI_GPE_LEVEL_TRIGGERED (u8) 0x01
-#define ACPI_GPE_EDGE_TRIGGERED (u8) 0x00
+#define ACPI_GPE_DISPATCH_NONE (u8) 0x00
+#define ACPI_GPE_DISPATCH_METHOD (u8) 0x01
+#define ACPI_GPE_DISPATCH_HANDLER (u8) 0x02
+#define ACPI_GPE_DISPATCH_NOTIFY (u8) 0x03
+#define ACPI_GPE_DISPATCH_MASK (u8) 0x03
-#define ACPI_GPE_CAN_WAKE (u8) 0x02
+#define ACPI_GPE_LEVEL_TRIGGERED (u8) 0x04
+#define ACPI_GPE_EDGE_TRIGGERED (u8) 0x00
+#define ACPI_GPE_XRUPT_TYPE_MASK (u8) 0x04
-#define ACPI_GPE_DISPATCH_MASK (u8) 0x0C
-#define ACPI_GPE_DISPATCH_HANDLER (u8) 0x04
-#define ACPI_GPE_DISPATCH_METHOD (u8) 0x08
-#define ACPI_GPE_DISPATCH_NOT_USED (u8) 0x00
+#define ACPI_GPE_CAN_WAKE (u8) 0x08
/*
* Flags for GPE and Lock interfaces
@@ -894,9 +895,20 @@ typedef void
/*
* Various handlers and callback procedures
*/
+typedef
+void (*ACPI_GBL_EVENT_HANDLER) (u32 event_type,
+ acpi_handle device,
+ u32 event_number, void *context);
+
+#define ACPI_EVENT_TYPE_GPE 0
+#define ACPI_EVENT_TYPE_FIXED 1
+
typedef u32(*acpi_event_handler) (void *context);
typedef
+u32 (*acpi_gpe_handler) (acpi_handle gpe_device, u32 gpe_number, void *context);
+
+typedef
void (*acpi_notify_handler) (acpi_handle device, u32 value, void *context);
typedef
@@ -951,6 +963,10 @@ u32 (*acpi_interface_handler) (acpi_string interface_name, u32 supported);
#define ACPI_INTERRUPT_NOT_HANDLED 0x00
#define ACPI_INTERRUPT_HANDLED 0x01
+/* GPE handler return values */
+
+#define ACPI_REENABLE_GPE 0x80
+
/* Length of 32-bit EISAID values when converted back to a string */
#define ACPI_EISAID_STRING_SIZE 8 /* Includes null terminator */
diff --git a/include/acpi/apei.h b/include/acpi/apei.h
index b336502..c4dbb13 100644
--- a/include/acpi/apei.h
+++ b/include/acpi/apei.h
@@ -19,6 +19,12 @@
extern int hest_disable;
extern int erst_disable;
+#ifdef CONFIG_ACPI_APEI
+void __init acpi_hest_init(void);
+#else
+static inline void acpi_hest_init(void) { return; }
+#endif
+
typedef int (*apei_hest_func_t)(struct acpi_hest_header *hest_hdr, void *data);
int apei_hest_parse(apei_hest_func_t func, void *data);
diff --git a/include/acpi/platform/acenv.h b/include/acpi/platform/acenv.h
index a3e334a..5af3ed5 100644
--- a/include/acpi/platform/acenv.h
+++ b/include/acpi/platform/acenv.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/include/acpi/platform/acgcc.h b/include/acpi/platform/acgcc.h
index 5dcb953..e228893 100644
--- a/include/acpi/platform/acgcc.h
+++ b/include/acpi/platform/acgcc.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/include/acpi/platform/aclinux.h b/include/acpi/platform/aclinux.h
index 572189e..5d2a5e9 100644
--- a/include/acpi/platform/aclinux.h
+++ b/include/acpi/platform/aclinux.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2011, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/include/acpi/processor.h b/include/acpi/processor.h
index 1b62102..55192ac 100644
--- a/include/acpi/processor.h
+++ b/include/acpi/processor.h
@@ -324,6 +324,12 @@ int acpi_processor_tstate_has_changed(struct acpi_processor *pr);
int acpi_processor_get_throttling_info(struct acpi_processor *pr);
extern int acpi_processor_set_throttling(struct acpi_processor *pr,
int state, bool force);
+/*
+ * Reevaluate whether the T-state is invalid after one cpu is
+ * onlined/offlined. In such case the flags.throttling will be updated.
+ */
+extern void acpi_processor_reevaluate_tstate(struct acpi_processor *pr,
+ unsigned long action);
extern const struct file_operations acpi_processor_throttling_fops;
extern void acpi_processor_throttling_init(void);
/* in processor_idle.c */
diff --git a/include/asm-generic/pgtable.h b/include/asm-generic/pgtable.h
index f1eddf7..31b6188 100644
--- a/include/asm-generic/pgtable.h
+++ b/include/asm-generic/pgtable.h
@@ -87,14 +87,6 @@ static inline pmd_t pmdp_get_and_clear(struct mm_struct *mm,
pmd_clear(mm, address, pmdp);
return pmd;
})
-#else /* CONFIG_TRANSPARENT_HUGEPAGE */
-static inline pmd_t pmdp_get_and_clear(struct mm_struct *mm,
- unsigned long address,
- pmd_t *pmdp)
-{
- BUG();
- return __pmd(0);
-}
#endif /* CONFIG_TRANSPARENT_HUGEPAGE */
#endif
@@ -163,9 +155,9 @@ static inline void pmdp_set_wrprotect(struct mm_struct *mm,
#endif
#ifndef __HAVE_ARCH_PMDP_SPLITTING_FLUSH
-extern pmd_t pmdp_clear_flush(struct vm_area_struct *vma,
- unsigned long address,
- pmd_t *pmdp);
+extern pmd_t pmdp_splitting_flush(struct vm_area_struct *vma,
+ unsigned long address,
+ pmd_t *pmdp);
#endif
#ifndef __HAVE_ARCH_PTE_SAME
diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
index 6864933..6ebb810 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -364,6 +364,13 @@
VMLINUX_SYMBOL(__start___param) = .; \
*(__param) \
VMLINUX_SYMBOL(__stop___param) = .; \
+ } \
+ \
+ /* Built-in module versions. */ \
+ __modver : AT(ADDR(__modver) - LOAD_OFFSET) { \
+ VMLINUX_SYMBOL(__start___modver) = .; \
+ *(__modver) \
+ VMLINUX_SYMBOL(__stop___modver) = .; \
. = ALIGN((align)); \
VMLINUX_SYMBOL(__end_rodata) = .; \
} \
diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h
index aac27bd..f22e7fe 100644
--- a/include/drm/drm_fb_helper.h
+++ b/include/drm/drm_fb_helper.h
@@ -121,6 +121,9 @@ int drm_fb_helper_setcolreg(unsigned regno,
void drm_fb_helper_restore(void);
void drm_fb_helper_fill_var(struct fb_info *info, struct drm_fb_helper *fb_helper,
uint32_t fb_width, uint32_t fb_height);
+void drm_fb_helper_fill_fix(struct fb_info *info, uint32_t pitch,
+ uint32_t depth);
+
int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info);
bool drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper);
diff --git a/include/drm/radeon_drm.h b/include/drm/radeon_drm.h
index e95a86b..e5c607a 100644
--- a/include/drm/radeon_drm.h
+++ b/include/drm/radeon_drm.h
@@ -907,6 +907,7 @@ struct drm_radeon_cs {
#define RADEON_INFO_TILING_CONFIG 0x06
#define RADEON_INFO_WANT_HYPERZ 0x07
#define RADEON_INFO_WANT_CMASK 0x08 /* get access to CMASK on r300 */
+#define RADEON_INFO_CLOCK_CRYSTAL_FREQ 0x09 /* clock crystal frequency */
struct drm_radeon_info {
uint32_t request;
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index 67c91b4..a2e910e 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -306,9 +306,6 @@ extern acpi_status acpi_pci_osc_control_set(acpi_handle handle,
u32 *mask, u32 req);
extern void acpi_early_init(void);
-int acpi_os_map_generic_address(struct acpi_generic_address *addr);
-void acpi_os_unmap_generic_address(struct acpi_generic_address *addr);
-
#else /* !CONFIG_ACPI */
#define acpi_disabled 1
@@ -352,4 +349,14 @@ static inline int acpi_table_parse(char *id,
return -1;
}
#endif /* !CONFIG_ACPI */
+
+#ifdef CONFIG_ACPI_SLEEP
+int suspend_nvs_register(unsigned long start, unsigned long size);
+#else
+static inline int suspend_nvs_register(unsigned long a, unsigned long b)
+{
+ return 0;
+}
+#endif
+
#endif /*_LINUX_ACPI_H*/
diff --git a/include/linux/acpi_io.h b/include/linux/acpi_io.h
new file mode 100644
index 0000000..7180013
--- /dev/null
+++ b/include/linux/acpi_io.h
@@ -0,0 +1,16 @@
+#ifndef _ACPI_IO_H_
+#define _ACPI_IO_H_
+
+#include <linux/io.h>
+#include <acpi/acpi.h>
+
+static inline void __iomem *acpi_os_ioremap(acpi_physical_address phys,
+ acpi_size size)
+{
+ return ioremap_cache(phys, size);
+}
+
+int acpi_os_map_generic_address(struct acpi_generic_address *addr);
+void acpi_os_unmap_generic_address(struct acpi_generic_address *addr);
+
+#endif
diff --git a/include/linux/amba/pl08x.h b/include/linux/amba/pl08x.h
index 521a0f8..3111385 100644
--- a/include/linux/amba/pl08x.h
+++ b/include/linux/amba/pl08x.h
@@ -12,7 +12,6 @@
*
* Please credit ARM.com
* Documentation: ARM DDI 0196D
- *
*/
#ifndef AMBA_PL08X_H
@@ -22,6 +21,15 @@
#include <linux/dmaengine.h>
#include <linux/interrupt.h>
+struct pl08x_lli;
+struct pl08x_driver_data;
+
+/* Bitmasks for selecting AHB ports for DMA transfers */
+enum {
+ PL08X_AHB1 = (1 << 0),
+ PL08X_AHB2 = (1 << 1)
+};
+
/**
* struct pl08x_channel_data - data structure to pass info between
* platform and PL08x driver regarding channel configuration
@@ -46,8 +54,10 @@
* @circular_buffer: whether the buffer passed in is circular and
* shall simply be looped round round (like a record baby round
* round round round)
- * @single: the device connected to this channel will request single
- * DMA transfers, not bursts. (Bursts are default.)
+ * @single: the device connected to this channel will request single DMA
+ * transfers, not bursts. (Bursts are default.)
+ * @periph_buses: the device connected to this channel is accessible via
+ * these buses (use PL08X_AHB1 | PL08X_AHB2).
*/
struct pl08x_channel_data {
char *bus_id;
@@ -55,10 +65,10 @@ struct pl08x_channel_data {
int max_signal;
u32 muxval;
u32 cctl;
- u32 ccfg;
dma_addr_t addr;
bool circular_buffer;
bool single;
+ u8 periph_buses;
};
/**
@@ -67,24 +77,23 @@ struct pl08x_channel_data {
* @addr: current address
* @maxwidth: the maximum width of a transfer on this bus
* @buswidth: the width of this bus in bytes: 1, 2 or 4
- * @fill_bytes: bytes required to fill to the next bus memory
- * boundary
+ * @fill_bytes: bytes required to fill to the next bus memory boundary
*/
struct pl08x_bus_data {
dma_addr_t addr;
u8 maxwidth;
u8 buswidth;
- u32 fill_bytes;
+ size_t fill_bytes;
};
/**
* struct pl08x_phy_chan - holder for the physical channels
* @id: physical index to this channel
* @lock: a lock to use when altering an instance of this struct
- * @signal: the physical signal (aka channel) serving this
- * physical channel right now
- * @serving: the virtual channel currently being served by this
- * physical channel
+ * @signal: the physical signal (aka channel) serving this physical channel
+ * right now
+ * @serving: the virtual channel currently being served by this physical
+ * channel
*/
struct pl08x_phy_chan {
unsigned int id;
@@ -92,11 +101,6 @@ struct pl08x_phy_chan {
spinlock_t lock;
int signal;
struct pl08x_dma_chan *serving;
- u32 csrc;
- u32 cdst;
- u32 clli;
- u32 cctl;
- u32 ccfg;
};
/**
@@ -108,26 +112,23 @@ struct pl08x_txd {
struct dma_async_tx_descriptor tx;
struct list_head node;
enum dma_data_direction direction;
- struct pl08x_bus_data srcbus;
- struct pl08x_bus_data dstbus;
- int len;
+ dma_addr_t src_addr;
+ dma_addr_t dst_addr;
+ size_t len;
dma_addr_t llis_bus;
- void *llis_va;
- struct pl08x_channel_data *cd;
- bool active;
+ struct pl08x_lli *llis_va;
+ /* Default cctl value for LLIs */
+ u32 cctl;
/*
* Settings to be put into the physical channel when we
- * trigger this txd
+ * trigger this txd. Other registers are in llis_va[0].
*/
- u32 csrc;
- u32 cdst;
- u32 clli;
- u32 cctl;
+ u32 ccfg;
};
/**
- * struct pl08x_dma_chan_state - holds the PL08x specific virtual
- * channel states
+ * struct pl08x_dma_chan_state - holds the PL08x specific virtual channel
+ * states
* @PL08X_CHAN_IDLE: the channel is idle
* @PL08X_CHAN_RUNNING: the channel has allocated a physical transport
* channel and is running a transfer on it
@@ -147,6 +148,8 @@ enum pl08x_dma_chan_state {
* struct pl08x_dma_chan - this structure wraps a DMA ENGINE channel
* @chan: wrappped abstract channel
* @phychan: the physical channel utilized by this channel, if there is one
+ * @phychan_hold: if non-zero, hold on to the physical channel even if we
+ * have no pending entries
* @tasklet: tasklet scheduled by the IRQ to handle actual work etc
* @name: name of channel
* @cd: channel platform data
@@ -154,53 +157,49 @@ enum pl08x_dma_chan_state {
* @runtime_direction: current direction of this channel according to
* runtime config
* @lc: last completed transaction on this channel
- * @desc_list: queued transactions pending on this channel
+ * @pend_list: queued transactions pending on this channel
* @at: active transaction on this channel
- * @lockflags: sometimes we let a lock last between two function calls,
- * especially prep/submit, and then we need to store the IRQ flags
- * in the channel state, here
* @lock: a lock for this channel data
* @host: a pointer to the host (internal use)
* @state: whether the channel is idle, paused, running etc
* @slave: whether this channel is a device (slave) or for memcpy
- * @waiting: a TX descriptor on this channel which is waiting for
- * a physical channel to become available
+ * @waiting: a TX descriptor on this channel which is waiting for a physical
+ * channel to become available
*/
struct pl08x_dma_chan {
struct dma_chan chan;
struct pl08x_phy_chan *phychan;
+ int phychan_hold;
struct tasklet_struct tasklet;
char *name;
struct pl08x_channel_data *cd;
dma_addr_t runtime_addr;
enum dma_data_direction runtime_direction;
- atomic_t last_issued;
dma_cookie_t lc;
- struct list_head desc_list;
+ struct list_head pend_list;
struct pl08x_txd *at;
- unsigned long lockflags;
spinlock_t lock;
- void *host;
+ struct pl08x_driver_data *host;
enum pl08x_dma_chan_state state;
bool slave;
struct pl08x_txd *waiting;
};
/**
- * struct pl08x_platform_data - the platform configuration for the
- * PL08x PrimeCells.
+ * struct pl08x_platform_data - the platform configuration for the PL08x
+ * PrimeCells.
* @slave_channels: the channels defined for the different devices on the
* platform, all inclusive, including multiplexed channels. The available
- * physical channels will be multiplexed around these signals as they
- * are requested, just enumerate all possible channels.
- * @get_signal: request a physical signal to be used for a DMA
- * transfer immediately: if there is some multiplexing or similar blocking
- * the use of the channel the transfer can be denied by returning
- * less than zero, else it returns the allocated signal number
+ * physical channels will be multiplexed around these signals as they are
+ * requested, just enumerate all possible channels.
+ * @get_signal: request a physical signal to be used for a DMA transfer
+ * immediately: if there is some multiplexing or similar blocking the use
+ * of the channel the transfer can be denied by returning less than zero,
+ * else it returns the allocated signal number
* @put_signal: indicate to the platform that this physical signal is not
* running any DMA transfer and multiplexing can be recycled
- * @bus_bit_lli: Bit[0] of the address indicated which AHB bus master the
- * LLI addresses are on 0/1 Master 1/2.
+ * @lli_buses: buses which LLIs can be fetched from: PL08X_AHB1 | PL08X_AHB2
+ * @mem_buses: buses which memory can be accessed from: PL08X_AHB1 | PL08X_AHB2
*/
struct pl08x_platform_data {
struct pl08x_channel_data *slave_channels;
@@ -208,6 +207,8 @@ struct pl08x_platform_data {
struct pl08x_channel_data memcpy_channel;
int (*get_signal)(struct pl08x_dma_chan *);
void (*put_signal)(struct pl08x_dma_chan *);
+ u8 lli_buses;
+ u8 mem_buses;
};
#ifdef CONFIG_AMBA_PL08X
diff --git a/include/linux/auto_fs4.h b/include/linux/auto_fs4.h
index 8b49ac4..e02982f 100644
--- a/include/linux/auto_fs4.h
+++ b/include/linux/auto_fs4.h
@@ -24,7 +24,7 @@
#define AUTOFS_MIN_PROTO_VERSION 3
#define AUTOFS_MAX_PROTO_VERSION 5
-#define AUTOFS_PROTO_SUBVERSION 1
+#define AUTOFS_PROTO_SUBVERSION 2
/* Mask for expire behaviour */
#define AUTOFS_EXP_IMMEDIATE 1
diff --git a/include/linux/cper.h b/include/linux/cper.h
index bf972f8..3104aaf 100644
--- a/include/linux/cper.h
+++ b/include/linux/cper.h
@@ -39,10 +39,12 @@
* Severity difinition for error_severity in struct cper_record_header
* and section_severity in struct cper_section_descriptor
*/
-#define CPER_SEV_RECOVERABLE 0x0
-#define CPER_SEV_FATAL 0x1
-#define CPER_SEV_CORRECTED 0x2
-#define CPER_SEV_INFORMATIONAL 0x3
+enum {
+ CPER_SEV_RECOVERABLE,
+ CPER_SEV_FATAL,
+ CPER_SEV_CORRECTED,
+ CPER_SEV_INFORMATIONAL,
+};
/*
* Validation bits difinition for validation_bits in struct
@@ -201,6 +203,47 @@
UUID_LE(0x036F84E1, 0x7F37, 0x428c, 0xA7, 0x9E, 0x57, 0x5F, \
0xDF, 0xAA, 0x84, 0xEC)
+#define CPER_PROC_VALID_TYPE 0x0001
+#define CPER_PROC_VALID_ISA 0x0002
+#define CPER_PROC_VALID_ERROR_TYPE 0x0004
+#define CPER_PROC_VALID_OPERATION 0x0008
+#define CPER_PROC_VALID_FLAGS 0x0010
+#define CPER_PROC_VALID_LEVEL 0x0020
+#define CPER_PROC_VALID_VERSION 0x0040
+#define CPER_PROC_VALID_BRAND_INFO 0x0080
+#define CPER_PROC_VALID_ID 0x0100
+#define CPER_PROC_VALID_TARGET_ADDRESS 0x0200
+#define CPER_PROC_VALID_REQUESTOR_ID 0x0400
+#define CPER_PROC_VALID_RESPONDER_ID 0x0800
+#define CPER_PROC_VALID_IP 0x1000
+
+#define CPER_MEM_VALID_ERROR_STATUS 0x0001
+#define CPER_MEM_VALID_PHYSICAL_ADDRESS 0x0002
+#define CPER_MEM_VALID_PHYSICAL_ADDRESS_MASK 0x0004
+#define CPER_MEM_VALID_NODE 0x0008
+#define CPER_MEM_VALID_CARD 0x0010
+#define CPER_MEM_VALID_MODULE 0x0020
+#define CPER_MEM_VALID_BANK 0x0040
+#define CPER_MEM_VALID_DEVICE 0x0080
+#define CPER_MEM_VALID_ROW 0x0100
+#define CPER_MEM_VALID_COLUMN 0x0200
+#define CPER_MEM_VALID_BIT_POSITION 0x0400
+#define CPER_MEM_VALID_REQUESTOR_ID 0x0800
+#define CPER_MEM_VALID_RESPONDER_ID 0x1000
+#define CPER_MEM_VALID_TARGET_ID 0x2000
+#define CPER_MEM_VALID_ERROR_TYPE 0x4000
+
+#define CPER_PCIE_VALID_PORT_TYPE 0x0001
+#define CPER_PCIE_VALID_VERSION 0x0002
+#define CPER_PCIE_VALID_COMMAND_STATUS 0x0004
+#define CPER_PCIE_VALID_DEVICE_ID 0x0008
+#define CPER_PCIE_VALID_SERIAL_NUMBER 0x0010
+#define CPER_PCIE_VALID_BRIDGE_CONTROL_STATUS 0x0020
+#define CPER_PCIE_VALID_CAPABILITY 0x0040
+#define CPER_PCIE_VALID_AER_INFO 0x0080
+
+#define CPER_PCIE_SLOT_SHIFT 3
+
/*
* All tables and structs must be byte-packed to match CPER
* specification, since the tables are provided by the system BIOS
@@ -306,6 +349,41 @@ struct cper_sec_mem_err {
__u8 error_type;
};
+struct cper_sec_pcie {
+ __u64 validation_bits;
+ __u32 port_type;
+ struct {
+ __u8 minor;
+ __u8 major;
+ __u8 reserved[2];
+ } version;
+ __u16 command;
+ __u16 status;
+ __u32 reserved;
+ struct {
+ __u16 vendor_id;
+ __u16 device_id;
+ __u8 class_code[3];
+ __u8 function;
+ __u8 device;
+ __u16 segment;
+ __u8 bus;
+ __u8 secondary_bus;
+ __u16 slot;
+ __u8 reserved;
+ } device_id;
+ struct {
+ __u32 lower;
+ __u32 upper;
+ } serial_number;
+ struct {
+ __u16 secondary_status;
+ __u16 control;
+ } bridge;
+ __u8 capability[60];
+ __u8 aer_info[96];
+};
+
/* Reset to default packing */
#pragma pack()
diff --git a/include/linux/cpuidle.h b/include/linux/cpuidle.h
index 1be416b..36719ea 100644
--- a/include/linux/cpuidle.h
+++ b/include/linux/cpuidle.h
@@ -47,13 +47,7 @@ struct cpuidle_state {
/* Idle State Flags */
#define CPUIDLE_FLAG_TIME_VALID (0x01) /* is residency time measurable? */
-#define CPUIDLE_FLAG_CHECK_BM (0x02) /* BM activity will exit state */
-#define CPUIDLE_FLAG_POLL (0x10) /* no latency, no savings */
-#define CPUIDLE_FLAG_SHALLOW (0x20) /* low latency, minimal savings */
-#define CPUIDLE_FLAG_BALANCED (0x40) /* medium latency, moderate savings */
-#define CPUIDLE_FLAG_DEEP (0x80) /* high latency, large savings */
#define CPUIDLE_FLAG_IGNORE (0x100) /* ignore during this idle period */
-#define CPUIDLE_FLAG_TLB_FLUSHED (0x200) /* tlb will be flushed */
#define CPUIDLE_DRIVER_FLAGS_MASK (0xFFFF0000)
diff --git a/include/linux/dcache.h b/include/linux/dcache.h
index 59fcd24..f958c19 100644
--- a/include/linux/dcache.h
+++ b/include/linux/dcache.h
@@ -167,6 +167,8 @@ struct dentry_operations {
void (*d_release)(struct dentry *);
void (*d_iput)(struct dentry *, struct inode *);
char *(*d_dname)(struct dentry *, char *, int);
+ struct vfsmount *(*d_automount)(struct path *);
+ int (*d_manage)(struct dentry *, bool, bool);
} ____cacheline_aligned;
/*
@@ -205,13 +207,18 @@ struct dentry_operations {
#define DCACHE_CANT_MOUNT 0x0100
#define DCACHE_GENOCIDE 0x0200
-#define DCACHE_MOUNTED 0x0400 /* is a mountpoint */
#define DCACHE_OP_HASH 0x1000
#define DCACHE_OP_COMPARE 0x2000
#define DCACHE_OP_REVALIDATE 0x4000
#define DCACHE_OP_DELETE 0x8000
+#define DCACHE_MOUNTED 0x10000 /* is a mountpoint */
+#define DCACHE_NEED_AUTOMOUNT 0x20000 /* handle automount on this dir */
+#define DCACHE_MANAGE_TRANSIT 0x40000 /* manage transit from this dirent */
+#define DCACHE_MANAGED_DENTRY \
+ (DCACHE_MOUNTED|DCACHE_NEED_AUTOMOUNT|DCACHE_MANAGE_TRANSIT)
+
extern seqlock_t rename_lock;
static inline int dname_external(struct dentry *dentry)
@@ -399,7 +406,12 @@ static inline void dont_mount(struct dentry *dentry)
extern void dput(struct dentry *);
-static inline int d_mountpoint(struct dentry *dentry)
+static inline bool d_managed(struct dentry *dentry)
+{
+ return dentry->d_flags & DCACHE_MANAGED_DENTRY;
+}
+
+static inline bool d_mountpoint(struct dentry *dentry)
{
return dentry->d_flags & DCACHE_MOUNTED;
}
diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h
index 8cd00ad..9bebd7f 100644
--- a/include/linux/dmaengine.h
+++ b/include/linux/dmaengine.h
@@ -532,7 +532,7 @@ static inline int dmaengine_resume(struct dma_chan *chan)
return dmaengine_device_control(chan, DMA_RESUME, 0);
}
-static inline int dmaengine_submit(struct dma_async_tx_descriptor *desc)
+static inline dma_cookie_t dmaengine_submit(struct dma_async_tx_descriptor *desc)
{
return desc->tx_submit(desc);
}
diff --git a/include/linux/etherdevice.h b/include/linux/etherdevice.h
index bec8b82..ab68f78 100644
--- a/include/linux/etherdevice.h
+++ b/include/linux/etherdevice.h
@@ -99,6 +99,17 @@ static inline int is_broadcast_ether_addr(const u8 *addr)
}
/**
+ * is_unicast_ether_addr - Determine if the Ethernet address is unicast
+ * @addr: Pointer to a six-byte array containing the Ethernet address
+ *
+ * Return true if the address is a unicast address.
+ */
+static inline int is_unicast_ether_addr(const u8 *addr)
+{
+ return !is_multicast_ether_addr(addr);
+}
+
+/**
* is_valid_ether_addr - Determine if the given Ethernet address is valid
* @addr: Pointer to a six-byte array containing the Ethernet address
*
diff --git a/include/linux/fcntl.h b/include/linux/fcntl.h
index afc00af..a562fa5 100644
--- a/include/linux/fcntl.h
+++ b/include/linux/fcntl.h
@@ -45,6 +45,7 @@
#define AT_REMOVEDIR 0x200 /* Remove directory instead of
unlinking file. */
#define AT_SYMLINK_FOLLOW 0x400 /* Follow symbolic links. */
+#define AT_NO_AUTOMOUNT 0x800 /* Suppress terminal automount traversal */
#ifdef __KERNEL__
diff --git a/include/linux/file.h b/include/linux/file.h
index b1e1297..e85baeb 100644
--- a/include/linux/file.h
+++ b/include/linux/file.h
@@ -23,7 +23,7 @@ extern struct file *alloc_file(struct path *, fmode_t mode,
static inline void fput_light(struct file *file, int fput_needed)
{
- if (unlikely(fput_needed))
+ if (fput_needed)
fput(file);
}
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 3984f23..32b38cd 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -242,6 +242,7 @@ struct inodes_stat_t {
#define S_SWAPFILE 256 /* Do not truncate: swapon got its bmaps */
#define S_PRIVATE 512 /* Inode is fs-internal */
#define S_IMA 1024 /* Inode has an associated IMA struct */
+#define S_AUTOMOUNT 2048 /* Automount/referral quasi-directory */
/*
* Note that nosuid etc flags are inode-specific: setting some file-system
@@ -277,6 +278,7 @@ struct inodes_stat_t {
#define IS_SWAPFILE(inode) ((inode)->i_flags & S_SWAPFILE)
#define IS_PRIVATE(inode) ((inode)->i_flags & S_PRIVATE)
#define IS_IMA(inode) ((inode)->i_flags & S_IMA)
+#define IS_AUTOMOUNT(inode) ((inode)->i_flags & S_AUTOMOUNT)
/* the read-only stuff doesn't really belong here, but any other place is
probably as bad and I don't want to create yet another include file. */
@@ -666,7 +668,7 @@ struct block_device {
int bd_holders;
bool bd_write_holder;
#ifdef CONFIG_SYSFS
- struct gendisk * bd_holder_disk; /* for sysfs slave linkng */
+ struct list_head bd_holder_disks;
#endif
struct block_device * bd_contains;
unsigned bd_block_size;
@@ -1066,7 +1068,6 @@ struct lock_manager_operations {
int (*fl_grant)(struct file_lock *, struct file_lock *, int);
void (*fl_release_private)(struct file_lock *);
void (*fl_break)(struct file_lock *);
- int (*fl_mylease)(struct file_lock *, struct file_lock *);
int (*fl_change)(struct file_lock **, int);
};
@@ -1482,8 +1483,8 @@ struct fiemap_extent_info {
unsigned int fi_flags; /* Flags as passed from user */
unsigned int fi_extents_mapped; /* Number of mapped extents */
unsigned int fi_extents_max; /* Size of fiemap_extent array */
- struct fiemap_extent *fi_extents_start; /* Start of fiemap_extent
- * array */
+ struct fiemap_extent __user *fi_extents_start; /* Start of
+ fiemap_extent array */
};
int fiemap_fill_next_extent(struct fiemap_extent_info *info, u64 logical,
u64 phys, u64 len, u32 flags);
@@ -1551,6 +1552,8 @@ struct file_operations {
ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int);
ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int);
int (*setlease)(struct file *, long, struct file_lock **);
+ long (*fallocate)(struct file *file, int mode, loff_t offset,
+ loff_t len);
};
#define IPERM_FLAG_RCU 0x0001
@@ -1581,8 +1584,6 @@ struct inode_operations {
ssize_t (*listxattr) (struct dentry *, char *, size_t);
int (*removexattr) (struct dentry *, const char *);
void (*truncate_range)(struct inode *, loff_t, loff_t);
- long (*fallocate)(struct inode *inode, int mode, loff_t offset,
- loff_t len);
int (*fiemap)(struct inode *, struct fiemap_extent_info *, u64 start,
u64 len);
} ____cacheline_aligned;
@@ -2058,12 +2059,18 @@ extern struct block_device *blkdev_get_by_dev(dev_t dev, fmode_t mode,
extern int blkdev_put(struct block_device *bdev, fmode_t mode);
#ifdef CONFIG_SYSFS
extern int bd_link_disk_holder(struct block_device *bdev, struct gendisk *disk);
+extern void bd_unlink_disk_holder(struct block_device *bdev,
+ struct gendisk *disk);
#else
static inline int bd_link_disk_holder(struct block_device *bdev,
struct gendisk *disk)
{
return 0;
}
+static inline void bd_unlink_disk_holder(struct block_device *bdev,
+ struct gendisk *disk)
+{
+}
#endif
#endif
diff --git a/include/linux/gfp.h b/include/linux/gfp.h
index a3b148a..0b84c61 100644
--- a/include/linux/gfp.h
+++ b/include/linux/gfp.h
@@ -249,7 +249,7 @@ static inline enum zone_type gfp_zone(gfp_t flags)
((1 << ZONES_SHIFT) - 1);
if (__builtin_constant_p(bit))
- MAYBE_BUILD_BUG_ON((GFP_ZONE_BAD >> bit) & 1);
+ BUILD_BUG_ON((GFP_ZONE_BAD >> bit) & 1);
else {
#ifdef CONFIG_DEBUG_VM
BUG_ON((GFP_ZONE_BAD >> bit) & 1);
diff --git a/include/linux/gpio.h b/include/linux/gpio.h
index 4b47ed9..32720ba 100644
--- a/include/linux/gpio.h
+++ b/include/linux/gpio.h
@@ -35,13 +35,13 @@ static inline int gpio_request(unsigned gpio, const char *label)
return -ENOSYS;
}
-static inline int __must_check gpio_request_one(unsigned gpio,
+static inline int gpio_request_one(unsigned gpio,
unsigned long flags, const char *label)
{
return -ENOSYS;
}
-static inline int __must_check gpio_request_array(struct gpio *array, size_t num)
+static inline int gpio_request_array(struct gpio *array, size_t num)
{
return -ENOSYS;
}
diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
index 6042228..294169e 100644
--- a/include/linux/ieee80211.h
+++ b/include/linux/ieee80211.h
@@ -959,7 +959,7 @@ struct ieee80211_ht_info {
/* block-ack parameters */
#define IEEE80211_ADDBA_PARAM_POLICY_MASK 0x0002
#define IEEE80211_ADDBA_PARAM_TID_MASK 0x003C
-#define IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK 0xFFA0
+#define IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK 0xFFC0
#define IEEE80211_DELBA_PARAM_TID_MASK 0xF000
#define IEEE80211_DELBA_PARAM_INITIATOR_MASK 0x0800
diff --git a/include/linux/ipmi.h b/include/linux/ipmi.h
index 65aae34..045f2f2 100644
--- a/include/linux/ipmi.h
+++ b/include/linux/ipmi.h
@@ -454,6 +454,44 @@ unsigned int ipmi_addr_length(int addr_type);
/* Validate that the given IPMI address is valid. */
int ipmi_validate_addr(struct ipmi_addr *addr, int len);
+/*
+ * How did the IPMI driver find out about the device?
+ */
+enum ipmi_addr_src {
+ SI_INVALID = 0, SI_HOTMOD, SI_HARDCODED, SI_SPMI, SI_ACPI, SI_SMBIOS,
+ SI_PCI, SI_DEVICETREE, SI_DEFAULT
+};
+
+union ipmi_smi_info_union {
+ /*
+ * the acpi_info element is defined for the SI_ACPI
+ * address type
+ */
+ struct {
+ void *acpi_handle;
+ } acpi_info;
+};
+
+struct ipmi_smi_info {
+ enum ipmi_addr_src addr_src;
+
+ /*
+ * Base device for the interface. Don't forget to put this when
+ * you are done.
+ */
+ struct device *dev;
+
+ /*
+ * The addr_info provides more detailed info for some IPMI
+ * devices, depending on the addr_src. Currently only SI_ACPI
+ * info is provided.
+ */
+ union ipmi_smi_info_union addr_info;
+};
+
+/* This is to get the private info of ipmi_smi_t */
+extern int ipmi_get_smi_info(int if_num, struct ipmi_smi_info *data);
+
#endif /* __KERNEL__ */
diff --git a/include/linux/ipmi_smi.h b/include/linux/ipmi_smi.h
index 4b48318..906590a 100644
--- a/include/linux/ipmi_smi.h
+++ b/include/linux/ipmi_smi.h
@@ -39,6 +39,7 @@
#include <linux/module.h>
#include <linux/device.h>
#include <linux/platform_device.h>
+#include <linux/ipmi.h>
/* This files describes the interface for IPMI system management interface
drivers to bind into the IPMI message handler. */
@@ -86,6 +87,13 @@ struct ipmi_smi_handlers {
int (*start_processing)(void *send_info,
ipmi_smi_t new_intf);
+ /*
+ * Get the detailed private info of the low level interface and store
+ * it into the structure of ipmi_smi_data. For example: the
+ * ACPI device handle will be returned for the pnp_acpi IPMI device.
+ */
+ int (*get_smi_info)(void *send_info, struct ipmi_smi_info *data);
+
/* Called to enqueue an SMI message to be sent. This
operation is not allowed to fail. If an error occurs, it
should report back the error in a received message. It may
diff --git a/include/linux/irqdesc.h b/include/linux/irqdesc.h
index 6a64c6f..c1a95b7 100644
--- a/include/linux/irqdesc.h
+++ b/include/linux/irqdesc.h
@@ -101,13 +101,6 @@ static inline struct irq_desc *move_irq_desc(struct irq_desc *desc, int node)
#define get_irq_desc_msi(desc) ((desc)->irq_data.msi_desc)
/*
- * Monolithic do_IRQ implementation.
- */
-#ifndef CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ
-extern unsigned int __do_IRQ(unsigned int irq);
-#endif
-
-/*
* Architectures call this to let the generic IRQ layer
* handle an interrupt. If the descriptor is attached to an
* irqchip-style controller then we call the ->handle_irq() handler,
@@ -115,14 +108,7 @@ extern unsigned int __do_IRQ(unsigned int irq);
*/
static inline void generic_handle_irq_desc(unsigned int irq, struct irq_desc *desc)
{
-#ifdef CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ
desc->handle_irq(irq, desc);
-#else
- if (likely(desc->handle_irq))
- desc->handle_irq(irq, desc);
- else
- __do_IRQ(irq);
-#endif
}
static inline void generic_handle_irq(unsigned int irq)
diff --git a/include/linux/kernel.h b/include/linux/kernel.h
index 5a9d905..e2f4d6a 100644
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -243,6 +243,8 @@ extern int test_taint(unsigned flag);
extern unsigned long get_taint(void);
extern int root_mountflags;
+extern bool early_boot_irqs_disabled;
+
/* Values used for system_state */
extern enum system_states {
SYSTEM_BOOTING,
@@ -573,12 +575,6 @@ struct sysinfo {
char _f[20-2*sizeof(long)-sizeof(int)]; /* Padding: libc5 uses this.. */
};
-/* Force a compilation error if condition is true */
-#define BUILD_BUG_ON(condition) ((void)BUILD_BUG_ON_ZERO(condition))
-
-/* Force a compilation error if condition is constant and true */
-#define MAYBE_BUILD_BUG_ON(cond) ((void)sizeof(char[1 - 2 * !!(cond)]))
-
/* Force a compilation error if a constant expression is not a power of 2 */
#define BUILD_BUG_ON_NOT_POWER_OF_2(n) \
BUILD_BUG_ON((n) == 0 || (((n) & ((n) - 1)) != 0))
@@ -590,6 +586,32 @@ struct sysinfo {
#define BUILD_BUG_ON_ZERO(e) (sizeof(struct { int:-!!(e); }))
#define BUILD_BUG_ON_NULL(e) ((void *)sizeof(struct { int:-!!(e); }))
+/**
+ * BUILD_BUG_ON - break compile if a condition is true.
+ * @cond: the condition which the compiler should know is false.
+ *
+ * If you have some code which relies on certain constants being equal, or
+ * other compile-time-evaluated condition, you should use BUILD_BUG_ON to
+ * detect if someone changes it.
+ *
+ * The implementation uses gcc's reluctance to create a negative array, but
+ * gcc (as of 4.4) only emits that error for obvious cases (eg. not arguments
+ * to inline functions). So as a fallback we use the optimizer; if it can't
+ * prove the condition is false, it will cause a link error on the undefined
+ * "__build_bug_on_failed". This error message can be harder to track down
+ * though, hence the two different methods.
+ */
+#ifndef __OPTIMIZE__
+#define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)]))
+#else
+extern int __build_bug_on_failed;
+#define BUILD_BUG_ON(condition) \
+ do { \
+ ((void)sizeof(char[1 - 2*!!(condition)])); \
+ if (condition) __build_bug_on_failed = 1; \
+ } while(0)
+#endif
+
/* Trap pasters of __FUNCTION__ at compile-time */
#define __FUNCTION__ (__func__)
diff --git a/include/linux/kmemcheck.h b/include/linux/kmemcheck.h
index 08d7dc4..39f8453 100644
--- a/include/linux/kmemcheck.h
+++ b/include/linux/kmemcheck.h
@@ -76,7 +76,7 @@ bool kmemcheck_is_obj_initialized(unsigned long addr, size_t size);
\
_n = (long) &((ptr)->name##_end) \
- (long) &((ptr)->name##_begin); \
- MAYBE_BUILD_BUG_ON(_n < 0); \
+ BUILD_BUG_ON(_n < 0); \
\
kmemcheck_mark_initialized(&((ptr)->name##_begin), _n); \
} while (0)
diff --git a/include/linux/list_bl.h b/include/linux/list_bl.h
index 9ee97e7..5bad17d1 100644
--- a/include/linux/list_bl.h
+++ b/include/linux/list_bl.h
@@ -62,7 +62,8 @@ static inline void hlist_bl_set_first(struct hlist_bl_head *h,
struct hlist_bl_node *n)
{
LIST_BL_BUG_ON((unsigned long)n & LIST_BL_LOCKMASK);
- LIST_BL_BUG_ON(!((unsigned long)h->first & LIST_BL_LOCKMASK));
+ LIST_BL_BUG_ON(((unsigned long)h->first & LIST_BL_LOCKMASK) !=
+ LIST_BL_LOCKMASK);
h->first = (struct hlist_bl_node *)((unsigned long)n | LIST_BL_LOCKMASK);
}
diff --git a/include/linux/lockdep.h b/include/linux/lockdep.h
index 71c09b26..4aef1dd 100644
--- a/include/linux/lockdep.h
+++ b/include/linux/lockdep.h
@@ -436,16 +436,8 @@ do { \
#endif /* CONFIG_LOCKDEP */
#ifdef CONFIG_TRACE_IRQFLAGS
-extern void early_boot_irqs_off(void);
-extern void early_boot_irqs_on(void);
extern void print_irqtrace_events(struct task_struct *curr);
#else
-static inline void early_boot_irqs_off(void)
-{
-}
-static inline void early_boot_irqs_on(void)
-{
-}
static inline void print_irqtrace_events(struct task_struct *curr)
{
}
@@ -522,12 +514,15 @@ static inline void print_irqtrace_events(struct task_struct *curr)
#ifdef CONFIG_DEBUG_LOCK_ALLOC
# ifdef CONFIG_PROVE_LOCKING
# define lock_map_acquire(l) lock_acquire(l, 0, 0, 0, 2, NULL, _THIS_IP_)
+# define lock_map_acquire_read(l) lock_acquire(l, 0, 0, 2, 2, NULL, _THIS_IP_)
# else
# define lock_map_acquire(l) lock_acquire(l, 0, 0, 0, 1, NULL, _THIS_IP_)
+# define lock_map_acquire_read(l) lock_acquire(l, 0, 0, 2, 1, NULL, _THIS_IP_)
# endif
# define lock_map_release(l) lock_release(l, 1, _THIS_IP_)
#else
# define lock_map_acquire(l) do { } while (0)
+# define lock_map_acquire_read(l) do { } while (0)
# define lock_map_release(l) do { } while (0)
#endif
diff --git a/include/linux/magic.h b/include/linux/magic.h
index ff690d0..62730ea 100644
--- a/include/linux/magic.h
+++ b/include/linux/magic.h
@@ -16,6 +16,7 @@
#define TMPFS_MAGIC 0x01021994
#define HUGETLBFS_MAGIC 0x958458f6 /* some random number */
#define SQUASHFS_MAGIC 0x73717368
+#define ECRYPTFS_SUPER_MAGIC 0xf15f
#define EFS_SUPER_MAGIC 0x414A53
#define EXT2_SUPER_MAGIC 0xEF53
#define EXT3_SUPER_MAGIC 0xEF53
diff --git a/include/linux/memcontrol.h b/include/linux/memcontrol.h
index 6a576f9..f512e18 100644
--- a/include/linux/memcontrol.h
+++ b/include/linux/memcontrol.h
@@ -146,6 +146,10 @@ unsigned long mem_cgroup_soft_limit_reclaim(struct zone *zone, int order,
gfp_t gfp_mask);
u64 mem_cgroup_get_limit(struct mem_cgroup *mem);
+#ifdef CONFIG_TRANSPARENT_HUGEPAGE
+void mem_cgroup_split_huge_fixup(struct page *head, struct page *tail);
+#endif
+
#else /* CONFIG_CGROUP_MEM_RES_CTLR */
struct mem_cgroup;
@@ -335,6 +339,11 @@ u64 mem_cgroup_get_limit(struct mem_cgroup *mem)
return 0;
}
+static inline void mem_cgroup_split_huge_fixup(struct page *head,
+ struct page *tail)
+{
+}
+
#endif /* CONFIG_CGROUP_MEM_CONT */
#endif /* _LINUX_MEMCONTROL_H */
diff --git a/include/linux/memory_hotplug.h b/include/linux/memory_hotplug.h
index 24376fe..8122018d 100644
--- a/include/linux/memory_hotplug.h
+++ b/include/linux/memory_hotplug.h
@@ -165,6 +165,12 @@ extern void register_page_bootmem_info_node(struct pglist_data *pgdat);
extern void put_page_bootmem(struct page *page);
#endif
+/*
+ * Lock for memory hotplug guarantees 1) all callbacks for memory hotplug
+ * notifier will be called under this. 2) offline/online/add/remove memory
+ * will not run simultaneously.
+ */
+
void lock_memory_hotplug(void);
void unlock_memory_hotplug(void);
diff --git a/include/linux/mfd/ab8500.h b/include/linux/mfd/ab8500.h
index 85cf2c28..37f56b7 100644
--- a/include/linux/mfd/ab8500.h
+++ b/include/linux/mfd/ab8500.h
@@ -74,30 +74,37 @@
#define AB8500_INT_ACC_DETECT_21DB_F 37
#define AB8500_INT_ACC_DETECT_21DB_R 38
#define AB8500_INT_GP_SW_ADC_CONV_END 39
-#define AB8500_INT_BTEMP_LOW 72
-#define AB8500_INT_BTEMP_LOW_MEDIUM 73
-#define AB8500_INT_BTEMP_MEDIUM_HIGH 74
-#define AB8500_INT_BTEMP_HIGH 75
-#define AB8500_INT_USB_CHARGER_NOT_OK 81
-#define AB8500_INT_ID_WAKEUP_R 82
-#define AB8500_INT_ID_DET_R1R 84
-#define AB8500_INT_ID_DET_R2R 85
-#define AB8500_INT_ID_DET_R3R 86
-#define AB8500_INT_ID_DET_R4R 87
-#define AB8500_INT_ID_WAKEUP_F 88
-#define AB8500_INT_ID_DET_R1F 90
-#define AB8500_INT_ID_DET_R2F 91
-#define AB8500_INT_ID_DET_R3F 92
-#define AB8500_INT_ID_DET_R4F 93
-#define AB8500_INT_USB_CHG_DET_DONE 94
-#define AB8500_INT_USB_CH_TH_PROT_F 96
-#define AB8500_INT_USB_CH_TH_PROP_R 97
-#define AB8500_INT_MAIN_CH_TH_PROP_F 98
-#define AB8500_INT_MAIN_CH_TH_PROT_R 99
-#define AB8500_INT_USB_CHARGER_NOT_OKF 103
+#define AB8500_INT_ADP_SOURCE_ERROR 72
+#define AB8500_INT_ADP_SINK_ERROR 73
+#define AB8500_INT_ADP_PROBE_PLUG 74
+#define AB8500_INT_ADP_PROBE_UNPLUG 75
+#define AB8500_INT_ADP_SENSE_OFF 76
+#define AB8500_INT_USB_PHY_POWER_ERR 78
+#define AB8500_INT_USB_LINK_STATUS 79
+#define AB8500_INT_BTEMP_LOW 80
+#define AB8500_INT_BTEMP_LOW_MEDIUM 81
+#define AB8500_INT_BTEMP_MEDIUM_HIGH 82
+#define AB8500_INT_BTEMP_HIGH 83
+#define AB8500_INT_USB_CHARGER_NOT_OK 89
+#define AB8500_INT_ID_WAKEUP_R 90
+#define AB8500_INT_ID_DET_R1R 92
+#define AB8500_INT_ID_DET_R2R 93
+#define AB8500_INT_ID_DET_R3R 94
+#define AB8500_INT_ID_DET_R4R 95
+#define AB8500_INT_ID_WAKEUP_F 96
+#define AB8500_INT_ID_DET_R1F 98
+#define AB8500_INT_ID_DET_R2F 99
+#define AB8500_INT_ID_DET_R3F 100
+#define AB8500_INT_ID_DET_R4F 101
+#define AB8500_INT_USB_CHG_DET_DONE 102
+#define AB8500_INT_USB_CH_TH_PROT_F 104
+#define AB8500_INT_USB_CH_TH_PROT_R 105
+#define AB8500_INT_MAIN_CH_TH_PROT_F 106
+#define AB8500_INT_MAIN_CH_TH_PROT_R 107
+#define AB8500_INT_USB_CHARGER_NOT_OKF 111
-#define AB8500_NR_IRQS 104
-#define AB8500_NUM_IRQ_REGS 13
+#define AB8500_NR_IRQS 112
+#define AB8500_NUM_IRQ_REGS 14
/**
* struct ab8500 - ab8500 internal structure
diff --git a/include/linux/mfd/core.h b/include/linux/mfd/core.h
index 5582ab3..835996e 100644
--- a/include/linux/mfd/core.h
+++ b/include/linux/mfd/core.h
@@ -47,6 +47,12 @@ struct mfd_cell {
/* don't check for resource conflicts */
bool ignore_resource_conflicts;
+
+ /*
+ * Disable runtime PM callbacks for this subdevice - see
+ * pm_runtime_no_callbacks().
+ */
+ bool pm_runtime_no_callbacks;
};
extern int mfd_add_devices(struct device *parent, int id,
diff --git a/include/linux/mfd/max8998-private.h b/include/linux/mfd/max8998-private.h
index 7363dea..effa5d3 100644
--- a/include/linux/mfd/max8998-private.h
+++ b/include/linux/mfd/max8998-private.h
@@ -159,10 +159,12 @@ struct max8998_dev {
u8 irq_masks_cur[MAX8998_NUM_IRQ_REGS];
u8 irq_masks_cache[MAX8998_NUM_IRQ_REGS];
int type;
+ bool wakeup;
};
int max8998_irq_init(struct max8998_dev *max8998);
void max8998_irq_exit(struct max8998_dev *max8998);
+int max8998_irq_resume(struct max8998_dev *max8998);
extern int max8998_read_reg(struct i2c_client *i2c, u8 reg, u8 *dest);
extern int max8998_bulk_read(struct i2c_client *i2c, u8 reg, int count,
diff --git a/include/linux/mfd/max8998.h b/include/linux/mfd/max8998.h
index f8c9f88..61daa16 100644
--- a/include/linux/mfd/max8998.h
+++ b/include/linux/mfd/max8998.h
@@ -70,24 +70,43 @@ struct max8998_regulator_data {
* @num_regulators: number of regultors used
* @irq_base: base IRQ number for max8998, required for IRQs
* @ono: power onoff IRQ number for max8998
- * @buck1_max_voltage1: BUCK1 maximum alowed voltage register 1
- * @buck1_max_voltage2: BUCK1 maximum alowed voltage register 2
- * @buck2_max_voltage: BUCK2 maximum alowed voltage
+ * @buck_voltage_lock: Do NOT change the values of the following six
+ * registers set by buck?_voltage?. The voltage of BUCK1/2 cannot
+ * be other than the preset values.
+ * @buck1_voltage1: BUCK1 DVS mode 1 voltage register
+ * @buck1_voltage2: BUCK1 DVS mode 2 voltage register
+ * @buck1_voltage3: BUCK1 DVS mode 3 voltage register
+ * @buck1_voltage4: BUCK1 DVS mode 4 voltage register
+ * @buck2_voltage1: BUCK2 DVS mode 1 voltage register
+ * @buck2_voltage2: BUCK2 DVS mode 2 voltage register
* @buck1_set1: BUCK1 gpio pin 1 to set output voltage
* @buck1_set2: BUCK1 gpio pin 2 to set output voltage
+ * @buck1_default_idx: Default for BUCK1 gpio pin 1, 2
* @buck2_set3: BUCK2 gpio pin to set output voltage
+ * @buck2_default_idx: Default for BUCK2 gpio pin.
+ * @wakeup: Allow to wake up from suspend
+ * @rtc_delay: LP3974 RTC chip bug that requires delay after a register
+ * write before reading it.
*/
struct max8998_platform_data {
struct max8998_regulator_data *regulators;
int num_regulators;
int irq_base;
int ono;
- int buck1_max_voltage1;
- int buck1_max_voltage2;
- int buck2_max_voltage;
+ bool buck_voltage_lock;
+ int buck1_voltage1;
+ int buck1_voltage2;
+ int buck1_voltage3;
+ int buck1_voltage4;
+ int buck2_voltage1;
+ int buck2_voltage2;
int buck1_set1;
int buck1_set2;
+ int buck1_default_idx;
int buck2_set3;
+ int buck2_default_idx;
+ bool wakeup;
+ bool rtc_delay;
};
#endif /* __LINUX_MFD_MAX8998_H */
diff --git a/include/linux/mfd/wm831x/core.h b/include/linux/mfd/wm831x/core.h
index a1239c4..903280d 100644
--- a/include/linux/mfd/wm831x/core.h
+++ b/include/linux/mfd/wm831x/core.h
@@ -245,6 +245,7 @@ enum wm831x_parent {
WM8320 = 0x8320,
WM8321 = 0x8321,
WM8325 = 0x8325,
+ WM8326 = 0x8326,
};
struct wm831x {
diff --git a/include/linux/mlx4/device.h b/include/linux/mlx4/device.h
index a7b15bc..0492146 100644
--- a/include/linux/mlx4/device.h
+++ b/include/linux/mlx4/device.h
@@ -144,6 +144,11 @@ enum {
MLX4_STAT_RATE_OFFSET = 5
};
+enum mlx4_protocol {
+ MLX4_PROTOCOL_IB,
+ MLX4_PROTOCOL_EN,
+};
+
enum {
MLX4_MTT_FLAG_PRESENT = 1
};
@@ -500,8 +505,9 @@ int mlx4_INIT_PORT(struct mlx4_dev *dev, int port);
int mlx4_CLOSE_PORT(struct mlx4_dev *dev, int port);
int mlx4_multicast_attach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16],
- int block_mcast_loopback);
-int mlx4_multicast_detach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16]);
+ int block_mcast_loopback, enum mlx4_protocol protocol);
+int mlx4_multicast_detach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16],
+ enum mlx4_protocol protocol);
int mlx4_register_mac(struct mlx4_dev *dev, u8 port, u64 mac, int *index);
void mlx4_unregister_mac(struct mlx4_dev *dev, u8 port, int index);
diff --git a/include/linux/mlx4/driver.h b/include/linux/mlx4/driver.h
index f407cd4..e1eebf7 100644
--- a/include/linux/mlx4/driver.h
+++ b/include/linux/mlx4/driver.h
@@ -34,6 +34,7 @@
#define MLX4_DRIVER_H
#include <linux/device.h>
+#include <linux/mlx4/device.h>
struct mlx4_dev;
@@ -44,11 +45,6 @@ enum mlx4_dev_event {
MLX4_DEV_EVENT_PORT_REINIT,
};
-enum mlx4_protocol {
- MLX4_PROTOCOL_IB,
- MLX4_PROTOCOL_EN,
-};
-
struct mlx4_interface {
void * (*add) (struct mlx4_dev *dev);
void (*remove)(struct mlx4_dev *dev, void *context);
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 956a355..f6385fc 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -470,6 +470,7 @@ static inline void set_compound_order(struct page *page, unsigned long order)
page[1].lru.prev = (void *)order;
}
+#ifdef CONFIG_MMU
/*
* Do pte_mkwrite, but only if the vma says VM_WRITE. We do this when
* servicing faults for write access. In the normal case, do always want
@@ -482,6 +483,7 @@ static inline pte_t maybe_mkwrite(pte_t pte, struct vm_area_struct *vma)
pte = pte_mkwrite(pte);
return pte;
}
+#endif
/*
* Multiple processes may "see" the same page. E.g. for untouched
diff --git a/include/linux/module.h b/include/linux/module.h
index 8b17fd8..e7c6385 100644
--- a/include/linux/module.h
+++ b/include/linux/module.h
@@ -58,6 +58,12 @@ struct module_attribute {
void (*free)(struct module *);
};
+struct module_version_attribute {
+ struct module_attribute mattr;
+ const char *module_name;
+ const char *version;
+};
+
struct module_kobject
{
struct kobject kobj;
@@ -161,7 +167,28 @@ extern struct module __this_module;
Using this automatically adds a checksum of the .c files and the
local headers in "srcversion".
*/
+
+#if defined(MODULE) || !defined(CONFIG_SYSFS)
#define MODULE_VERSION(_version) MODULE_INFO(version, _version)
+#else
+#define MODULE_VERSION(_version) \
+ extern ssize_t __modver_version_show(struct module_attribute *, \
+ struct module *, char *); \
+ static struct module_version_attribute __modver_version_attr \
+ __used \
+ __attribute__ ((__section__ ("__modver"),aligned(sizeof(void *)))) \
+ = { \
+ .mattr = { \
+ .attr = { \
+ .name = "version", \
+ .mode = S_IRUGO, \
+ }, \
+ .show = __modver_version_show, \
+ }, \
+ .module_name = KBUILD_MODNAME, \
+ .version = _version, \
+ }
+#endif
/* Optional firmware file (or files) needed by the module
* format is simply firmware file name. Multiple firmware
diff --git a/include/linux/moduleparam.h b/include/linux/moduleparam.h
index 112adf8..07b4195 100644
--- a/include/linux/moduleparam.h
+++ b/include/linux/moduleparam.h
@@ -16,15 +16,17 @@
/* Chosen so that structs with an unsigned long line up. */
#define MAX_PARAM_PREFIX_LEN (64 - sizeof(unsigned long))
-#ifdef MODULE
#define ___module_cat(a,b) __mod_ ## a ## b
#define __module_cat(a,b) ___module_cat(a,b)
+#ifdef MODULE
#define __MODULE_INFO(tag, name, info) \
static const char __module_cat(name,__LINE__)[] \
__used __attribute__((section(".modinfo"), unused, aligned(1))) \
= __stringify(tag) "=" info
#else /* !MODULE */
-#define __MODULE_INFO(tag, name, info)
+/* This struct is here for syntactic coherency, it is not used */
+#define __MODULE_INFO(tag, name, info) \
+ struct __module_cat(name,__LINE__) {}
#endif
#define __MODULE_PARM_TYPE(name, _type) \
__MODULE_INFO(parmtype, name##type, #name ":" _type)
diff --git a/include/linux/mount.h b/include/linux/mount.h
index 1869ea2..604f122 100644
--- a/include/linux/mount.h
+++ b/include/linux/mount.h
@@ -60,7 +60,7 @@ struct vfsmount {
struct super_block *mnt_sb; /* pointer to superblock */
#ifdef CONFIG_SMP
struct mnt_pcp __percpu *mnt_pcp;
- atomic_t mnt_longrefs;
+ atomic_t mnt_longterm; /* how many of the refs are longterm */
#else
int mnt_count;
int mnt_writers;
@@ -96,8 +96,6 @@ extern int mnt_clone_write(struct vfsmount *mnt);
extern void mnt_drop_write(struct vfsmount *mnt);
extern void mntput(struct vfsmount *mnt);
extern struct vfsmount *mntget(struct vfsmount *mnt);
-extern void mntput_long(struct vfsmount *mnt);
-extern struct vfsmount *mntget_long(struct vfsmount *mnt);
extern void mnt_pin(struct vfsmount *mnt);
extern void mnt_unpin(struct vfsmount *mnt);
extern int __mnt_is_readonly(struct vfsmount *mnt);
@@ -110,12 +108,7 @@ extern struct vfsmount *vfs_kern_mount(struct file_system_type *type,
int flags, const char *name,
void *data);
-struct nameidata;
-
-struct path;
-extern int do_add_mount(struct vfsmount *newmnt, struct path *path,
- int mnt_flags, struct list_head *fslist);
-
+extern void mnt_set_expiry(struct vfsmount *mnt, struct list_head *expiry_list);
extern void mark_mounts_for_expiry(struct list_head *mounts);
extern dev_t name_to_dev_t(char *name);
diff --git a/include/linux/mtd/cfi.h b/include/linux/mtd/cfi.h
index 4dd0c2c..a9baee6 100644
--- a/include/linux/mtd/cfi.h
+++ b/include/linux/mtd/cfi.h
@@ -527,8 +527,7 @@ struct cfi_extquery *cfi_read_pri(struct map_info *map, uint16_t adr, uint16_t s
struct cfi_fixup {
uint16_t mfr;
uint16_t id;
- void (*fixup)(struct mtd_info *mtd, void* param);
- void* param;
+ void (*fixup)(struct mtd_info *mtd);
};
#define CFI_MFR_ANY 0xFFFF
diff --git a/include/linux/mtd/fsmc.h b/include/linux/mtd/fsmc.h
index 5d25567..6987995 100644
--- a/include/linux/mtd/fsmc.h
+++ b/include/linux/mtd/fsmc.h
@@ -16,6 +16,7 @@
#ifndef __MTD_FSMC_H
#define __MTD_FSMC_H
+#include <linux/io.h>
#include <linux/platform_device.h>
#include <linux/mtd/physmap.h>
#include <linux/types.h>
@@ -27,7 +28,7 @@
/*
* The placement of the Command Latch Enable (CLE) and
- * Address Latch Enable (ALE) is twised around in the
+ * Address Latch Enable (ALE) is twisted around in the
* SPEAR310 implementation.
*/
#if defined(CONFIG_MACH_SPEAR310)
@@ -62,7 +63,7 @@ struct fsmc_nor_bank_regs {
/* ctrl_tim register definitions */
-struct fsms_nand_bank_regs {
+struct fsmc_nand_bank_regs {
uint32_t pc;
uint32_t sts;
uint32_t comm;
@@ -78,7 +79,7 @@ struct fsms_nand_bank_regs {
struct fsmc_regs {
struct fsmc_nor_bank_regs nor_bank_regs[FSMC_MAX_NOR_BANKS];
uint8_t reserved_1[0x40 - 0x20];
- struct fsms_nand_bank_regs bank_regs[FSMC_MAX_NAND_BANKS];
+ struct fsmc_nand_bank_regs bank_regs[FSMC_MAX_NAND_BANKS];
uint8_t reserved_2[0xfe0 - 0xc0];
uint32_t peripid0; /* 0xfe0 */
uint32_t peripid1; /* 0xfe4 */
@@ -114,25 +115,6 @@ struct fsmc_regs {
#define FSMC_THOLD_4 (4 << 16)
#define FSMC_THIZ_1 (1 << 24)
-/* peripid2 register definitions */
-#define FSMC_REVISION_MSK (0xf)
-#define FSMC_REVISION_SHFT (0x4)
-
-#define FSMC_VER1 1
-#define FSMC_VER2 2
-#define FSMC_VER3 3
-#define FSMC_VER4 4
-#define FSMC_VER5 5
-#define FSMC_VER6 6
-#define FSMC_VER7 7
-#define FSMC_VER8 8
-
-static inline uint32_t get_fsmc_version(struct fsmc_regs *regs)
-{
- return (readl(&regs->peripid2) >> FSMC_REVISION_SHFT) &
- FSMC_REVISION_MSK;
-}
-
/*
* There are 13 bytes of ecc for every 512 byte block in FSMC version 8
* and it has to be read consecutively and immediately after the 512
diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h
index fe8d77e..9d5306b 100644
--- a/include/linux/mtd/mtd.h
+++ b/include/linux/mtd/mtd.h
@@ -144,6 +144,17 @@ struct mtd_info {
*/
uint32_t writesize;
+ /*
+ * Size of the write buffer used by the MTD. MTD devices having a write
+ * buffer can write multiple writesize chunks at a time. E.g. while
+ * writing 4 * writesize bytes to a device with 2 * writesize bytes
+ * buffer the MTD driver can (but doesn't have to) do 2 writesize
+ * operations, but not 4. Currently, all NANDs have writebufsize
+ * equivalent to writesize (NAND page size). Some NOR flashes do have
+ * writebufsize greater than writesize.
+ */
+ uint32_t writebufsize;
+
uint32_t oobsize; // Amount of OOB data per block (e.g. 16)
uint32_t oobavail; // Available OOB bytes per block
diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
index 63e17d0..1f489b2 100644
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -448,6 +448,8 @@ struct nand_buffers {
* See the defines for further explanation.
* @badblockpos: [INTERN] position of the bad block marker in the oob
* area.
+ * @badblockbits: [INTERN] number of bits to left-shift the bad block
+ * number
* @cellinfo: [INTERN] MLC/multichip data from chip ident
* @numchips: [INTERN] number of physical chips
* @chipsize: [INTERN] the size of one chip for multichip arrays
diff --git a/include/linux/mtd/onenand.h b/include/linux/mtd/onenand.h
index 0c8815b..ae418e4 100644
--- a/include/linux/mtd/onenand.h
+++ b/include/linux/mtd/onenand.h
@@ -118,6 +118,8 @@ struct onenand_chip {
int (*chip_probe)(struct mtd_info *mtd);
int (*block_markbad)(struct mtd_info *mtd, loff_t ofs);
int (*scan_bbt)(struct mtd_info *mtd);
+ int (*enable)(struct mtd_info *mtd);
+ int (*disable)(struct mtd_info *mtd);
struct completion complete;
int irq;
@@ -137,6 +139,14 @@ struct onenand_chip {
void *bbm;
void *priv;
+
+ /*
+ * Shows that the current operation is composed
+ * of sequence of commands. For example, cache program.
+ * Such command status OnGo bit is checked at the end of
+ * sequence.
+ */
+ unsigned int ongoing;
};
/*
@@ -171,6 +181,9 @@ struct onenand_chip {
#define ONENAND_IS_2PLANE(this) (0)
#endif
+#define ONENAND_IS_CACHE_PROGRAM(this) \
+ (this->options & ONENAND_HAS_CACHE_PROGRAM)
+
/* Check byte access in OneNAND */
#define ONENAND_CHECK_BYTE_ACCESS(addr) (addr & 0x1)
@@ -181,6 +194,7 @@ struct onenand_chip {
#define ONENAND_HAS_UNLOCK_ALL (0x0002)
#define ONENAND_HAS_2PLANE (0x0004)
#define ONENAND_HAS_4KB_PAGE (0x0008)
+#define ONENAND_HAS_CACHE_PROGRAM (0x0010)
#define ONENAND_SKIP_UNLOCK_CHECK (0x0100)
#define ONENAND_PAGEBUF_ALLOC (0x1000)
#define ONENAND_OOBBUF_ALLOC (0x2000)
diff --git a/include/linux/mtd/partitions.h b/include/linux/mtd/partitions.h
index 2b54316..4a0a8ba 100644
--- a/include/linux/mtd/partitions.h
+++ b/include/linux/mtd/partitions.h
@@ -89,7 +89,7 @@ static inline int mtd_has_cmdlinepart(void) { return 1; }
static inline int mtd_has_cmdlinepart(void) { return 0; }
#endif
-int mtd_is_master(struct mtd_info *mtd);
+int mtd_is_partition(struct mtd_info *mtd);
int mtd_add_partition(struct mtd_info *master, char *name,
long long offset, long long length);
int mtd_del_partition(struct mtd_info *master, int partno);
diff --git a/include/linux/namei.h b/include/linux/namei.h
index 18d06ad..f276d4f 100644
--- a/include/linux/namei.h
+++ b/include/linux/namei.h
@@ -45,6 +45,7 @@ enum {LAST_NORM, LAST_ROOT, LAST_DOT, LAST_DOTDOT, LAST_BIND};
* - ending slashes ok even for nonexistent files
* - internal "there are more path components" flag
* - dentry cache is untrusted; force a real lookup
+ * - suppress terminal automount
*/
#define LOOKUP_FOLLOW 0x0001
#define LOOKUP_DIRECTORY 0x0002
@@ -53,6 +54,7 @@ enum {LAST_NORM, LAST_ROOT, LAST_DOT, LAST_DOTDOT, LAST_BIND};
#define LOOKUP_PARENT 0x0010
#define LOOKUP_REVAL 0x0020
#define LOOKUP_RCU 0x0040
+#define LOOKUP_NO_AUTOMOUNT 0x0080
/*
* Intent data
*/
@@ -79,7 +81,8 @@ extern struct file *lookup_instantiate_filp(struct nameidata *nd, struct dentry
extern struct dentry *lookup_one_len(const char *, struct dentry *, int);
-extern int follow_down(struct path *);
+extern int follow_down_one(struct path *);
+extern int follow_down(struct path *, bool);
extern int follow_up(struct path *);
extern struct dentry *lock_rename(struct dentry *, struct dentry *);
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index be4957c..d971346 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -520,9 +520,6 @@ struct netdev_queue {
* please use this field instead of dev->trans_start
*/
unsigned long trans_start;
- u64 tx_bytes;
- u64 tx_packets;
- u64 tx_dropped;
} ____cacheline_aligned_in_smp;
static inline int netdev_queue_numa_node_read(const struct netdev_queue *q)
@@ -2265,8 +2262,6 @@ extern void dev_load(struct net *net, const char *name);
extern void dev_mcast_init(void);
extern struct rtnl_link_stats64 *dev_get_stats(struct net_device *dev,
struct rtnl_link_stats64 *storage);
-extern void dev_txq_stats_fold(const struct net_device *dev,
- struct rtnl_link_stats64 *stats);
extern int netdev_max_backlog;
extern int netdev_tstamp_prequeue;
diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h
index 9b46300..134716e 100644
--- a/include/linux/nfs4.h
+++ b/include/linux/nfs4.h
@@ -65,6 +65,9 @@
#define NFS4_CDFC4_FORE 0x1
#define NFS4_CDFC4_BACK 0x2
+#define NFS4_CDFC4_BOTH 0x3
+#define NFS4_CDFC4_FORE_OR_BOTH 0x3
+#define NFS4_CDFC4_BACK_OR_BOTH 0x7
#define NFS4_SET_TO_SERVER_TIME 0
#define NFS4_SET_TO_CLIENT_TIME 1
@@ -140,6 +143,9 @@
#define SEQ4_STATUS_CB_PATH_DOWN_SESSION 0x00000200
#define SEQ4_STATUS_BACKCHANNEL_FAULT 0x00000400
+#define NFS4_SECINFO_STYLE4_CURRENT_FH 0
+#define NFS4_SECINFO_STYLE4_PARENT 1
+
#define NFS4_MAX_UINT64 (~(u64)0)
/* An NFS4 sessions server must support at least NFS4_MAX_OPS operations.
diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h
index 0779bb8..6023efa 100644
--- a/include/linux/nfs_fs.h
+++ b/include/linux/nfs_fs.h
@@ -215,7 +215,6 @@ struct nfs_inode {
#define NFS_INO_ADVISE_RDPLUS (0) /* advise readdirplus */
#define NFS_INO_STALE (1) /* possible stale inode */
#define NFS_INO_ACL_LRU_SET (2) /* Inode is on the LRU list */
-#define NFS_INO_MOUNTPOINT (3) /* inode is remote mountpoint */
#define NFS_INO_FLUSHING (4) /* inode is flushing out data */
#define NFS_INO_FSCACHE (5) /* inode can be cached by FS-Cache */
#define NFS_INO_FSCACHE_LOCK (6) /* FS-Cache cookie management lock */
diff --git a/include/linux/nfsd/export.h b/include/linux/nfsd/export.h
index 8ae78a6..bd31615 100644
--- a/include/linux/nfsd/export.h
+++ b/include/linux/nfsd/export.h
@@ -35,7 +35,7 @@
#define NFSEXP_NOHIDE 0x0200
#define NFSEXP_NOSUBTREECHECK 0x0400
#define NFSEXP_NOAUTHNLM 0x0800 /* Don't authenticate NLM requests - just trust */
-#define NFSEXP_MSNFS 0x1000 /* do silly things that MS clients expect */
+#define NFSEXP_MSNFS 0x1000 /* do silly things that MS clients expect; no longer supported */
#define NFSEXP_FSID 0x2000
#define NFSEXP_CROSSMOUNT 0x4000
#define NFSEXP_NOACL 0x8000 /* reserved for possible ACL related use */
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index 2b89b71..821ffb9 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -148,6 +148,10 @@
* @NL80211_CMD_SET_MPATH: Set mesh path attributes for mesh path to
* destination %NL80211_ATTR_MAC on the interface identified by
* %NL80211_ATTR_IFINDEX.
+ * @NL80211_CMD_NEW_MPATH: Create a new mesh path for the destination given by
+ * %NL80211_ATTR_MAC via %NL80211_ATTR_MPATH_NEXT_HOP.
+ * @NL80211_CMD_DEL_MPATH: Delete a mesh path to the destination given by
+ * %NL80211_ATTR_MAC.
* @NL80211_CMD_NEW_PATH: Add a mesh path with given attributes to the
* the interface identified by %NL80211_ATTR_IFINDEX.
* @NL80211_CMD_DEL_PATH: Remove a mesh path identified by %NL80211_ATTR_MAC
@@ -612,7 +616,7 @@ enum nl80211_commands {
* consisting of a nested array.
*
* @NL80211_ATTR_MESH_ID: mesh id (1-32 bytes).
- * @NL80211_ATTR_PLINK_ACTION: action to perform on the mesh peer link.
+ * @NL80211_ATTR_STA_PLINK_ACTION: action to perform on the mesh peer link.
* @NL80211_ATTR_MPATH_NEXT_HOP: MAC address of the next hop for a mesh path.
* @NL80211_ATTR_MPATH_INFO: information about a mesh_path, part of mesh path
* info given for %NL80211_CMD_GET_MPATH, nested attribute described at
@@ -879,7 +883,9 @@ enum nl80211_commands {
* See &enum nl80211_key_default_types.
*
* @NL80211_ATTR_MESH_SETUP: Optional mesh setup parameters. These cannot be
- * changed once the mesh is active.
+ * changed once the mesh is active.
+ * @NL80211_ATTR_MESH_CONFIG: Mesh configuration parameters, a nested attribute
+ * containing attributes from &enum nl80211_meshconf_params.
*
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
@@ -1225,8 +1231,6 @@ enum nl80211_rate_info {
* @NL80211_STA_INFO_INACTIVE_TIME: time since last activity (u32, msecs)
* @NL80211_STA_INFO_RX_BYTES: total received bytes (u32, from this station)
* @NL80211_STA_INFO_TX_BYTES: total transmitted bytes (u32, to this station)
- * @__NL80211_STA_INFO_AFTER_LAST: internal
- * @NL80211_STA_INFO_MAX: highest possible station info attribute
* @NL80211_STA_INFO_SIGNAL: signal strength of last received PPDU (u8, dBm)
* @NL80211_STA_INFO_TX_BITRATE: current unicast tx rate, nested attribute
* containing info as possible, see &enum nl80211_sta_info_txrate.
@@ -1236,6 +1240,11 @@ enum nl80211_rate_info {
* @NL80211_STA_INFO_TX_RETRIES: total retries (u32, to this station)
* @NL80211_STA_INFO_TX_FAILED: total failed packets (u32, to this station)
* @NL80211_STA_INFO_SIGNAL_AVG: signal strength average (u8, dBm)
+ * @NL80211_STA_INFO_LLID: the station's mesh LLID
+ * @NL80211_STA_INFO_PLID: the station's mesh PLID
+ * @NL80211_STA_INFO_PLINK_STATE: peer link state for the station
+ * @__NL80211_STA_INFO_AFTER_LAST: internal
+ * @NL80211_STA_INFO_MAX: highest possible station info attribute
*/
enum nl80211_sta_info {
__NL80211_STA_INFO_INVALID,
@@ -1626,7 +1635,7 @@ enum nl80211_mntr_flags {
* @NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME: The interval of time (in TUs)
* that it takes for an HWMP information element to propagate across the mesh
*
- * @NL80211_MESHCONF_ROOTMODE: whether root mode is enabled or not
+ * @NL80211_MESHCONF_HWMP_ROOTMODE: whether root mode is enabled or not
*
* @NL80211_MESHCONF_ELEMENT_TTL: specifies the value of TTL field set at a
* source mesh point for path selection elements.
@@ -1678,6 +1687,7 @@ enum nl80211_meshconf_params {
* element that vendors will use to identify the path selection methods and
* metrics in use.
*
+ * @NL80211_MESH_SETUP_ATTR_MAX: highest possible mesh setup attribute number
* @__NL80211_MESH_SETUP_ATTR_AFTER_LAST: Internal use
*/
enum nl80211_mesh_setup_params {
diff --git a/include/linux/of_fdt.h b/include/linux/of_fdt.h
index 0ef22a1..c84d900 100644
--- a/include/linux/of_fdt.h
+++ b/include/linux/of_fdt.h
@@ -97,7 +97,7 @@ extern void early_init_dt_check_for_initrd(unsigned long node);
extern int early_init_dt_scan_memory(unsigned long node, const char *uname,
int depth, void *data);
extern void early_init_dt_add_memory_arch(u64 base, u64 size);
-extern u64 early_init_dt_alloc_memory_arch(u64 size, u64 align);
+extern void * early_init_dt_alloc_memory_arch(u64 size, u64 align);
extern u64 dt_mem_next_cell(int s, __be32 **cellp);
/*
diff --git a/include/linux/page_cgroup.h b/include/linux/page_cgroup.h
index 5b0c971..6d6cb7a 100644
--- a/include/linux/page_cgroup.h
+++ b/include/linux/page_cgroup.h
@@ -42,9 +42,6 @@ enum {
/* flags for mem_cgroup and file and I/O status */
PCG_MOVE_LOCK, /* For race between move_account v.s. following bits */
PCG_FILE_MAPPED, /* page is accounted as "mapped" */
- PCG_FILE_DIRTY, /* page is dirty */
- PCG_FILE_WRITEBACK, /* page is under writeback */
- PCG_FILE_UNSTABLE_NFS, /* page is NFS unstable */
/* No lock in page_cgroup */
PCG_ACCT_LRU, /* page has been accounted for (under lru_lock) */
};
@@ -65,10 +62,6 @@ static inline void ClearPageCgroup##uname(struct page_cgroup *pc) \
static inline int TestClearPageCgroup##uname(struct page_cgroup *pc) \
{ return test_and_clear_bit(PCG_##lname, &pc->flags); }
-#define TESTSETPCGFLAG(uname, lname) \
-static inline int TestSetPageCgroup##uname(struct page_cgroup *pc) \
- { return test_and_set_bit(PCG_##lname, &pc->flags); }
-
/* Cache flag is set only once (at allocation) */
TESTPCGFLAG(Cache, CACHE)
CLEARPCGFLAG(Cache, CACHE)
@@ -88,22 +81,6 @@ SETPCGFLAG(FileMapped, FILE_MAPPED)
CLEARPCGFLAG(FileMapped, FILE_MAPPED)
TESTPCGFLAG(FileMapped, FILE_MAPPED)
-SETPCGFLAG(FileDirty, FILE_DIRTY)
-CLEARPCGFLAG(FileDirty, FILE_DIRTY)
-TESTPCGFLAG(FileDirty, FILE_DIRTY)
-TESTCLEARPCGFLAG(FileDirty, FILE_DIRTY)
-TESTSETPCGFLAG(FileDirty, FILE_DIRTY)
-
-SETPCGFLAG(FileWriteback, FILE_WRITEBACK)
-CLEARPCGFLAG(FileWriteback, FILE_WRITEBACK)
-TESTPCGFLAG(FileWriteback, FILE_WRITEBACK)
-
-SETPCGFLAG(FileUnstableNFS, FILE_UNSTABLE_NFS)
-CLEARPCGFLAG(FileUnstableNFS, FILE_UNSTABLE_NFS)
-TESTPCGFLAG(FileUnstableNFS, FILE_UNSTABLE_NFS)
-TESTCLEARPCGFLAG(FileUnstableNFS, FILE_UNSTABLE_NFS)
-TESTSETPCGFLAG(FileUnstableNFS, FILE_UNSTABLE_NFS)
-
SETPCGFLAG(Migration, MIGRATION)
CLEARPCGFLAG(Migration, MIGRATION)
TESTPCGFLAG(Migration, MIGRATION)
diff --git a/include/linux/path.h b/include/linux/path.h
index a581e8c..edc98de 100644
--- a/include/linux/path.h
+++ b/include/linux/path.h
@@ -10,9 +10,7 @@ struct path {
};
extern void path_get(struct path *);
-extern void path_get_long(struct path *);
extern void path_put(struct path *);
-extern void path_put_long(struct path *);
static inline int path_equal(const struct path *path1, const struct path *path2)
{
diff --git a/include/linux/pci-acpi.h b/include/linux/pci-acpi.h
index c8b6473..4462350 100644
--- a/include/linux/pci-acpi.h
+++ b/include/linux/pci-acpi.h
@@ -35,9 +35,12 @@ static inline acpi_handle acpi_pci_get_bridge_handle(struct pci_bus *pbus)
return acpi_get_pci_rootbridge_handle(pci_domain_nr(pbus),
pbus->number);
}
+#endif
+
+#ifdef CONFIG_ACPI_APEI
+extern bool aer_acpi_firmware_first(void);
#else
-static inline acpi_handle acpi_find_root_bridge_handle(struct pci_dev *pdev)
-{ return NULL; }
+static inline bool aer_acpi_firmware_first(void) { return false; }
#endif
#endif /* _PCI_ACPI_H_ */
diff --git a/include/linux/pci-aspm.h b/include/linux/pci-aspm.h
index 91ba0b3..ce681051 100644
--- a/include/linux/pci-aspm.h
+++ b/include/linux/pci-aspm.h
@@ -27,6 +27,7 @@ extern void pcie_aspm_init_link_state(struct pci_dev *pdev);
extern void pcie_aspm_exit_link_state(struct pci_dev *pdev);
extern void pcie_aspm_pm_state_change(struct pci_dev *pdev);
extern void pci_disable_link_state(struct pci_dev *pdev, int state);
+extern void pcie_clear_aspm(void);
extern void pcie_no_aspm(void);
#else
static inline void pcie_aspm_init_link_state(struct pci_dev *pdev)
@@ -41,7 +42,9 @@ static inline void pcie_aspm_pm_state_change(struct pci_dev *pdev)
static inline void pci_disable_link_state(struct pci_dev *pdev, int state)
{
}
-
+static inline void pcie_clear_aspm(void)
+{
+}
static inline void pcie_no_aspm(void)
{
}
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 7454408..559d028 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -806,7 +806,7 @@ size_t pci_get_rom_size(struct pci_dev *pdev, void __iomem *rom, size_t size);
/* Power management related routines */
int pci_save_state(struct pci_dev *dev);
-int pci_restore_state(struct pci_dev *dev);
+void pci_restore_state(struct pci_dev *dev);
int __pci_complete_power_transition(struct pci_dev *dev, pci_power_t state);
int pci_set_power_state(struct pci_dev *dev, pci_power_t state);
pci_power_t pci_choose_state(struct pci_dev *dev, pm_message_t state);
@@ -820,7 +820,6 @@ int pci_prepare_to_sleep(struct pci_dev *dev);
int pci_back_from_sleep(struct pci_dev *dev);
bool pci_dev_run_wake(struct pci_dev *dev);
bool pci_check_pme_status(struct pci_dev *dev);
-void pci_wakeup_event(struct pci_dev *dev);
void pci_pme_wakeup_bus(struct pci_bus *bus);
static inline int pci_enable_wake(struct pci_dev *dev, pci_power_t state,
@@ -994,6 +993,14 @@ extern void pci_restore_msi_state(struct pci_dev *dev);
extern int pci_msi_enabled(void);
#endif
+#ifdef CONFIG_PCIEPORTBUS
+extern bool pcie_ports_disabled;
+extern bool pcie_ports_auto;
+#else
+#define pcie_ports_disabled true
+#define pcie_ports_auto false
+#endif
+
#ifndef CONFIG_PCIEASPM
static inline int pcie_aspm_enabled(void)
{
@@ -1003,6 +1010,14 @@ static inline int pcie_aspm_enabled(void)
extern int pcie_aspm_enabled(void);
#endif
+#ifdef CONFIG_PCIEAER
+void pci_no_aer(void);
+bool pci_aer_available(void);
+#else
+static inline void pci_no_aer(void) { }
+static inline bool pci_aer_available(void) { return false; }
+#endif
+
#ifndef CONFIG_PCIE_ECRC
static inline void pcie_set_ecrc_checking(struct pci_dev *dev)
{
@@ -1168,10 +1183,8 @@ static inline int pci_save_state(struct pci_dev *dev)
return 0;
}
-static inline int pci_restore_state(struct pci_dev *dev)
-{
- return 0;
-}
+static inline void pci_restore_state(struct pci_dev *dev)
+{ }
static inline int pci_set_power_state(struct pci_dev *dev, pci_power_t state)
{
diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
index ae0dc45..3adb06e 100644
--- a/include/linux/pci_ids.h
+++ b/include/linux/pci_ids.h
@@ -2478,7 +2478,8 @@
#define PCI_DEVICE_ID_INTEL_COUGARPOINT_LPC_MIN 0x1c41
#define PCI_DEVICE_ID_INTEL_COUGARPOINT_LPC_MAX 0x1c5f
#define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS 0x1d22
-#define PCI_DEVICE_ID_INTEL_PATSBURG_LPC 0x1d40
+#define PCI_DEVICE_ID_INTEL_PATSBURG_LPC_0 0x1d40
+#define PCI_DEVICE_ID_INTEL_PATSBURG_LPC_1 0x1d41
#define PCI_DEVICE_ID_INTEL_82801AA_0 0x2410
#define PCI_DEVICE_ID_INTEL_82801AA_1 0x2411
#define PCI_DEVICE_ID_INTEL_82801AA_3 0x2413
diff --git a/include/linux/pci_regs.h b/include/linux/pci_regs.h
index af83076..5b7e6b1 100644
--- a/include/linux/pci_regs.h
+++ b/include/linux/pci_regs.h
@@ -309,6 +309,14 @@
#define PCI_MSIX_PBA 8
#define PCI_MSIX_FLAGS_BIRMASK (7 << 0)
+/* MSI-X entry's format */
+#define PCI_MSIX_ENTRY_SIZE 16
+#define PCI_MSIX_ENTRY_LOWER_ADDR 0
+#define PCI_MSIX_ENTRY_UPPER_ADDR 4
+#define PCI_MSIX_ENTRY_DATA 8
+#define PCI_MSIX_ENTRY_VECTOR_CTRL 12
+#define PCI_MSIX_ENTRY_CTRL_MASKBIT 1
+
/* CompactPCI Hotswap Register */
#define PCI_CHSWP_CSR 2 /* Control and Status Register */
@@ -496,6 +504,8 @@
#define PCI_EXP_RTCTL_CRSSVE 0x10 /* CRS Software Visibility Enable */
#define PCI_EXP_RTCAP 30 /* Root Capabilities */
#define PCI_EXP_RTSTA 32 /* Root Status */
+#define PCI_EXP_RTSTA_PME 0x10000 /* PME status */
+#define PCI_EXP_RTSTA_PENDING 0x20000 /* PME pending */
#define PCI_EXP_DEVCAP2 36 /* Device Capabilities 2 */
#define PCI_EXP_DEVCAP2_ARI 0x20 /* Alternative Routing-ID */
#define PCI_EXP_DEVCTL2 40 /* Device Control 2 */
diff --git a/include/linux/power/gpio-charger.h b/include/linux/power/gpio-charger.h
new file mode 100644
index 0000000..de1dfe0
--- /dev/null
+++ b/include/linux/power/gpio-charger.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de>
+ *
+ * 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.
+ *
+ * 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.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef __LINUX_POWER_GPIO_CHARGER_H__
+#define __LINUX_POWER_GPIO_CHARGER_H__
+
+#include <linux/power_supply.h>
+#include <linux/types.h>
+
+/**
+ * struct gpio_charger_platform_data - platform_data for gpio_charger devices
+ * @name: Name for the chargers power_supply device
+ * @type: Type of the charger
+ * @gpio: GPIO which is used to indicate the chargers status
+ * @gpio_active_low: Should be set to 1 if the GPIO is active low otherwise 0
+ * @supplied_to: Array of battery names to which this chargers supplies power
+ * @num_supplicants: Number of entries in the supplied_to array
+ */
+struct gpio_charger_platform_data {
+ const char *name;
+ enum power_supply_type type;
+
+ int gpio;
+ int gpio_active_low;
+
+ char **supplied_to;
+ size_t num_supplicants;
+};
+
+#endif
diff --git a/include/linux/power/max17042_battery.h b/include/linux/power/max17042_battery.h
new file mode 100644
index 0000000..7995deb
--- /dev/null
+++ b/include/linux/power/max17042_battery.h
@@ -0,0 +1,30 @@
+/*
+ * Fuel gauge driver for Maxim 17042 / 8966 / 8997
+ * Note that Maxim 8966 and 8997 are mfd and this is its subdevice.
+ *
+ * Copyright (C) 2011 Samsung Electronics
+ * MyungJoo Ham <myungjoo.ham@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.
+ *
+ * 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 __MAX17042_BATTERY_H_
+#define __MAX17042_BATTERY_H_
+
+struct max17042_platform_data {
+ bool enable_current_sense;
+};
+
+#endif /* __MAX17042_BATTERY_H_ */
diff --git a/include/linux/quota.h b/include/linux/quota.h
index 94c1f03..9a85412 100644
--- a/include/linux/quota.h
+++ b/include/linux/quota.h
@@ -322,9 +322,12 @@ struct dquot_operations {
qsize_t *(*get_reserved_space) (struct inode *);
};
+struct path;
+
/* Operations handling requests from userspace */
struct quotactl_ops {
- int (*quota_on)(struct super_block *, int, int, char *);
+ int (*quota_on)(struct super_block *, int, int, struct path *);
+ int (*quota_on_meta)(struct super_block *, int, int);
int (*quota_off)(struct super_block *, int);
int (*quota_sync)(struct super_block *, int, int);
int (*get_info)(struct super_block *, int, struct if_dqinfo *);
diff --git a/include/linux/quotaops.h b/include/linux/quotaops.h
index 223b14c..eb354f6 100644
--- a/include/linux/quotaops.h
+++ b/include/linux/quotaops.h
@@ -76,11 +76,9 @@ int dquot_mark_dquot_dirty(struct dquot *dquot);
int dquot_file_open(struct inode *inode, struct file *file);
-int dquot_quota_on(struct super_block *sb, int type, int format_id,
- char *path);
int dquot_enable(struct inode *inode, int type, int format_id,
unsigned int flags);
-int dquot_quota_on_path(struct super_block *sb, int type, int format_id,
+int dquot_quota_on(struct super_block *sb, int type, int format_id,
struct path *path);
int dquot_quota_on_mount(struct super_block *sb, char *qf_name,
int format_id, int type);
diff --git a/include/linux/rculist_bl.h b/include/linux/rculist_bl.h
index b872b49..cf1244f 100644
--- a/include/linux/rculist_bl.h
+++ b/include/linux/rculist_bl.h
@@ -11,7 +11,8 @@ static inline void hlist_bl_set_first_rcu(struct hlist_bl_head *h,
struct hlist_bl_node *n)
{
LIST_BL_BUG_ON((unsigned long)n & LIST_BL_LOCKMASK);
- LIST_BL_BUG_ON(!((unsigned long)h->first & LIST_BL_LOCKMASK));
+ LIST_BL_BUG_ON(((unsigned long)h->first & LIST_BL_LOCKMASK) !=
+ LIST_BL_LOCKMASK);
rcu_assign_pointer(h->first,
(struct hlist_bl_node *)((unsigned long)n | LIST_BL_LOCKMASK));
}
diff --git a/include/linux/rtc.h b/include/linux/rtc.h
index 3c995b4..a0b639f 100644
--- a/include/linux/rtc.h
+++ b/include/linux/rtc.h
@@ -235,8 +235,6 @@ extern int rtc_irq_set_freq(struct rtc_device *rtc,
struct rtc_task *task, int freq);
extern int rtc_update_irq_enable(struct rtc_device *rtc, unsigned int enabled);
extern int rtc_alarm_irq_enable(struct rtc_device *rtc, unsigned int enabled);
-extern int rtc_dev_update_irq_enable_emul(struct rtc_device *rtc,
- unsigned int enabled);
void rtc_aie_update_irq(void *private);
void rtc_uie_update_irq(void *private);
@@ -246,8 +244,6 @@ int rtc_register(rtc_task_t *task);
int rtc_unregister(rtc_task_t *task);
int rtc_control(rtc_task_t *t, unsigned int cmd, unsigned long arg);
-void rtc_timer_enqueue(struct rtc_device *rtc, struct rtc_timer *timer);
-void rtc_timer_remove(struct rtc_device *rtc, struct rtc_timer *timer);
void rtc_timer_init(struct rtc_timer *timer, void (*f)(void* p), void* data);
int rtc_timer_start(struct rtc_device *rtc, struct rtc_timer* timer,
ktime_t expires, ktime_t period);
diff --git a/include/linux/s3c_adc_battery.h b/include/linux/s3c_adc_battery.h
index dbce22f..fbe58b7 100644
--- a/include/linux/s3c_adc_battery.h
+++ b/include/linux/s3c_adc_battery.h
@@ -14,6 +14,7 @@ struct s3c_adc_bat_pdata {
void (*disable_charger)(void);
int gpio_charge_finished;
+ int gpio_inverted;
const struct s3c_adc_bat_thresh *lut_noac;
unsigned int lut_noac_cnt;
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index 20ec0a64..bf221d6 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -255,6 +255,11 @@ typedef unsigned int sk_buff_data_t;
typedef unsigned char *sk_buff_data_t;
#endif
+#if defined(CONFIG_NF_DEFRAG_IPV4) || defined(CONFIG_NF_DEFRAG_IPV4_MODULE) || \
+ defined(CONFIG_NF_DEFRAG_IPV6) || defined(CONFIG_NF_DEFRAG_IPV6_MODULE)
+#define NET_SKBUFF_NF_DEFRAG_NEEDED 1
+#endif
+
/**
* struct sk_buff - socket buffer
* @next: Next buffer in list
@@ -362,6 +367,8 @@ struct sk_buff {
void (*destructor)(struct sk_buff *skb);
#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
struct nf_conntrack *nfct;
+#endif
+#ifdef NET_SKBUFF_NF_DEFRAG_NEEDED
struct sk_buff *nfct_reasm;
#endif
#ifdef CONFIG_BRIDGE_NETFILTER
@@ -2057,6 +2064,8 @@ static inline void nf_conntrack_get(struct nf_conntrack *nfct)
if (nfct)
atomic_inc(&nfct->use);
}
+#endif
+#ifdef NET_SKBUFF_NF_DEFRAG_NEEDED
static inline void nf_conntrack_get_reasm(struct sk_buff *skb)
{
if (skb)
@@ -2085,6 +2094,8 @@ static inline void nf_reset(struct sk_buff *skb)
#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
nf_conntrack_put(skb->nfct);
skb->nfct = NULL;
+#endif
+#ifdef NET_SKBUFF_NF_DEFRAG_NEEDED
nf_conntrack_put_reasm(skb->nfct_reasm);
skb->nfct_reasm = NULL;
#endif
@@ -2101,6 +2112,8 @@ static inline void __nf_copy(struct sk_buff *dst, const struct sk_buff *src)
dst->nfct = src->nfct;
nf_conntrack_get(src->nfct);
dst->nfctinfo = src->nfctinfo;
+#endif
+#ifdef NET_SKBUFF_NF_DEFRAG_NEEDED
dst->nfct_reasm = src->nfct_reasm;
nf_conntrack_get_reasm(src->nfct_reasm);
#endif
@@ -2114,6 +2127,8 @@ static inline void nf_copy(struct sk_buff *dst, const struct sk_buff *src)
{
#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
nf_conntrack_put(dst->nfct);
+#endif
+#ifdef NET_SKBUFF_NF_DEFRAG_NEEDED
nf_conntrack_put_reasm(dst->nfct_reasm);
#endif
#ifdef CONFIG_BRIDGE_NETFILTER
diff --git a/include/linux/sunrpc/cache.h b/include/linux/sunrpc/cache.h
index 78aa104..7898ea1 100644
--- a/include/linux/sunrpc/cache.h
+++ b/include/linux/sunrpc/cache.h
@@ -256,10 +256,13 @@ static inline time_t get_expiry(char **bpp)
return rv - boot.tv_sec;
}
+#ifdef CONFIG_NFSD_DEPRECATED
static inline void sunrpc_invalidate(struct cache_head *h,
struct cache_detail *detail)
{
h->expiry_time = seconds_since_boot() - 1;
detail->nextcheck = seconds_since_boot();
}
+#endif /* CONFIG_NFSD_DEPRECATED */
+
#endif /* _LINUX_SUNRPC_CACHE_H_ */
diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h
index c81d4d8..ea29330 100644
--- a/include/linux/sunrpc/svc.h
+++ b/include/linux/sunrpc/svc.h
@@ -269,6 +269,7 @@ struct svc_rqst {
struct cache_req rq_chandle; /* handle passed to caches for
* request delaying
*/
+ bool rq_dropme;
/* Catering to nfsd */
struct auth_domain * rq_client; /* RPC peer info */
struct auth_domain * rq_gssclient; /* "gss/"-style peer info */
diff --git a/include/linux/sunrpc/svc_xprt.h b/include/linux/sunrpc/svc_xprt.h
index 357da5e..059877b 100644
--- a/include/linux/sunrpc/svc_xprt.h
+++ b/include/linux/sunrpc/svc_xprt.h
@@ -63,7 +63,6 @@ struct svc_xprt {
#define XPT_LISTENER 11 /* listening endpoint */
#define XPT_CACHE_AUTH 12 /* cache auth info */
- struct svc_pool *xpt_pool; /* current pool iff queued */
struct svc_serv *xpt_server; /* service for transport */
atomic_t xpt_reserved; /* space on outq that is rsvd */
struct mutex xpt_mutex; /* to serialize sending data */
@@ -81,6 +80,7 @@ struct svc_xprt {
void *xpt_bc_sid; /* back channel session ID */
struct net *xpt_net;
+ struct rpc_xprt *xpt_bc_xprt; /* NFSv4.1 backchannel */
};
static inline void unregister_xpt_user(struct svc_xprt *xpt, struct svc_xpt_user *u)
diff --git a/include/linux/sunrpc/svcsock.h b/include/linux/sunrpc/svcsock.h
index 1b353a7..04dba23 100644
--- a/include/linux/sunrpc/svcsock.h
+++ b/include/linux/sunrpc/svcsock.h
@@ -28,7 +28,6 @@ struct svc_sock {
/* private TCP part */
u32 sk_reclen; /* length of record */
u32 sk_tcplen; /* current read length */
- struct rpc_xprt *sk_bc_xprt; /* NFSv4.1 backchannel xprt */
};
/*
diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h
index 89d10d2..bef0f53 100644
--- a/include/linux/sunrpc/xprt.h
+++ b/include/linux/sunrpc/xprt.h
@@ -321,6 +321,7 @@ void xprt_conditional_disconnect(struct rpc_xprt *xprt, unsigned int cookie);
#define XPRT_CLOSING (6)
#define XPRT_CONNECTION_ABORT (7)
#define XPRT_CONNECTION_CLOSE (8)
+#define XPRT_INITIALIZED (9)
static inline void xprt_set_connected(struct rpc_xprt *xprt)
{
diff --git a/include/linux/suspend.h b/include/linux/suspend.h
index c1f4998..5a89e36 100644
--- a/include/linux/suspend.h
+++ b/include/linux/suspend.h
@@ -258,23 +258,6 @@ static inline int hibernate(void) { return -ENOSYS; }
static inline bool system_entering_hibernation(void) { return false; }
#endif /* CONFIG_HIBERNATION */
-#ifdef CONFIG_SUSPEND_NVS
-extern int suspend_nvs_register(unsigned long start, unsigned long size);
-extern int suspend_nvs_alloc(void);
-extern void suspend_nvs_free(void);
-extern void suspend_nvs_save(void);
-extern void suspend_nvs_restore(void);
-#else /* CONFIG_SUSPEND_NVS */
-static inline int suspend_nvs_register(unsigned long a, unsigned long b)
-{
- return 0;
-}
-static inline int suspend_nvs_alloc(void) { return 0; }
-static inline void suspend_nvs_free(void) {}
-static inline void suspend_nvs_save(void) {}
-static inline void suspend_nvs_restore(void) {}
-#endif /* CONFIG_SUSPEND_NVS */
-
#ifdef CONFIG_PM_SLEEP
void save_processor_state(void);
void restore_processor_state(void);
diff --git a/include/linux/thermal.h b/include/linux/thermal.h
index 1de8b9eb..8651556 100644
--- a/include/linux/thermal.h
+++ b/include/linux/thermal.h
@@ -77,7 +77,7 @@ struct thermal_cooling_device {
char type[THERMAL_NAME_LENGTH];
struct device device;
void *devdata;
- struct thermal_cooling_device_ops *ops;
+ const struct thermal_cooling_device_ops *ops;
struct list_head node;
};
@@ -114,7 +114,7 @@ struct thermal_zone_device {
int last_temperature;
bool passive;
unsigned int forced_passive;
- struct thermal_zone_device_ops *ops;
+ const struct thermal_zone_device_ops *ops;
struct list_head cooling_devices;
struct idr idr;
struct mutex lock; /* protect cooling devices list */
@@ -127,13 +127,41 @@ struct thermal_zone_device {
struct thermal_hwmon_attr temp_crit; /* hwmon sys attr */
#endif
};
+/* Adding event notification support elements */
+#define THERMAL_GENL_FAMILY_NAME "thermal_event"
+#define THERMAL_GENL_VERSION 0x01
+#define THERMAL_GENL_MCAST_GROUP_NAME "thermal_mc_group"
+
+enum events {
+ THERMAL_AUX0,
+ THERMAL_AUX1,
+ THERMAL_CRITICAL,
+ THERMAL_DEV_FAULT,
+};
+
+struct thermal_genl_event {
+ u32 orig;
+ enum events event;
+};
+/* attributes of thermal_genl_family */
+enum {
+ THERMAL_GENL_ATTR_UNSPEC,
+ THERMAL_GENL_ATTR_EVENT,
+ __THERMAL_GENL_ATTR_MAX,
+};
+#define THERMAL_GENL_ATTR_MAX (__THERMAL_GENL_ATTR_MAX - 1)
+
+/* commands supported by the thermal_genl_family */
+enum {
+ THERMAL_GENL_CMD_UNSPEC,
+ THERMAL_GENL_CMD_EVENT,
+ __THERMAL_GENL_CMD_MAX,
+};
+#define THERMAL_GENL_CMD_MAX (__THERMAL_GENL_CMD_MAX - 1)
struct thermal_zone_device *thermal_zone_device_register(char *, int, void *,
- struct
- thermal_zone_device_ops
- *, int tc1, int tc2,
- int passive_freq,
- int polling_freq);
+ const struct thermal_zone_device_ops *, int tc1, int tc2,
+ int passive_freq, int polling_freq);
void thermal_zone_device_unregister(struct thermal_zone_device *);
int thermal_zone_bind_cooling_device(struct thermal_zone_device *, int,
@@ -142,9 +170,8 @@ int thermal_zone_unbind_cooling_device(struct thermal_zone_device *, int,
struct thermal_cooling_device *);
void thermal_zone_device_update(struct thermal_zone_device *);
struct thermal_cooling_device *thermal_cooling_device_register(char *, void *,
- struct
- thermal_cooling_device_ops
- *);
+ const struct thermal_cooling_device_ops *);
void thermal_cooling_device_unregister(struct thermal_cooling_device *);
+extern int generate_netlink_event(u32 orig, enum events event);
#endif /* __THERMAL_H__ */
diff --git a/include/linux/virtio_config.h b/include/linux/virtio_config.h
index 0093dd7..800617b 100644
--- a/include/linux/virtio_config.h
+++ b/include/linux/virtio_config.h
@@ -109,7 +109,10 @@ static inline bool virtio_has_feature(const struct virtio_device *vdev,
unsigned int fbit)
{
/* Did you forget to fix assumptions on max features? */
- MAYBE_BUILD_BUG_ON(fbit >= 32);
+ if (__builtin_constant_p(fbit))
+ BUILD_BUG_ON(fbit >= 32);
+ else
+ BUG_ON(fbit >= 32);
if (fbit < VIRTIO_TRANSPORT_F_START)
virtio_check_driver_offered_feature(vdev, fbit);
diff --git a/include/media/mt9v011.h b/include/media/mt9v011.h
new file mode 100644
index 0000000..ea29fc7
--- /dev/null
+++ b/include/media/mt9v011.h
@@ -0,0 +1,17 @@
+/* mt9v011 sensor
+ *
+ * Copyright (C) 2011 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * 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 __MT9V011_H__
+#define __MT9V011_H__
+
+struct mt9v011_platform_data {
+ unsigned xtal; /* Hz */
+};
+
+#endif
diff --git a/include/media/rc-core.h b/include/media/rc-core.h
index a23c1fc..2963263 100644
--- a/include/media/rc-core.h
+++ b/include/media/rc-core.h
@@ -183,6 +183,9 @@ static inline void init_ir_raw_event(struct ir_raw_event *ev)
}
#define IR_MAX_DURATION 0xFFFFFFFF /* a bit more than 4 seconds */
+#define US_TO_NS(usec) ((usec) * 1000)
+#define MS_TO_US(msec) ((msec) * 1000)
+#define MS_TO_NS(msec) ((msec) * 1000 * 1000)
void ir_raw_event_handle(struct rc_dev *dev);
int ir_raw_event_store(struct rc_dev *dev, struct ir_raw_event *ev);
diff --git a/include/media/saa7146.h b/include/media/saa7146.h
index ac7ce00..7982714 100644
--- a/include/media/saa7146.h
+++ b/include/media/saa7146.h
@@ -115,7 +115,7 @@ struct saa7146_dev
/* different device locks */
spinlock_t slock;
- struct mutex lock;
+ struct mutex v4l2_lock;
unsigned char __iomem *mem; /* pointer to mapped IO memory */
u32 revision; /* chip revision; needed for bug-workarounds*/
diff --git a/include/media/v4l2-common.h b/include/media/v4l2-common.h
index 2d65b35..a659319 100644
--- a/include/media/v4l2-common.h
+++ b/include/media/v4l2-common.h
@@ -138,21 +138,10 @@ struct v4l2_subdev_ops;
/* Load an i2c module and return an initialized v4l2_subdev struct.
The client_type argument is the name of the chip that's on the adapter. */
-struct v4l2_subdev *v4l2_i2c_new_subdev_cfg(struct v4l2_device *v4l2_dev,
+struct v4l2_subdev *v4l2_i2c_new_subdev(struct v4l2_device *v4l2_dev,
struct i2c_adapter *adapter, const char *client_type,
- int irq, void *platform_data,
u8 addr, const unsigned short *probe_addrs);
-/* Load an i2c module and return an initialized v4l2_subdev struct.
- The client_type argument is the name of the chip that's on the adapter. */
-static inline struct v4l2_subdev *v4l2_i2c_new_subdev(struct v4l2_device *v4l2_dev,
- struct i2c_adapter *adapter, const char *client_type,
- u8 addr, const unsigned short *probe_addrs)
-{
- return v4l2_i2c_new_subdev_cfg(v4l2_dev, adapter, client_type, 0, NULL,
- addr, probe_addrs);
-}
-
struct i2c_board_info;
struct v4l2_subdev *v4l2_i2c_new_subdev_board(struct v4l2_device *v4l2_dev,
diff --git a/include/media/v4l2-ctrls.h b/include/media/v4l2-ctrls.h
index d69ab4a..97d0638 100644
--- a/include/media/v4l2-ctrls.h
+++ b/include/media/v4l2-ctrls.h
@@ -23,6 +23,7 @@
#include <linux/list.h>
#include <linux/device.h>
+#include <linux/videodev2.h>
/* forward references */
struct v4l2_ctrl_handler;
@@ -53,8 +54,10 @@ struct v4l2_ctrl_ops {
* @handler: The handler that owns the control.
* @cluster: Point to start of cluster array.
* @ncontrols: Number of controls in cluster array.
- * @has_new: Internal flag: set when there is a valid new value.
* @done: Internal flag: set for each processed control.
+ * @is_new: Set when the user specified a new value for this control. It
+ * is also set when called from v4l2_ctrl_handler_setup. Drivers
+ * should never set this flag.
* @is_private: If set, then this control is private to its handler and it
* will not be added to any other handlers. Drivers can set
* this flag.
@@ -97,9 +100,9 @@ struct v4l2_ctrl {
struct v4l2_ctrl_handler *handler;
struct v4l2_ctrl **cluster;
unsigned ncontrols;
- unsigned int has_new:1;
unsigned int done:1;
+ unsigned int is_new:1;
unsigned int is_private:1;
unsigned int is_volatile:1;
diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
index b0316a7..daf1e57 100644
--- a/include/media/v4l2-subdev.h
+++ b/include/media/v4l2-subdev.h
@@ -106,10 +106,7 @@ struct v4l2_subdev_io_pin_config {
u8 strength; /* Pin drive strength */
};
-/* s_config: if set, then it is always called by the v4l2_i2c_new_subdev*
- functions after the v4l2_subdev was registered. It is used to pass
- platform data to the subdev which can be used during initialization.
-
+/*
s_io_pin_config: configure one or more chip I/O pins for chips that
multiplex different internal signal pads out to IO pins. This function
takes a pointer to an array of 'n' pin configuration entries, one for
@@ -141,7 +138,6 @@ struct v4l2_subdev_io_pin_config {
struct v4l2_subdev_core_ops {
int (*g_chip_ident)(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip);
int (*log_status)(struct v4l2_subdev *sd);
- int (*s_config)(struct v4l2_subdev *sd, int irq, void *platform_data);
int (*s_io_pin_config)(struct v4l2_subdev *sd, size_t n,
struct v4l2_subdev_io_pin_config *pincfg);
int (*init)(struct v4l2_subdev *sd, u32 val);
@@ -415,6 +411,21 @@ struct v4l2_subdev_ops {
const struct v4l2_subdev_sensor_ops *sensor;
};
+/*
+ * Internal ops. Never call this from drivers, only the v4l2 framework can call
+ * these ops.
+ *
+ * registered: called when this subdev is registered. When called the v4l2_dev
+ * field is set to the correct v4l2_device.
+ *
+ * unregistered: called when this subdev is unregistered. When called the
+ * v4l2_dev field is still set to the correct v4l2_device.
+ */
+struct v4l2_subdev_internal_ops {
+ int (*registered)(struct v4l2_subdev *sd);
+ void (*unregistered)(struct v4l2_subdev *sd);
+};
+
#define V4L2_SUBDEV_NAME_SIZE 32
/* Set this flag if this subdev is a i2c device. */
@@ -431,6 +442,8 @@ struct v4l2_subdev {
u32 flags;
struct v4l2_device *v4l2_dev;
const struct v4l2_subdev_ops *ops;
+ /* Never call these internal ops from within a driver! */
+ const struct v4l2_subdev_internal_ops *internal_ops;
/* The control handler of this subdev. May be NULL. */
struct v4l2_ctrl_handler *ctrl_handler;
/* name must be unique */
diff --git a/include/net/ah.h b/include/net/ah.h
index be7798d..ca95b98 100644
--- a/include/net/ah.h
+++ b/include/net/ah.h
@@ -4,7 +4,7 @@
#include <linux/skbuff.h>
/* This is the maximum truncated ICV length that we know of. */
-#define MAX_AH_AUTH_LEN 16
+#define MAX_AH_AUTH_LEN 64
struct crypto_ahash;
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index bcc9f44..1322695 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -1103,6 +1103,8 @@ struct cfg80211_pmksa {
* @change_mpath: change a given mesh path
* @get_mpath: get a mesh path for the given parameters
* @dump_mpath: dump mesh path callback -- resume dump at index @idx
+ * @join_mesh: join the mesh network with the specified parameters
+ * @leave_mesh: leave the current mesh network
*
* @get_mesh_config: Get the current mesh configuration
*
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 5b3fd5a..62c0ce2 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -337,6 +337,10 @@ struct ieee80211_bss_conf {
* @IEEE80211_TX_CTL_LDPC: tells the driver to use LDPC for this frame
* @IEEE80211_TX_CTL_STBC: Enables Space-Time Block Coding (STBC) for this
* frame and selects the maximum number of streams that it can use.
+ * @IEEE80211_TX_CTL_TX_OFFCHAN: Marks this packet to be transmitted on
+ * the off-channel channel when a remain-on-channel offload is done
+ * in hardware -- normal packets still flow and are expected to be
+ * handled properly by the device.
*
* Note: If you have to add new flags to the enumeration, then don't
* forget to update %IEEE80211_TX_TEMPORARY_FLAGS when necessary.
@@ -1753,6 +1757,16 @@ enum ieee80211_ampdu_mlme_action {
* (also see nl80211.h @NL80211_ATTR_WIPHY_ANTENNA_TX).
*
* @get_antenna: Get current antenna configuration from device (tx_ant, rx_ant).
+ *
+ * @remain_on_channel: Starts an off-channel period on the given channel, must
+ * call back to ieee80211_ready_on_channel() when on that channel. Note
+ * that normal channel traffic is not stopped as this is intended for hw
+ * offload. Frames to transmit on the off-channel channel are transmitted
+ * normally except for the %IEEE80211_TX_CTL_TX_OFFCHAN flag. When the
+ * duration (which will always be non-zero) expires, the driver must call
+ * ieee80211_remain_on_channel_expired(). This callback may sleep.
+ * @cancel_remain_on_channel: Requests that an ongoing off-channel period is
+ * aborted before it expires. This callback may sleep.
*/
struct ieee80211_ops {
int (*tx)(struct ieee80211_hw *hw, struct sk_buff *skb);
diff --git a/include/net/netfilter/ipv6/nf_conntrack_ipv6.h b/include/net/netfilter/ipv6/nf_conntrack_ipv6.h
index 1ee717e..a4c9936 100644
--- a/include/net/netfilter/ipv6/nf_conntrack_ipv6.h
+++ b/include/net/netfilter/ipv6/nf_conntrack_ipv6.h
@@ -7,16 +7,6 @@ extern struct nf_conntrack_l4proto nf_conntrack_l4proto_tcp6;
extern struct nf_conntrack_l4proto nf_conntrack_l4proto_udp6;
extern struct nf_conntrack_l4proto nf_conntrack_l4proto_icmpv6;
-extern int nf_ct_frag6_init(void);
-extern void nf_ct_frag6_cleanup(void);
-extern struct sk_buff *nf_ct_frag6_gather(struct sk_buff *skb, u32 user);
-extern void nf_ct_frag6_output(unsigned int hooknum, struct sk_buff *skb,
- struct net_device *in,
- struct net_device *out,
- int (*okfn)(struct sk_buff *));
-
-struct inet_frags_ctl;
-
#include <linux/sysctl.h>
extern struct ctl_table nf_ct_ipv6_sysctl_table[];
diff --git a/include/net/netfilter/ipv6/nf_defrag_ipv6.h b/include/net/netfilter/ipv6/nf_defrag_ipv6.h
index 94dd54d..fd79c9a 100644
--- a/include/net/netfilter/ipv6/nf_defrag_ipv6.h
+++ b/include/net/netfilter/ipv6/nf_defrag_ipv6.h
@@ -3,4 +3,14 @@
extern void nf_defrag_ipv6_enable(void);
+extern int nf_ct_frag6_init(void);
+extern void nf_ct_frag6_cleanup(void);
+extern struct sk_buff *nf_ct_frag6_gather(struct sk_buff *skb, u32 user);
+extern void nf_ct_frag6_output(unsigned int hooknum, struct sk_buff *skb,
+ struct net_device *in,
+ struct net_device *out,
+ int (*okfn)(struct sk_buff *));
+
+struct inet_frags_ctl;
+
#endif /* _NF_DEFRAG_IPV6_H */
diff --git a/include/net/red.h b/include/net/red.h
index 995108e..3319f16 100644
--- a/include/net/red.h
+++ b/include/net/red.h
@@ -97,7 +97,6 @@ struct red_stats {
u32 forced_mark; /* Forced marks, qavg > max_thresh */
u32 pdrop; /* Drops due to queue limits */
u32 other; /* Drops due to drop() calls */
- u32 backlog;
};
struct red_parms {
diff --git a/include/net/sctp/user.h b/include/net/sctp/user.h
index 2a128c8..e73ebda 100644
--- a/include/net/sctp/user.h
+++ b/include/net/sctp/user.h
@@ -78,6 +78,7 @@ typedef __s32 sctp_assoc_t;
#define SCTP_GET_PEER_ADDR_INFO 15
#define SCTP_DELAYED_ACK_TIME 16
#define SCTP_DELAYED_ACK SCTP_DELAYED_ACK_TIME
+#define SCTP_DELAYED_SACK SCTP_DELAYED_ACK_TIME
#define SCTP_CONTEXT 17
#define SCTP_FRAGMENT_INTERLEAVE 18
#define SCTP_PARTIAL_DELIVERY_POINT 19 /* Set/Get partial delivery point */
diff --git a/include/rdma/ib_verbs.h b/include/rdma/ib_verbs.h
index e04c488..55cd0a0 100644
--- a/include/rdma/ib_verbs.h
+++ b/include/rdma/ib_verbs.h
@@ -47,10 +47,13 @@
#include <linux/list.h>
#include <linux/rwsem.h>
#include <linux/scatterlist.h>
+#include <linux/workqueue.h>
#include <asm/atomic.h>
#include <asm/uaccess.h>
+extern struct workqueue_struct *ib_wq;
+
union ib_gid {
u8 raw[16];
struct {
diff --git a/include/sound/ac97_codec.h b/include/sound/ac97_codec.h
index 4940045..b602f47 100644
--- a/include/sound/ac97_codec.h
+++ b/include/sound/ac97_codec.h
@@ -477,7 +477,7 @@ struct snd_ac97_template {
struct snd_ac97 {
/* -- lowlevel (hardware) driver specific -- */
- struct snd_ac97_build_ops * build_ops;
+ const struct snd_ac97_build_ops *build_ops;
void *private_data;
void (*private_free) (struct snd_ac97 *ac97);
/* --- */
diff --git a/include/target/configfs_macros.h b/include/target/configfs_macros.h
new file mode 100644
index 0000000..7fe7460
--- /dev/null
+++ b/include/target/configfs_macros.h
@@ -0,0 +1,147 @@
+/* -*- mode: c; c-basic-offset: 8; -*-
+ * vim: noexpandtab sw=8 ts=8 sts=0:
+ *
+ * configfs_macros.h - extends macros for configfs
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 021110-1307, USA.
+ *
+ * Based on sysfs:
+ * sysfs is Copyright (C) 2001, 2002, 2003 Patrick Mochel
+ *
+ * Based on kobject.h:
+ * Copyright (c) 2002-2003 Patrick Mochel
+ * Copyright (c) 2002-2003 Open Source Development Labs
+ *
+ * configfs Copyright (C) 2005 Oracle. All rights reserved.
+ *
+ * Added CONFIGFS_EATTR() macros from original configfs.h macros
+ * Copright (C) 2008-2009 Nicholas A. Bellinger <nab@linux-iscsi.org>
+ *
+ * Please read Documentation/filesystems/configfs.txt before using the
+ * configfs interface, ESPECIALLY the parts about reference counts and
+ * item destructors.
+ */
+
+#ifndef _CONFIGFS_MACROS_H_
+#define _CONFIGFS_MACROS_H_
+
+#include <linux/configfs.h>
+
+/*
+ * Users often need to create attribute structures for their configurable
+ * attributes, containing a configfs_attribute member and function pointers
+ * for the show() and store() operations on that attribute. If they don't
+ * need anything else on the extended attribute structure, they can use
+ * this macro to define it. The argument _name isends up as
+ * 'struct _name_attribute, as well as names of to CONFIGFS_ATTR_OPS() below.
+ * The argument _item is the name of the structure containing the
+ * struct config_item or struct config_group structure members
+ */
+#define CONFIGFS_EATTR_STRUCT(_name, _item) \
+struct _name##_attribute { \
+ struct configfs_attribute attr; \
+ ssize_t (*show)(struct _item *, char *); \
+ ssize_t (*store)(struct _item *, const char *, size_t); \
+}
+
+/*
+ * With the extended attribute structure, users can use this macro
+ * (similar to sysfs' __ATTR) to make defining attributes easier.
+ * An example:
+ * #define MYITEM_EATTR(_name, _mode, _show, _store) \
+ * struct myitem_attribute childless_attr_##_name = \
+ * __CONFIGFS_EATTR(_name, _mode, _show, _store)
+ */
+#define __CONFIGFS_EATTR(_name, _mode, _show, _store) \
+{ \
+ .attr = { \
+ .ca_name = __stringify(_name), \
+ .ca_mode = _mode, \
+ .ca_owner = THIS_MODULE, \
+ }, \
+ .show = _show, \
+ .store = _store, \
+}
+/* Here is a readonly version, only requiring a show() operation */
+#define __CONFIGFS_EATTR_RO(_name, _show) \
+{ \
+ .attr = { \
+ .ca_name = __stringify(_name), \
+ .ca_mode = 0444, \
+ .ca_owner = THIS_MODULE, \
+ }, \
+ .show = _show, \
+}
+
+/*
+ * With these extended attributes, the simple show_attribute() and
+ * store_attribute() operations need to call the show() and store() of the
+ * attributes. This is a common pattern, so we provide a macro to define
+ * them. The argument _name is the name of the attribute defined by
+ * CONFIGFS_ATTR_STRUCT(). The argument _item is the name of the structure
+ * containing the struct config_item or struct config_group structure member.
+ * The argument _item_member is the actual name of the struct config_* struct
+ * in your _item structure. Meaning my_structure->some_config_group.
+ * ^^_item^^^^^ ^^_item_member^^^
+ * This macro expects the attributes to be named "struct <name>_attribute".
+ */
+#define CONFIGFS_EATTR_OPS_TO_FUNC(_name, _item, _item_member) \
+static struct _item *to_##_name(struct config_item *ci) \
+{ \
+ return (ci) ? container_of(to_config_group(ci), struct _item, \
+ _item_member) : NULL; \
+}
+
+#define CONFIGFS_EATTR_OPS_SHOW(_name, _item) \
+static ssize_t _name##_attr_show(struct config_item *item, \
+ struct configfs_attribute *attr, \
+ char *page) \
+{ \
+ struct _item *_item = to_##_name(item); \
+ struct _name##_attribute * _name##_attr = \
+ container_of(attr, struct _name##_attribute, attr); \
+ ssize_t ret = 0; \
+ \
+ if (_name##_attr->show) \
+ ret = _name##_attr->show(_item, page); \
+ return ret; \
+}
+
+#define CONFIGFS_EATTR_OPS_STORE(_name, _item) \
+static ssize_t _name##_attr_store(struct config_item *item, \
+ struct configfs_attribute *attr, \
+ const char *page, size_t count) \
+{ \
+ struct _item *_item = to_##_name(item); \
+ struct _name##_attribute * _name##_attr = \
+ container_of(attr, struct _name##_attribute, attr); \
+ ssize_t ret = -EINVAL; \
+ \
+ if (_name##_attr->store) \
+ ret = _name##_attr->store(_item, page, count); \
+ return ret; \
+}
+
+#define CONFIGFS_EATTR_OPS(_name, _item, _item_member) \
+ CONFIGFS_EATTR_OPS_TO_FUNC(_name, _item, _item_member); \
+ CONFIGFS_EATTR_OPS_SHOW(_name, _item); \
+ CONFIGFS_EATTR_OPS_STORE(_name, _item);
+
+#define CONFIGFS_EATTR_OPS_RO(_name, _item, _item_member) \
+ CONFIGFS_EATTR_OPS_TO_FUNC(_name, _item, _item_member); \
+ CONFIGFS_EATTR_OPS_SHOW(_name, _item);
+
+#endif /* _CONFIGFS_MACROS_H_ */
diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h
new file mode 100644
index 0000000..07fdfb6
--- /dev/null
+++ b/include/target/target_core_base.h
@@ -0,0 +1,937 @@
+#ifndef TARGET_CORE_BASE_H
+#define TARGET_CORE_BASE_H
+
+#include <linux/in.h>
+#include <linux/configfs.h>
+#include <linux/dma-mapping.h>
+#include <linux/blkdev.h>
+#include <scsi/scsi_cmnd.h>
+#include <net/sock.h>
+#include <net/tcp.h>
+#include "target_core_mib.h"
+
+#define TARGET_CORE_MOD_VERSION "v4.0.0-rc6"
+#define SHUTDOWN_SIGS (sigmask(SIGKILL)|sigmask(SIGINT)|sigmask(SIGABRT))
+
+/* Used by transport_generic_allocate_iovecs() */
+#define TRANSPORT_IOV_DATA_BUFFER 5
+/* Maximum Number of LUNs per Target Portal Group */
+#define TRANSPORT_MAX_LUNS_PER_TPG 256
+/*
+ * By default we use 32-byte CDBs in TCM Core and subsystem plugin code.
+ *
+ * Note that both include/scsi/scsi_cmnd.h:MAX_COMMAND_SIZE and
+ * include/linux/blkdev.h:BLOCK_MAX_CDB as of v2.6.36-rc4 still use
+ * 16-byte CDBs by default and require an extra allocation for
+ * 32-byte CDBs to becasue of legacy issues.
+ *
+ * Within TCM Core there are no such legacy limitiations, so we go ahead
+ * use 32-byte CDBs by default and use include/scsi/scsi.h:scsi_command_size()
+ * within all TCM Core and subsystem plugin code.
+ */
+#define TCM_MAX_COMMAND_SIZE 32
+/*
+ * From include/scsi/scsi_cmnd.h:SCSI_SENSE_BUFFERSIZE, currently
+ * defined 96, but the real limit is 252 (or 260 including the header)
+ */
+#define TRANSPORT_SENSE_BUFFER SCSI_SENSE_BUFFERSIZE
+/* Used by transport_send_check_condition_and_sense() */
+#define SPC_SENSE_KEY_OFFSET 2
+#define SPC_ASC_KEY_OFFSET 12
+#define SPC_ASCQ_KEY_OFFSET 13
+#define TRANSPORT_IQN_LEN 224
+/* Used by target_core_store_alua_lu_gp() and target_core_alua_lu_gp_show_attr_members() */
+#define LU_GROUP_NAME_BUF 256
+/* Used by core_alua_store_tg_pt_gp_info() and target_core_alua_tg_pt_gp_show_attr_members() */
+#define TG_PT_GROUP_NAME_BUF 256
+/* Used to parse VPD into struct t10_vpd */
+#define VPD_TMP_BUF_SIZE 128
+/* Used by transport_generic_cmd_sequencer() */
+#define READ_BLOCK_LEN 6
+#define READ_CAP_LEN 8
+#define READ_POSITION_LEN 20
+#define INQUIRY_LEN 36
+/* Used by transport_get_inquiry_vpd_serial() */
+#define INQUIRY_VPD_SERIAL_LEN 254
+/* Used by transport_get_inquiry_vpd_device_ident() */
+#define INQUIRY_VPD_DEVICE_IDENTIFIER_LEN 254
+
+/* struct se_hba->hba_flags */
+enum hba_flags_table {
+ HBA_FLAGS_INTERNAL_USE = 0x01,
+ HBA_FLAGS_PSCSI_MODE = 0x02,
+};
+
+/* struct se_lun->lun_status */
+enum transport_lun_status_table {
+ TRANSPORT_LUN_STATUS_FREE = 0,
+ TRANSPORT_LUN_STATUS_ACTIVE = 1,
+};
+
+/* struct se_portal_group->se_tpg_type */
+enum transport_tpg_type_table {
+ TRANSPORT_TPG_TYPE_NORMAL = 0,
+ TRANSPORT_TPG_TYPE_DISCOVERY = 1,
+};
+
+/* Used for generate timer flags */
+enum timer_flags_table {
+ TF_RUNNING = 0x01,
+ TF_STOP = 0x02,
+};
+
+/* Special transport agnostic struct se_cmd->t_states */
+enum transport_state_table {
+ TRANSPORT_NO_STATE = 0,
+ TRANSPORT_NEW_CMD = 1,
+ TRANSPORT_DEFERRED_CMD = 2,
+ TRANSPORT_WRITE_PENDING = 3,
+ TRANSPORT_PROCESS_WRITE = 4,
+ TRANSPORT_PROCESSING = 5,
+ TRANSPORT_COMPLETE_OK = 6,
+ TRANSPORT_COMPLETE_FAILURE = 7,
+ TRANSPORT_COMPLETE_TIMEOUT = 8,
+ TRANSPORT_PROCESS_TMR = 9,
+ TRANSPORT_TMR_COMPLETE = 10,
+ TRANSPORT_ISTATE_PROCESSING = 11,
+ TRANSPORT_ISTATE_PROCESSED = 12,
+ TRANSPORT_KILL = 13,
+ TRANSPORT_REMOVE = 14,
+ TRANSPORT_FREE = 15,
+ TRANSPORT_NEW_CMD_MAP = 16,
+};
+
+/* Used for struct se_cmd->se_cmd_flags */
+enum se_cmd_flags_table {
+ SCF_SUPPORTED_SAM_OPCODE = 0x00000001,
+ SCF_TRANSPORT_TASK_SENSE = 0x00000002,
+ SCF_EMULATED_TASK_SENSE = 0x00000004,
+ SCF_SCSI_DATA_SG_IO_CDB = 0x00000008,
+ SCF_SCSI_CONTROL_SG_IO_CDB = 0x00000010,
+ SCF_SCSI_CONTROL_NONSG_IO_CDB = 0x00000020,
+ SCF_SCSI_NON_DATA_CDB = 0x00000040,
+ SCF_SCSI_CDB_EXCEPTION = 0x00000080,
+ SCF_SCSI_RESERVATION_CONFLICT = 0x00000100,
+ SCF_CMD_PASSTHROUGH_NOALLOC = 0x00000200,
+ SCF_SE_CMD_FAILED = 0x00000400,
+ SCF_SE_LUN_CMD = 0x00000800,
+ SCF_SE_ALLOW_EOO = 0x00001000,
+ SCF_SE_DISABLE_ONLINE_CHECK = 0x00002000,
+ SCF_SENT_CHECK_CONDITION = 0x00004000,
+ SCF_OVERFLOW_BIT = 0x00008000,
+ SCF_UNDERFLOW_BIT = 0x00010000,
+ SCF_SENT_DELAYED_TAS = 0x00020000,
+ SCF_ALUA_NON_OPTIMIZED = 0x00040000,
+ SCF_DELAYED_CMD_FROM_SAM_ATTR = 0x00080000,
+ SCF_PASSTHROUGH_SG_TO_MEM = 0x00100000,
+ SCF_PASSTHROUGH_CONTIG_TO_SG = 0x00200000,
+ SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC = 0x00400000,
+ SCF_EMULATE_SYNC_CACHE = 0x00800000,
+ SCF_EMULATE_CDB_ASYNC = 0x01000000,
+ SCF_EMULATE_SYNC_UNMAP = 0x02000000
+};
+
+/* struct se_dev_entry->lun_flags and struct se_lun->lun_access */
+enum transport_lunflags_table {
+ TRANSPORT_LUNFLAGS_NO_ACCESS = 0x00,
+ TRANSPORT_LUNFLAGS_INITIATOR_ACCESS = 0x01,
+ TRANSPORT_LUNFLAGS_READ_ONLY = 0x02,
+ TRANSPORT_LUNFLAGS_READ_WRITE = 0x04,
+};
+
+/* struct se_device->dev_status */
+enum transport_device_status_table {
+ TRANSPORT_DEVICE_ACTIVATED = 0x01,
+ TRANSPORT_DEVICE_DEACTIVATED = 0x02,
+ TRANSPORT_DEVICE_QUEUE_FULL = 0x04,
+ TRANSPORT_DEVICE_SHUTDOWN = 0x08,
+ TRANSPORT_DEVICE_OFFLINE_ACTIVATED = 0x10,
+ TRANSPORT_DEVICE_OFFLINE_DEACTIVATED = 0x20,
+};
+
+/*
+ * Used by transport_send_check_condition_and_sense() and se_cmd->scsi_sense_reason
+ * to signal which ASC/ASCQ sense payload should be built.
+ */
+enum tcm_sense_reason_table {
+ TCM_NON_EXISTENT_LUN = 0x01,
+ TCM_UNSUPPORTED_SCSI_OPCODE = 0x02,
+ TCM_INCORRECT_AMOUNT_OF_DATA = 0x03,
+ TCM_UNEXPECTED_UNSOLICITED_DATA = 0x04,
+ TCM_SERVICE_CRC_ERROR = 0x05,
+ TCM_SNACK_REJECTED = 0x06,
+ TCM_SECTOR_COUNT_TOO_MANY = 0x07,
+ TCM_INVALID_CDB_FIELD = 0x08,
+ TCM_INVALID_PARAMETER_LIST = 0x09,
+ TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE = 0x0a,
+ TCM_UNKNOWN_MODE_PAGE = 0x0b,
+ TCM_WRITE_PROTECTED = 0x0c,
+ TCM_CHECK_CONDITION_ABORT_CMD = 0x0d,
+ TCM_CHECK_CONDITION_UNIT_ATTENTION = 0x0e,
+ TCM_CHECK_CONDITION_NOT_READY = 0x0f,
+};
+
+struct se_obj {
+ atomic_t obj_access_count;
+} ____cacheline_aligned;
+
+/*
+ * Used by TCM Core internally to signal if ALUA emulation is enabled or
+ * disabled, or running in with TCM/pSCSI passthrough mode
+ */
+typedef enum {
+ SPC_ALUA_PASSTHROUGH,
+ SPC2_ALUA_DISABLED,
+ SPC3_ALUA_EMULATED
+} t10_alua_index_t;
+
+/*
+ * Used by TCM Core internally to signal if SAM Task Attribute emulation
+ * is enabled or disabled, or running in with TCM/pSCSI passthrough mode
+ */
+typedef enum {
+ SAM_TASK_ATTR_PASSTHROUGH,
+ SAM_TASK_ATTR_UNTAGGED,
+ SAM_TASK_ATTR_EMULATED
+} t10_task_attr_index_t;
+
+struct se_cmd;
+
+struct t10_alua {
+ t10_alua_index_t alua_type;
+ /* ALUA Target Port Group ID */
+ u16 alua_tg_pt_gps_counter;
+ u32 alua_tg_pt_gps_count;
+ spinlock_t tg_pt_gps_lock;
+ struct se_subsystem_dev *t10_sub_dev;
+ /* Used for default ALUA Target Port Group */
+ struct t10_alua_tg_pt_gp *default_tg_pt_gp;
+ /* Used for default ALUA Target Port Group ConfigFS group */
+ struct config_group alua_tg_pt_gps_group;
+ int (*alua_state_check)(struct se_cmd *, unsigned char *, u8 *);
+ struct list_head tg_pt_gps_list;
+} ____cacheline_aligned;
+
+struct t10_alua_lu_gp {
+ u16 lu_gp_id;
+ int lu_gp_valid_id;
+ u32 lu_gp_members;
+ atomic_t lu_gp_shutdown;
+ atomic_t lu_gp_ref_cnt;
+ spinlock_t lu_gp_lock;
+ struct config_group lu_gp_group;
+ struct list_head lu_gp_list;
+ struct list_head lu_gp_mem_list;
+} ____cacheline_aligned;
+
+struct t10_alua_lu_gp_member {
+ int lu_gp_assoc:1;
+ atomic_t lu_gp_mem_ref_cnt;
+ spinlock_t lu_gp_mem_lock;
+ struct t10_alua_lu_gp *lu_gp;
+ struct se_device *lu_gp_mem_dev;
+ struct list_head lu_gp_mem_list;
+} ____cacheline_aligned;
+
+struct t10_alua_tg_pt_gp {
+ u16 tg_pt_gp_id;
+ int tg_pt_gp_valid_id;
+ int tg_pt_gp_alua_access_status;
+ int tg_pt_gp_alua_access_type;
+ int tg_pt_gp_nonop_delay_msecs;
+ int tg_pt_gp_trans_delay_msecs;
+ int tg_pt_gp_pref;
+ int tg_pt_gp_write_metadata;
+ /* Used by struct t10_alua_tg_pt_gp->tg_pt_gp_md_buf_len */
+#define ALUA_MD_BUF_LEN 1024
+ u32 tg_pt_gp_md_buf_len;
+ u32 tg_pt_gp_members;
+ atomic_t tg_pt_gp_alua_access_state;
+ atomic_t tg_pt_gp_ref_cnt;
+ spinlock_t tg_pt_gp_lock;
+ struct mutex tg_pt_gp_md_mutex;
+ struct se_subsystem_dev *tg_pt_gp_su_dev;
+ struct config_group tg_pt_gp_group;
+ struct list_head tg_pt_gp_list;
+ struct list_head tg_pt_gp_mem_list;
+} ____cacheline_aligned;
+
+struct t10_alua_tg_pt_gp_member {
+ int tg_pt_gp_assoc:1;
+ atomic_t tg_pt_gp_mem_ref_cnt;
+ spinlock_t tg_pt_gp_mem_lock;
+ struct t10_alua_tg_pt_gp *tg_pt_gp;
+ struct se_port *tg_pt;
+ struct list_head tg_pt_gp_mem_list;
+} ____cacheline_aligned;
+
+struct t10_vpd {
+ unsigned char device_identifier[INQUIRY_VPD_DEVICE_IDENTIFIER_LEN];
+ int protocol_identifier_set;
+ u32 protocol_identifier;
+ u32 device_identifier_code_set;
+ u32 association;
+ u32 device_identifier_type;
+ struct list_head vpd_list;
+} ____cacheline_aligned;
+
+struct t10_wwn {
+ unsigned char vendor[8];
+ unsigned char model[16];
+ unsigned char revision[4];
+ unsigned char unit_serial[INQUIRY_VPD_SERIAL_LEN];
+ spinlock_t t10_vpd_lock;
+ struct se_subsystem_dev *t10_sub_dev;
+ struct config_group t10_wwn_group;
+ struct list_head t10_vpd_list;
+} ____cacheline_aligned;
+
+
+/*
+ * Used by TCM Core internally to signal if >= SPC-3 peristent reservations
+ * emulation is enabled or disabled, or running in with TCM/pSCSI passthrough
+ * mode
+ */
+typedef enum {
+ SPC_PASSTHROUGH,
+ SPC2_RESERVATIONS,
+ SPC3_PERSISTENT_RESERVATIONS
+} t10_reservations_index_t;
+
+struct t10_pr_registration {
+ /* Used for fabrics that contain WWN+ISID */
+#define PR_REG_ISID_LEN 16
+ /* PR_REG_ISID_LEN + ',i,0x' */
+#define PR_REG_ISID_ID_LEN (PR_REG_ISID_LEN + 5)
+ char pr_reg_isid[PR_REG_ISID_LEN];
+ /* Used during APTPL metadata reading */
+#define PR_APTPL_MAX_IPORT_LEN 256
+ unsigned char pr_iport[PR_APTPL_MAX_IPORT_LEN];
+ /* Used during APTPL metadata reading */
+#define PR_APTPL_MAX_TPORT_LEN 256
+ unsigned char pr_tport[PR_APTPL_MAX_TPORT_LEN];
+ /* For writing out live meta data */
+ unsigned char *pr_aptpl_buf;
+ u16 pr_aptpl_rpti;
+ u16 pr_reg_tpgt;
+ /* Reservation effects all target ports */
+ int pr_reg_all_tg_pt;
+ /* Activate Persistence across Target Power Loss */
+ int pr_reg_aptpl;
+ int pr_res_holder;
+ int pr_res_type;
+ int pr_res_scope;
+ /* Used for fabric initiator WWPNs using a ISID */
+ int isid_present_at_reg:1;
+ u32 pr_res_mapped_lun;
+ u32 pr_aptpl_target_lun;
+ u32 pr_res_generation;
+ u64 pr_reg_bin_isid;
+ u64 pr_res_key;
+ atomic_t pr_res_holders;
+ struct se_node_acl *pr_reg_nacl;
+ struct se_dev_entry *pr_reg_deve;
+ struct se_lun *pr_reg_tg_pt_lun;
+ struct list_head pr_reg_list;
+ struct list_head pr_reg_abort_list;
+ struct list_head pr_reg_aptpl_list;
+ struct list_head pr_reg_atp_list;
+ struct list_head pr_reg_atp_mem_list;
+} ____cacheline_aligned;
+
+/*
+ * This set of function pointer ops is set based upon SPC3_PERSISTENT_RESERVATIONS,
+ * SPC2_RESERVATIONS or SPC_PASSTHROUGH in drivers/target/target_core_pr.c:
+ * core_setup_reservations()
+ */
+struct t10_reservation_ops {
+ int (*t10_reservation_check)(struct se_cmd *, u32 *);
+ int (*t10_seq_non_holder)(struct se_cmd *, unsigned char *, u32);
+ int (*t10_pr_register)(struct se_cmd *);
+ int (*t10_pr_clear)(struct se_cmd *);
+};
+
+struct t10_reservation_template {
+ /* Reservation effects all target ports */
+ int pr_all_tg_pt;
+ /* Activate Persistence across Target Power Loss enabled
+ * for SCSI device */
+ int pr_aptpl_active;
+ /* Used by struct t10_reservation_template->pr_aptpl_buf_len */
+#define PR_APTPL_BUF_LEN 8192
+ u32 pr_aptpl_buf_len;
+ u32 pr_generation;
+ t10_reservations_index_t res_type;
+ spinlock_t registration_lock;
+ spinlock_t aptpl_reg_lock;
+ /*
+ * This will always be set by one individual I_T Nexus.
+ * However with all_tg_pt=1, other I_T Nexus from the
+ * same initiator can access PR reg/res info on a different
+ * target port.
+ *
+ * There is also the 'All Registrants' case, where there is
+ * a single *pr_res_holder of the reservation, but all
+ * registrations are considered reservation holders.
+ */
+ struct se_node_acl *pr_res_holder;
+ struct list_head registration_list;
+ struct list_head aptpl_reg_list;
+ struct t10_reservation_ops pr_ops;
+} ____cacheline_aligned;
+
+struct se_queue_req {
+ int state;
+ void *cmd;
+ struct list_head qr_list;
+} ____cacheline_aligned;
+
+struct se_queue_obj {
+ atomic_t queue_cnt;
+ spinlock_t cmd_queue_lock;
+ struct list_head qobj_list;
+ wait_queue_head_t thread_wq;
+} ____cacheline_aligned;
+
+/*
+ * Used one per struct se_cmd to hold all extra struct se_task
+ * metadata. This structure is setup and allocated in
+ * drivers/target/target_core_transport.c:__transport_alloc_se_cmd()
+ */
+struct se_transport_task {
+ unsigned char *t_task_cdb;
+ unsigned char __t_task_cdb[TCM_MAX_COMMAND_SIZE];
+ unsigned long long t_task_lba;
+ int t_tasks_failed;
+ int t_tasks_fua;
+ int t_tasks_bidi:1;
+ u32 t_task_cdbs;
+ u32 t_tasks_check;
+ u32 t_tasks_no;
+ u32 t_tasks_sectors;
+ u32 t_tasks_se_num;
+ u32 t_tasks_se_bidi_num;
+ u32 t_tasks_sg_chained_no;
+ atomic_t t_fe_count;
+ atomic_t t_se_count;
+ atomic_t t_task_cdbs_left;
+ atomic_t t_task_cdbs_ex_left;
+ atomic_t t_task_cdbs_timeout_left;
+ atomic_t t_task_cdbs_sent;
+ atomic_t t_transport_aborted;
+ atomic_t t_transport_active;
+ atomic_t t_transport_complete;
+ atomic_t t_transport_queue_active;
+ atomic_t t_transport_sent;
+ atomic_t t_transport_stop;
+ atomic_t t_transport_timeout;
+ atomic_t transport_dev_active;
+ atomic_t transport_lun_active;
+ atomic_t transport_lun_fe_stop;
+ atomic_t transport_lun_stop;
+ spinlock_t t_state_lock;
+ struct completion t_transport_stop_comp;
+ struct completion transport_lun_fe_stop_comp;
+ struct completion transport_lun_stop_comp;
+ struct scatterlist *t_tasks_sg_chained;
+ struct scatterlist t_tasks_sg_bounce;
+ void *t_task_buf;
+ /*
+ * Used for pre-registered fabric SGL passthrough WRITE and READ
+ * with the special SCF_PASSTHROUGH_CONTIG_TO_SG case for TCM_Loop
+ * and other HW target mode fabric modules.
+ */
+ struct scatterlist *t_task_pt_sgl;
+ struct list_head *t_mem_list;
+ /* Used for BIDI READ */
+ struct list_head *t_mem_bidi_list;
+ struct list_head t_task_list;
+} ____cacheline_aligned;
+
+struct se_task {
+ unsigned char task_sense;
+ struct scatterlist *task_sg;
+ struct scatterlist *task_sg_bidi;
+ u8 task_scsi_status;
+ u8 task_flags;
+ int task_error_status;
+ int task_state_flags;
+ int task_padded_sg:1;
+ unsigned long long task_lba;
+ u32 task_no;
+ u32 task_sectors;
+ u32 task_size;
+ u32 task_sg_num;
+ u32 task_sg_offset;
+ enum dma_data_direction task_data_direction;
+ struct se_cmd *task_se_cmd;
+ struct se_device *se_dev;
+ struct completion task_stop_comp;
+ atomic_t task_active;
+ atomic_t task_execute_queue;
+ atomic_t task_timeout;
+ atomic_t task_sent;
+ atomic_t task_stop;
+ atomic_t task_state_active;
+ struct timer_list task_timer;
+ struct se_device *se_obj_ptr;
+ struct list_head t_list;
+ struct list_head t_execute_list;
+ struct list_head t_state_list;
+} ____cacheline_aligned;
+
+#define TASK_CMD(task) ((struct se_cmd *)task->task_se_cmd)
+#define TASK_DEV(task) ((struct se_device *)task->se_dev)
+
+struct se_cmd {
+ /* SAM response code being sent to initiator */
+ u8 scsi_status;
+ u8 scsi_asc;
+ u8 scsi_ascq;
+ u8 scsi_sense_reason;
+ u16 scsi_sense_length;
+ /* Delay for ALUA Active/NonOptimized state access in milliseconds */
+ int alua_nonop_delay;
+ /* See include/linux/dma-mapping.h */
+ enum dma_data_direction data_direction;
+ /* For SAM Task Attribute */
+ int sam_task_attr;
+ /* Transport protocol dependent state, see transport_state_table */
+ enum transport_state_table t_state;
+ /* Transport protocol dependent state for out of order CmdSNs */
+ int deferred_t_state;
+ /* Transport specific error status */
+ int transport_error_status;
+ /* See se_cmd_flags_table */
+ u32 se_cmd_flags;
+ u32 se_ordered_id;
+ /* Total size in bytes associated with command */
+ u32 data_length;
+ /* SCSI Presented Data Transfer Length */
+ u32 cmd_spdtl;
+ u32 residual_count;
+ u32 orig_fe_lun;
+ /* Persistent Reservation key */
+ u64 pr_res_key;
+ atomic_t transport_sent;
+ /* Used for sense data */
+ void *sense_buffer;
+ struct list_head se_delayed_list;
+ struct list_head se_ordered_list;
+ struct list_head se_lun_list;
+ struct se_device *se_dev;
+ struct se_dev_entry *se_deve;
+ struct se_device *se_obj_ptr;
+ struct se_device *se_orig_obj_ptr;
+ struct se_lun *se_lun;
+ /* Only used for internal passthrough and legacy TCM fabric modules */
+ struct se_session *se_sess;
+ struct se_tmr_req *se_tmr_req;
+ /* t_task is setup to t_task_backstore in transport_init_se_cmd() */
+ struct se_transport_task *t_task;
+ struct se_transport_task t_task_backstore;
+ struct target_core_fabric_ops *se_tfo;
+ int (*transport_emulate_cdb)(struct se_cmd *);
+ void (*transport_split_cdb)(unsigned long long, u32 *, unsigned char *);
+ void (*transport_wait_for_tasks)(struct se_cmd *, int, int);
+ void (*transport_complete_callback)(struct se_cmd *);
+} ____cacheline_aligned;
+
+#define T_TASK(cmd) ((struct se_transport_task *)(cmd->t_task))
+#define CMD_TFO(cmd) ((struct target_core_fabric_ops *)cmd->se_tfo)
+
+struct se_tmr_req {
+ /* Task Management function to be preformed */
+ u8 function;
+ /* Task Management response to send */
+ u8 response;
+ int call_transport;
+ /* Reference to ITT that Task Mgmt should be preformed */
+ u32 ref_task_tag;
+ /* 64-bit encoded SAM LUN from $FABRIC_MOD TMR header */
+ u64 ref_task_lun;
+ void *fabric_tmr_ptr;
+ struct se_cmd *task_cmd;
+ struct se_cmd *ref_cmd;
+ struct se_device *tmr_dev;
+ struct se_lun *tmr_lun;
+ struct list_head tmr_list;
+} ____cacheline_aligned;
+
+struct se_ua {
+ u8 ua_asc;
+ u8 ua_ascq;
+ struct se_node_acl *ua_nacl;
+ struct list_head ua_dev_list;
+ struct list_head ua_nacl_list;
+} ____cacheline_aligned;
+
+struct se_node_acl {
+ char initiatorname[TRANSPORT_IQN_LEN];
+ /* Used to signal demo mode created ACL, disabled by default */
+ int dynamic_node_acl:1;
+ u32 queue_depth;
+ u32 acl_index;
+ u64 num_cmds;
+ u64 read_bytes;
+ u64 write_bytes;
+ spinlock_t stats_lock;
+ /* Used for PR SPEC_I_PT=1 and REGISTER_AND_MOVE */
+ atomic_t acl_pr_ref_count;
+ /* Used for MIB access */
+ atomic_t mib_ref_count;
+ struct se_dev_entry *device_list;
+ struct se_session *nacl_sess;
+ struct se_portal_group *se_tpg;
+ spinlock_t device_list_lock;
+ spinlock_t nacl_sess_lock;
+ struct config_group acl_group;
+ struct config_group acl_attrib_group;
+ struct config_group acl_auth_group;
+ struct config_group acl_param_group;
+ struct config_group *acl_default_groups[4];
+ struct list_head acl_list;
+ struct list_head acl_sess_list;
+} ____cacheline_aligned;
+
+struct se_session {
+ /* Used for MIB access */
+ atomic_t mib_ref_count;
+ u64 sess_bin_isid;
+ struct se_node_acl *se_node_acl;
+ struct se_portal_group *se_tpg;
+ void *fabric_sess_ptr;
+ struct list_head sess_list;
+ struct list_head sess_acl_list;
+} ____cacheline_aligned;
+
+#define SE_SESS(cmd) ((struct se_session *)(cmd)->se_sess)
+#define SE_NODE_ACL(sess) ((struct se_node_acl *)(sess)->se_node_acl)
+
+struct se_device;
+struct se_transform_info;
+struct scatterlist;
+
+struct se_lun_acl {
+ char initiatorname[TRANSPORT_IQN_LEN];
+ u32 mapped_lun;
+ struct se_node_acl *se_lun_nacl;
+ struct se_lun *se_lun;
+ struct list_head lacl_list;
+ struct config_group se_lun_group;
+} ____cacheline_aligned;
+
+struct se_dev_entry {
+ int def_pr_registered:1;
+ /* See transport_lunflags_table */
+ u32 lun_flags;
+ u32 deve_cmds;
+ u32 mapped_lun;
+ u32 average_bytes;
+ u32 last_byte_count;
+ u32 total_cmds;
+ u32 total_bytes;
+ u64 pr_res_key;
+ u64 creation_time;
+ u32 attach_count;
+ u64 read_bytes;
+ u64 write_bytes;
+ atomic_t ua_count;
+ /* Used for PR SPEC_I_PT=1 and REGISTER_AND_MOVE */
+ atomic_t pr_ref_count;
+ struct se_lun_acl *se_lun_acl;
+ spinlock_t ua_lock;
+ struct se_lun *se_lun;
+ struct list_head alua_port_list;
+ struct list_head ua_list;
+} ____cacheline_aligned;
+
+struct se_dev_limits {
+ /* Max supported HW queue depth */
+ u32 hw_queue_depth;
+ /* Max supported virtual queue depth */
+ u32 queue_depth;
+ /* From include/linux/blkdev.h for the other HW/SW limits. */
+ struct queue_limits limits;
+} ____cacheline_aligned;
+
+struct se_dev_attrib {
+ int emulate_dpo;
+ int emulate_fua_write;
+ int emulate_fua_read;
+ int emulate_write_cache;
+ int emulate_ua_intlck_ctrl;
+ int emulate_tas;
+ int emulate_tpu;
+ int emulate_tpws;
+ int emulate_reservations;
+ int emulate_alua;
+ int enforce_pr_isids;
+ u32 hw_block_size;
+ u32 block_size;
+ u32 hw_max_sectors;
+ u32 max_sectors;
+ u32 optimal_sectors;
+ u32 hw_queue_depth;
+ u32 queue_depth;
+ u32 task_timeout;
+ u32 max_unmap_lba_count;
+ u32 max_unmap_block_desc_count;
+ u32 unmap_granularity;
+ u32 unmap_granularity_alignment;
+ struct se_subsystem_dev *da_sub_dev;
+ struct config_group da_group;
+} ____cacheline_aligned;
+
+struct se_subsystem_dev {
+/* Used for struct se_subsystem_dev-->se_dev_alias, must be less than PAGE_SIZE */
+#define SE_DEV_ALIAS_LEN 512
+ unsigned char se_dev_alias[SE_DEV_ALIAS_LEN];
+/* Used for struct se_subsystem_dev->se_dev_udev_path[], must be less than PAGE_SIZE */
+#define SE_UDEV_PATH_LEN 512
+ unsigned char se_dev_udev_path[SE_UDEV_PATH_LEN];
+ u32 su_dev_flags;
+ struct se_hba *se_dev_hba;
+ struct se_device *se_dev_ptr;
+ struct se_dev_attrib se_dev_attrib;
+ /* T10 Asymmetric Logical Unit Assignment for Target Ports */
+ struct t10_alua t10_alua;
+ /* T10 Inquiry and VPD WWN Information */
+ struct t10_wwn t10_wwn;
+ /* T10 SPC-2 + SPC-3 Reservations */
+ struct t10_reservation_template t10_reservation;
+ spinlock_t se_dev_lock;
+ void *se_dev_su_ptr;
+ struct list_head g_se_dev_list;
+ struct config_group se_dev_group;
+ /* For T10 Reservations */
+ struct config_group se_dev_pr_group;
+} ____cacheline_aligned;
+
+#define T10_ALUA(su_dev) (&(su_dev)->t10_alua)
+#define T10_RES(su_dev) (&(su_dev)->t10_reservation)
+#define T10_PR_OPS(su_dev) (&(su_dev)->t10_reservation.pr_ops)
+
+struct se_device {
+ /* Set to 1 if thread is NOT sleeping on thread_sem */
+ u8 thread_active;
+ u8 dev_status_timer_flags;
+ /* RELATIVE TARGET PORT IDENTIFER Counter */
+ u16 dev_rpti_counter;
+ /* Used for SAM Task Attribute ordering */
+ u32 dev_cur_ordered_id;
+ u32 dev_flags;
+ u32 dev_port_count;
+ /* See transport_device_status_table */
+ u32 dev_status;
+ u32 dev_tcq_window_closed;
+ /* Physical device queue depth */
+ u32 queue_depth;
+ /* Used for SPC-2 reservations enforce of ISIDs */
+ u64 dev_res_bin_isid;
+ t10_task_attr_index_t dev_task_attr_type;
+ /* Pointer to transport specific device structure */
+ void *dev_ptr;
+ u32 dev_index;
+ u64 creation_time;
+ u32 num_resets;
+ u64 num_cmds;
+ u64 read_bytes;
+ u64 write_bytes;
+ spinlock_t stats_lock;
+ /* Active commands on this virtual SE device */
+ atomic_t active_cmds;
+ atomic_t simple_cmds;
+ atomic_t depth_left;
+ atomic_t dev_ordered_id;
+ atomic_t dev_tur_active;
+ atomic_t execute_tasks;
+ atomic_t dev_status_thr_count;
+ atomic_t dev_hoq_count;
+ atomic_t dev_ordered_sync;
+ struct se_obj dev_obj;
+ struct se_obj dev_access_obj;
+ struct se_obj dev_export_obj;
+ struct se_queue_obj *dev_queue_obj;
+ struct se_queue_obj *dev_status_queue_obj;
+ spinlock_t delayed_cmd_lock;
+ spinlock_t ordered_cmd_lock;
+ spinlock_t execute_task_lock;
+ spinlock_t state_task_lock;
+ spinlock_t dev_alua_lock;
+ spinlock_t dev_reservation_lock;
+ spinlock_t dev_state_lock;
+ spinlock_t dev_status_lock;
+ spinlock_t dev_status_thr_lock;
+ spinlock_t se_port_lock;
+ spinlock_t se_tmr_lock;
+ /* Used for legacy SPC-2 reservationsa */
+ struct se_node_acl *dev_reserved_node_acl;
+ /* Used for ALUA Logical Unit Group membership */
+ struct t10_alua_lu_gp_member *dev_alua_lu_gp_mem;
+ /* Used for SPC-3 Persistent Reservations */
+ struct t10_pr_registration *dev_pr_res_holder;
+ struct list_head dev_sep_list;
+ struct list_head dev_tmr_list;
+ struct timer_list dev_status_timer;
+ /* Pointer to descriptor for processing thread */
+ struct task_struct *process_thread;
+ pid_t process_thread_pid;
+ struct task_struct *dev_mgmt_thread;
+ struct list_head delayed_cmd_list;
+ struct list_head ordered_cmd_list;
+ struct list_head execute_task_list;
+ struct list_head state_task_list;
+ /* Pointer to associated SE HBA */
+ struct se_hba *se_hba;
+ struct se_subsystem_dev *se_sub_dev;
+ /* Pointer to template of function pointers for transport */
+ struct se_subsystem_api *transport;
+ /* Linked list for struct se_hba struct se_device list */
+ struct list_head dev_list;
+ /* Linked list for struct se_global->g_se_dev_list */
+ struct list_head g_se_dev_list;
+} ____cacheline_aligned;
+
+#define SE_DEV(cmd) ((struct se_device *)(cmd)->se_lun->lun_se_dev)
+#define SU_DEV(dev) ((struct se_subsystem_dev *)(dev)->se_sub_dev)
+#define DEV_ATTRIB(dev) (&(dev)->se_sub_dev->se_dev_attrib)
+#define DEV_T10_WWN(dev) (&(dev)->se_sub_dev->t10_wwn)
+
+struct se_hba {
+ u16 hba_tpgt;
+ u32 hba_id;
+ /* See hba_flags_table */
+ u32 hba_flags;
+ /* Virtual iSCSI devices attached. */
+ u32 dev_count;
+ u32 hba_index;
+ atomic_t dev_mib_access_count;
+ atomic_t load_balance_queue;
+ atomic_t left_queue_depth;
+ /* Maximum queue depth the HBA can handle. */
+ atomic_t max_queue_depth;
+ /* Pointer to transport specific host structure. */
+ void *hba_ptr;
+ /* Linked list for struct se_device */
+ struct list_head hba_dev_list;
+ struct list_head hba_list;
+ spinlock_t device_lock;
+ spinlock_t hba_queue_lock;
+ struct config_group hba_group;
+ struct mutex hba_access_mutex;
+ struct se_subsystem_api *transport;
+} ____cacheline_aligned;
+
+#define SE_HBA(d) ((struct se_hba *)(d)->se_hba)
+
+struct se_lun {
+ /* See transport_lun_status_table */
+ enum transport_lun_status_table lun_status;
+ u32 lun_access;
+ u32 lun_flags;
+ u32 unpacked_lun;
+ atomic_t lun_acl_count;
+ spinlock_t lun_acl_lock;
+ spinlock_t lun_cmd_lock;
+ spinlock_t lun_sep_lock;
+ struct completion lun_shutdown_comp;
+ struct list_head lun_cmd_list;
+ struct list_head lun_acl_list;
+ struct se_device *lun_se_dev;
+ struct config_group lun_group;
+ struct se_port *lun_sep;
+} ____cacheline_aligned;
+
+#define SE_LUN(c) ((struct se_lun *)(c)->se_lun)
+
+struct se_port {
+ /* RELATIVE TARGET PORT IDENTIFER */
+ u16 sep_rtpi;
+ int sep_tg_pt_secondary_stat;
+ int sep_tg_pt_secondary_write_md;
+ u32 sep_index;
+ struct scsi_port_stats sep_stats;
+ /* Used for ALUA Target Port Groups membership */
+ atomic_t sep_tg_pt_gp_active;
+ atomic_t sep_tg_pt_secondary_offline;
+ /* Used for PR ALL_TG_PT=1 */
+ atomic_t sep_tg_pt_ref_cnt;
+ spinlock_t sep_alua_lock;
+ struct mutex sep_tg_pt_md_mutex;
+ struct t10_alua_tg_pt_gp_member *sep_alua_tg_pt_gp_mem;
+ struct se_lun *sep_lun;
+ struct se_portal_group *sep_tpg;
+ struct list_head sep_alua_list;
+ struct list_head sep_list;
+} ____cacheline_aligned;
+
+struct se_tpg_np {
+ struct config_group tpg_np_group;
+} ____cacheline_aligned;
+
+struct se_portal_group {
+ /* Type of target portal group, see transport_tpg_type_table */
+ enum transport_tpg_type_table se_tpg_type;
+ /* Number of ACLed Initiator Nodes for this TPG */
+ u32 num_node_acls;
+ /* Used for PR SPEC_I_PT=1 and REGISTER_AND_MOVE */
+ atomic_t tpg_pr_ref_count;
+ /* Spinlock for adding/removing ACLed Nodes */
+ spinlock_t acl_node_lock;
+ /* Spinlock for adding/removing sessions */
+ spinlock_t session_lock;
+ spinlock_t tpg_lun_lock;
+ /* Pointer to $FABRIC_MOD portal group */
+ void *se_tpg_fabric_ptr;
+ struct list_head se_tpg_list;
+ /* linked list for initiator ACL list */
+ struct list_head acl_node_list;
+ struct se_lun *tpg_lun_list;
+ struct se_lun tpg_virt_lun0;
+ /* List of TCM sessions assoicated wth this TPG */
+ struct list_head tpg_sess_list;
+ /* Pointer to $FABRIC_MOD dependent code */
+ struct target_core_fabric_ops *se_tpg_tfo;
+ struct se_wwn *se_tpg_wwn;
+ struct config_group tpg_group;
+ struct config_group *tpg_default_groups[6];
+ struct config_group tpg_lun_group;
+ struct config_group tpg_np_group;
+ struct config_group tpg_acl_group;
+ struct config_group tpg_attrib_group;
+ struct config_group tpg_param_group;
+} ____cacheline_aligned;
+
+#define TPG_TFO(se_tpg) ((struct target_core_fabric_ops *)(se_tpg)->se_tpg_tfo)
+
+struct se_wwn {
+ struct target_fabric_configfs *wwn_tf;
+ struct config_group wwn_group;
+} ____cacheline_aligned;
+
+struct se_global {
+ u16 alua_lu_gps_counter;
+ int g_sub_api_initialized;
+ u32 in_shutdown;
+ u32 alua_lu_gps_count;
+ u32 g_hba_id_counter;
+ struct config_group target_core_hbagroup;
+ struct config_group alua_group;
+ struct config_group alua_lu_gps_group;
+ struct list_head g_lu_gps_list;
+ struct list_head g_se_tpg_list;
+ struct list_head g_hba_list;
+ struct list_head g_se_dev_list;
+ struct se_hba *g_lun0_hba;
+ struct se_subsystem_dev *g_lun0_su_dev;
+ struct se_device *g_lun0_dev;
+ struct t10_alua_lu_gp *default_lu_gp;
+ spinlock_t g_device_lock;
+ spinlock_t hba_lock;
+ spinlock_t se_tpg_lock;
+ spinlock_t lu_gps_lock;
+ spinlock_t plugin_class_lock;
+} ____cacheline_aligned;
+
+#endif /* TARGET_CORE_BASE_H */
diff --git a/include/target/target_core_configfs.h b/include/target/target_core_configfs.h
new file mode 100644
index 0000000..40e6e74
--- /dev/null
+++ b/include/target/target_core_configfs.h
@@ -0,0 +1,52 @@
+#define TARGET_CORE_CONFIGFS_VERSION TARGET_CORE_MOD_VERSION
+
+#define TARGET_CORE_CONFIG_ROOT "/sys/kernel/config"
+
+#define TARGET_CORE_NAME_MAX_LEN 64
+#define TARGET_FABRIC_NAME_SIZE 32
+
+extern struct target_fabric_configfs *target_fabric_configfs_init(
+ struct module *, const char *);
+extern void target_fabric_configfs_free(struct target_fabric_configfs *);
+extern int target_fabric_configfs_register(struct target_fabric_configfs *);
+extern void target_fabric_configfs_deregister(struct target_fabric_configfs *);
+
+struct target_fabric_configfs_template {
+ struct config_item_type tfc_discovery_cit;
+ struct config_item_type tfc_wwn_cit;
+ struct config_item_type tfc_tpg_cit;
+ struct config_item_type tfc_tpg_base_cit;
+ struct config_item_type tfc_tpg_lun_cit;
+ struct config_item_type tfc_tpg_port_cit;
+ struct config_item_type tfc_tpg_np_cit;
+ struct config_item_type tfc_tpg_np_base_cit;
+ struct config_item_type tfc_tpg_attrib_cit;
+ struct config_item_type tfc_tpg_param_cit;
+ struct config_item_type tfc_tpg_nacl_cit;
+ struct config_item_type tfc_tpg_nacl_base_cit;
+ struct config_item_type tfc_tpg_nacl_attrib_cit;
+ struct config_item_type tfc_tpg_nacl_auth_cit;
+ struct config_item_type tfc_tpg_nacl_param_cit;
+ struct config_item_type tfc_tpg_mappedlun_cit;
+};
+
+struct target_fabric_configfs {
+ char tf_name[TARGET_FABRIC_NAME_SIZE];
+ atomic_t tf_access_cnt;
+ struct list_head tf_list;
+ struct config_group tf_group;
+ struct config_group tf_disc_group;
+ struct config_group *tf_default_groups[2];
+ /* Pointer to fabric's config_item */
+ struct config_item *tf_fabric;
+ /* Passed from fabric modules */
+ struct config_item_type *tf_fabric_cit;
+ /* Pointer to target core subsystem */
+ struct configfs_subsystem *tf_subsys;
+ /* Pointer to fabric's struct module */
+ struct module *tf_module;
+ struct target_core_fabric_ops tf_ops;
+ struct target_fabric_configfs_template tf_cit_tmpl;
+};
+
+#define TF_CIT_TMPL(tf) (&(tf)->tf_cit_tmpl)
diff --git a/include/target/target_core_device.h b/include/target/target_core_device.h
new file mode 100644
index 0000000..52b18a5
--- /dev/null
+++ b/include/target/target_core_device.h
@@ -0,0 +1,61 @@
+#ifndef TARGET_CORE_DEVICE_H
+#define TARGET_CORE_DEVICE_H
+
+extern int transport_get_lun_for_cmd(struct se_cmd *, unsigned char *, u32);
+extern int transport_get_lun_for_tmr(struct se_cmd *, u32);
+extern struct se_dev_entry *core_get_se_deve_from_rtpi(
+ struct se_node_acl *, u16);
+extern int core_free_device_list_for_node(struct se_node_acl *,
+ struct se_portal_group *);
+extern void core_dec_lacl_count(struct se_node_acl *, struct se_cmd *);
+extern void core_update_device_list_access(u32, u32, struct se_node_acl *);
+extern int core_update_device_list_for_node(struct se_lun *, struct se_lun_acl *, u32,
+ u32, struct se_node_acl *,
+ struct se_portal_group *, int);
+extern void core_clear_lun_from_tpg(struct se_lun *, struct se_portal_group *);
+extern int core_dev_export(struct se_device *, struct se_portal_group *,
+ struct se_lun *);
+extern void core_dev_unexport(struct se_device *, struct se_portal_group *,
+ struct se_lun *);
+extern int transport_core_report_lun_response(struct se_cmd *);
+extern void se_release_device_for_hba(struct se_device *);
+extern void se_release_vpd_for_dev(struct se_device *);
+extern void se_clear_dev_ports(struct se_device *);
+extern int se_free_virtual_device(struct se_device *, struct se_hba *);
+extern int se_dev_check_online(struct se_device *);
+extern int se_dev_check_shutdown(struct se_device *);
+extern void se_dev_set_default_attribs(struct se_device *, struct se_dev_limits *);
+extern int se_dev_set_task_timeout(struct se_device *, u32);
+extern int se_dev_set_max_unmap_lba_count(struct se_device *, u32);
+extern int se_dev_set_max_unmap_block_desc_count(struct se_device *, u32);
+extern int se_dev_set_unmap_granularity(struct se_device *, u32);
+extern int se_dev_set_unmap_granularity_alignment(struct se_device *, u32);
+extern int se_dev_set_emulate_dpo(struct se_device *, int);
+extern int se_dev_set_emulate_fua_write(struct se_device *, int);
+extern int se_dev_set_emulate_fua_read(struct se_device *, int);
+extern int se_dev_set_emulate_write_cache(struct se_device *, int);
+extern int se_dev_set_emulate_ua_intlck_ctrl(struct se_device *, int);
+extern int se_dev_set_emulate_tas(struct se_device *, int);
+extern int se_dev_set_emulate_tpu(struct se_device *, int);
+extern int se_dev_set_emulate_tpws(struct se_device *, int);
+extern int se_dev_set_enforce_pr_isids(struct se_device *, int);
+extern int se_dev_set_queue_depth(struct se_device *, u32);
+extern int se_dev_set_max_sectors(struct se_device *, u32);
+extern int se_dev_set_optimal_sectors(struct se_device *, u32);
+extern int se_dev_set_block_size(struct se_device *, u32);
+extern struct se_lun *core_dev_add_lun(struct se_portal_group *, struct se_hba *,
+ struct se_device *, u32);
+extern int core_dev_del_lun(struct se_portal_group *, u32);
+extern struct se_lun *core_get_lun_from_tpg(struct se_portal_group *, u32);
+extern struct se_lun_acl *core_dev_init_initiator_node_lun_acl(struct se_portal_group *,
+ u32, char *, int *);
+extern int core_dev_add_initiator_node_lun_acl(struct se_portal_group *,
+ struct se_lun_acl *, u32, u32);
+extern int core_dev_del_initiator_node_lun_acl(struct se_portal_group *,
+ struct se_lun *, struct se_lun_acl *);
+extern void core_dev_free_initiator_node_lun_acl(struct se_portal_group *,
+ struct se_lun_acl *lacl);
+extern int core_dev_setup_virtual_lun0(void);
+extern void core_dev_release_virtual_lun0(void);
+
+#endif /* TARGET_CORE_DEVICE_H */
diff --git a/include/target/target_core_fabric_configfs.h b/include/target/target_core_fabric_configfs.h
new file mode 100644
index 0000000..a26fb75
--- /dev/null
+++ b/include/target/target_core_fabric_configfs.h
@@ -0,0 +1,106 @@
+/*
+ * Used for tfc_wwn_cit attributes
+ */
+
+#include <target/configfs_macros.h>
+
+CONFIGFS_EATTR_STRUCT(target_fabric_nacl_attrib, se_node_acl);
+#define TF_NACL_ATTRIB_ATTR(_fabric, _name, _mode) \
+static struct target_fabric_nacl_attrib_attribute _fabric##_nacl_attrib_##_name = \
+ __CONFIGFS_EATTR(_name, _mode, \
+ _fabric##_nacl_attrib_show_##_name, \
+ _fabric##_nacl_attrib_store_##_name);
+
+CONFIGFS_EATTR_STRUCT(target_fabric_nacl_auth, se_node_acl);
+#define TF_NACL_AUTH_ATTR(_fabric, _name, _mode) \
+static struct target_fabric_nacl_auth_attribute _fabric##_nacl_auth_##_name = \
+ __CONFIGFS_EATTR(_name, _mode, \
+ _fabric##_nacl_auth_show_##_name, \
+ _fabric##_nacl_auth_store_##_name);
+
+#define TF_NACL_AUTH_ATTR_RO(_fabric, _name) \
+static struct target_fabric_nacl_auth_attribute _fabric##_nacl_auth_##_name = \
+ __CONFIGFS_EATTR_RO(_name, \
+ _fabric##_nacl_auth_show_##_name);
+
+CONFIGFS_EATTR_STRUCT(target_fabric_nacl_param, se_node_acl);
+#define TF_NACL_PARAM_ATTR(_fabric, _name, _mode) \
+static struct target_fabric_nacl_param_attribute _fabric##_nacl_param_##_name = \
+ __CONFIGFS_EATTR(_name, _mode, \
+ _fabric##_nacl_param_show_##_name, \
+ _fabric##_nacl_param_store_##_name);
+
+#define TF_NACL_PARAM_ATTR_RO(_fabric, _name) \
+static struct target_fabric_nacl_param_attribute _fabric##_nacl_param_##_name = \
+ __CONFIGFS_EATTR_RO(_name, \
+ _fabric##_nacl_param_show_##_name);
+
+
+CONFIGFS_EATTR_STRUCT(target_fabric_nacl_base, se_node_acl);
+#define TF_NACL_BASE_ATTR(_fabric, _name, _mode) \
+static struct target_fabric_nacl_base_attribute _fabric##_nacl_##_name = \
+ __CONFIGFS_EATTR(_name, _mode, \
+ _fabric##_nacl_show_##_name, \
+ _fabric##_nacl_store_##_name);
+
+#define TF_NACL_BASE_ATTR_RO(_fabric, _name) \
+static struct target_fabric_nacl_base_attribute _fabric##_nacl_##_name = \
+ __CONFIGFS_EATTR_RO(_name, \
+ _fabric##_nacl_show_##_name);
+
+CONFIGFS_EATTR_STRUCT(target_fabric_np_base, se_tpg_np);
+#define TF_NP_BASE_ATTR(_fabric, _name, _mode) \
+static struct target_fabric_np_base_attribute _fabric##_np_##_name = \
+ __CONFIGFS_EATTR(_name, _mode, \
+ _fabric##_np_show_##_name, \
+ _fabric##_np_store_##_name);
+
+CONFIGFS_EATTR_STRUCT(target_fabric_tpg_attrib, se_portal_group);
+#define TF_TPG_ATTRIB_ATTR(_fabric, _name, _mode) \
+static struct target_fabric_tpg_attrib_attribute _fabric##_tpg_attrib_##_name = \
+ __CONFIGFS_EATTR(_name, _mode, \
+ _fabric##_tpg_attrib_show_##_name, \
+ _fabric##_tpg_attrib_store_##_name);
+
+
+CONFIGFS_EATTR_STRUCT(target_fabric_tpg_param, se_portal_group);
+#define TF_TPG_PARAM_ATTR(_fabric, _name, _mode) \
+static struct target_fabric_tpg_param_attribute _fabric##_tpg_param_##_name = \
+ __CONFIGFS_EATTR(_name, _mode, \
+ _fabric##_tpg_param_show_##_name, \
+ _fabric##_tpg_param_store_##_name);
+
+
+CONFIGFS_EATTR_STRUCT(target_fabric_tpg, se_portal_group);
+#define TF_TPG_BASE_ATTR(_fabric, _name, _mode) \
+static struct target_fabric_tpg_attribute _fabric##_tpg_##_name = \
+ __CONFIGFS_EATTR(_name, _mode, \
+ _fabric##_tpg_show_##_name, \
+ _fabric##_tpg_store_##_name);
+
+
+CONFIGFS_EATTR_STRUCT(target_fabric_wwn, target_fabric_configfs);
+#define TF_WWN_ATTR(_fabric, _name, _mode) \
+static struct target_fabric_wwn_attribute _fabric##_wwn_##_name = \
+ __CONFIGFS_EATTR(_name, _mode, \
+ _fabric##_wwn_show_attr_##_name, \
+ _fabric##_wwn_store_attr_##_name);
+
+#define TF_WWN_ATTR_RO(_fabric, _name) \
+static struct target_fabric_wwn_attribute _fabric##_wwn_##_name = \
+ __CONFIGFS_EATTR_RO(_name, \
+ _fabric##_wwn_show_attr_##_name);
+
+CONFIGFS_EATTR_STRUCT(target_fabric_discovery, target_fabric_configfs);
+#define TF_DISC_ATTR(_fabric, _name, _mode) \
+static struct target_fabric_discovery_attribute _fabric##_disc_##_name = \
+ __CONFIGFS_EATTR(_name, _mode, \
+ _fabric##_disc_show_##_name, \
+ _fabric##_disc_store_##_name);
+
+#define TF_DISC_ATTR_RO(_fabric, _name) \
+static struct target_fabric_discovery_attribute _fabric##_disc_##_name = \
+ __CONFIGFS_EATTR_RO(_name, \
+ _fabric##_disc_show_##_name);
+
+extern int target_fabric_setup_cits(struct target_fabric_configfs *);
diff --git a/include/target/target_core_fabric_lib.h b/include/target/target_core_fabric_lib.h
new file mode 100644
index 0000000..c2f8d0e
--- /dev/null
+++ b/include/target/target_core_fabric_lib.h
@@ -0,0 +1,28 @@
+#ifndef TARGET_CORE_FABRIC_LIB_H
+#define TARGET_CORE_FABRIC_LIB_H
+
+extern u8 sas_get_fabric_proto_ident(struct se_portal_group *);
+extern u32 sas_get_pr_transport_id(struct se_portal_group *, struct se_node_acl *,
+ struct t10_pr_registration *, int *, unsigned char *);
+extern u32 sas_get_pr_transport_id_len(struct se_portal_group *, struct se_node_acl *,
+ struct t10_pr_registration *, int *);
+extern char *sas_parse_pr_out_transport_id(struct se_portal_group *,
+ const char *, u32 *, char **);
+
+extern u8 fc_get_fabric_proto_ident(struct se_portal_group *);
+extern u32 fc_get_pr_transport_id(struct se_portal_group *, struct se_node_acl *,
+ struct t10_pr_registration *, int *, unsigned char *);
+extern u32 fc_get_pr_transport_id_len(struct se_portal_group *, struct se_node_acl *,
+ struct t10_pr_registration *, int *);
+extern char *fc_parse_pr_out_transport_id(struct se_portal_group *,
+ const char *, u32 *, char **);
+
+extern u8 iscsi_get_fabric_proto_ident(struct se_portal_group *);
+extern u32 iscsi_get_pr_transport_id(struct se_portal_group *, struct se_node_acl *,
+ struct t10_pr_registration *, int *, unsigned char *);
+extern u32 iscsi_get_pr_transport_id_len(struct se_portal_group *, struct se_node_acl *,
+ struct t10_pr_registration *, int *);
+extern char *iscsi_parse_pr_out_transport_id(struct se_portal_group *,
+ const char *, u32 *, char **);
+
+#endif /* TARGET_CORE_FABRIC_LIB_H */
diff --git a/include/target/target_core_fabric_ops.h b/include/target/target_core_fabric_ops.h
new file mode 100644
index 0000000..f3ac12b
--- /dev/null
+++ b/include/target/target_core_fabric_ops.h
@@ -0,0 +1,100 @@
+/* Defined in target_core_configfs.h */
+struct target_fabric_configfs;
+
+struct target_core_fabric_ops {
+ struct configfs_subsystem *tf_subsys;
+ /*
+ * Optional to signal struct se_task->task_sg[] padding entries
+ * for scatterlist chaining using transport_do_task_sg_link(),
+ * disabled by default
+ */
+ int task_sg_chaining:1;
+ char *(*get_fabric_name)(void);
+ u8 (*get_fabric_proto_ident)(struct se_portal_group *);
+ char *(*tpg_get_wwn)(struct se_portal_group *);
+ u16 (*tpg_get_tag)(struct se_portal_group *);
+ u32 (*tpg_get_default_depth)(struct se_portal_group *);
+ u32 (*tpg_get_pr_transport_id)(struct se_portal_group *,
+ struct se_node_acl *,
+ struct t10_pr_registration *, int *,
+ unsigned char *);
+ u32 (*tpg_get_pr_transport_id_len)(struct se_portal_group *,
+ struct se_node_acl *,
+ struct t10_pr_registration *, int *);
+ char *(*tpg_parse_pr_out_transport_id)(struct se_portal_group *,
+ const char *, u32 *, char **);
+ int (*tpg_check_demo_mode)(struct se_portal_group *);
+ int (*tpg_check_demo_mode_cache)(struct se_portal_group *);
+ int (*tpg_check_demo_mode_write_protect)(struct se_portal_group *);
+ int (*tpg_check_prod_mode_write_protect)(struct se_portal_group *);
+ struct se_node_acl *(*tpg_alloc_fabric_acl)(
+ struct se_portal_group *);
+ void (*tpg_release_fabric_acl)(struct se_portal_group *,
+ struct se_node_acl *);
+ u32 (*tpg_get_inst_index)(struct se_portal_group *);
+ /*
+ * Optional function pointer for TCM to perform command map
+ * from TCM processing thread context, for those struct se_cmd
+ * initally allocated in interrupt context.
+ */
+ int (*new_cmd_map)(struct se_cmd *);
+ /*
+ * Optional function pointer for TCM fabric modules that use
+ * Linux/NET sockets to allocate struct iovec array to struct se_cmd
+ */
+ int (*alloc_cmd_iovecs)(struct se_cmd *);
+ /*
+ * Optional to release struct se_cmd and fabric dependent allocated
+ * I/O descriptor in transport_cmd_check_stop()
+ */
+ void (*check_stop_free)(struct se_cmd *);
+ void (*release_cmd_to_pool)(struct se_cmd *);
+ void (*release_cmd_direct)(struct se_cmd *);
+ /*
+ * Called with spin_lock_bh(struct se_portal_group->session_lock held.
+ */
+ int (*shutdown_session)(struct se_session *);
+ void (*close_session)(struct se_session *);
+ void (*stop_session)(struct se_session *, int, int);
+ void (*fall_back_to_erl0)(struct se_session *);
+ int (*sess_logged_in)(struct se_session *);
+ u32 (*sess_get_index)(struct se_session *);
+ /*
+ * Used only for SCSI fabrics that contain multi-value TransportIDs
+ * (like iSCSI). All other SCSI fabrics should set this to NULL.
+ */
+ u32 (*sess_get_initiator_sid)(struct se_session *,
+ unsigned char *, u32);
+ int (*write_pending)(struct se_cmd *);
+ int (*write_pending_status)(struct se_cmd *);
+ void (*set_default_node_attributes)(struct se_node_acl *);
+ u32 (*get_task_tag)(struct se_cmd *);
+ int (*get_cmd_state)(struct se_cmd *);
+ void (*new_cmd_failure)(struct se_cmd *);
+ int (*queue_data_in)(struct se_cmd *);
+ int (*queue_status)(struct se_cmd *);
+ int (*queue_tm_rsp)(struct se_cmd *);
+ u16 (*set_fabric_sense_len)(struct se_cmd *, u32);
+ u16 (*get_fabric_sense_len)(void);
+ int (*is_state_remove)(struct se_cmd *);
+ u64 (*pack_lun)(unsigned int);
+ /*
+ * fabric module calls for target_core_fabric_configfs.c
+ */
+ struct se_wwn *(*fabric_make_wwn)(struct target_fabric_configfs *,
+ struct config_group *, const char *);
+ void (*fabric_drop_wwn)(struct se_wwn *);
+ struct se_portal_group *(*fabric_make_tpg)(struct se_wwn *,
+ struct config_group *, const char *);
+ void (*fabric_drop_tpg)(struct se_portal_group *);
+ int (*fabric_post_link)(struct se_portal_group *,
+ struct se_lun *);
+ void (*fabric_pre_unlink)(struct se_portal_group *,
+ struct se_lun *);
+ struct se_tpg_np *(*fabric_make_np)(struct se_portal_group *,
+ struct config_group *, const char *);
+ void (*fabric_drop_np)(struct se_tpg_np *);
+ struct se_node_acl *(*fabric_make_nodeacl)(struct se_portal_group *,
+ struct config_group *, const char *);
+ void (*fabric_drop_nodeacl)(struct se_node_acl *);
+};
diff --git a/include/target/target_core_tmr.h b/include/target/target_core_tmr.h
new file mode 100644
index 0000000..6c8248b
--- /dev/null
+++ b/include/target/target_core_tmr.h
@@ -0,0 +1,43 @@
+#ifndef TARGET_CORE_TMR_H
+#define TARGET_CORE_TMR_H
+
+/* task management function values */
+#ifdef ABORT_TASK
+#undef ABORT_TASK
+#endif /* ABORT_TASK */
+#define ABORT_TASK 1
+#ifdef ABORT_TASK_SET
+#undef ABORT_TASK_SET
+#endif /* ABORT_TASK_SET */
+#define ABORT_TASK_SET 2
+#ifdef CLEAR_ACA
+#undef CLEAR_ACA
+#endif /* CLEAR_ACA */
+#define CLEAR_ACA 3
+#ifdef CLEAR_TASK_SET
+#undef CLEAR_TASK_SET
+#endif /* CLEAR_TASK_SET */
+#define CLEAR_TASK_SET 4
+#define LUN_RESET 5
+#define TARGET_WARM_RESET 6
+#define TARGET_COLD_RESET 7
+#define TASK_REASSIGN 8
+
+/* task management response values */
+#define TMR_FUNCTION_COMPLETE 0
+#define TMR_TASK_DOES_NOT_EXIST 1
+#define TMR_LUN_DOES_NOT_EXIST 2
+#define TMR_TASK_STILL_ALLEGIANT 3
+#define TMR_TASK_FAILOVER_NOT_SUPPORTED 4
+#define TMR_TASK_MGMT_FUNCTION_NOT_SUPPORTED 5
+#define TMR_FUNCTION_AUTHORIZATION_FAILED 6
+#define TMR_FUNCTION_REJECTED 255
+
+extern struct kmem_cache *se_tmr_req_cache;
+
+extern struct se_tmr_req *core_tmr_alloc_req(struct se_cmd *, void *, u8);
+extern void core_tmr_release_req(struct se_tmr_req *);
+extern int core_tmr_lun_reset(struct se_device *, struct se_tmr_req *,
+ struct list_head *, struct se_cmd *);
+
+#endif /* TARGET_CORE_TMR_H */
diff --git a/include/target/target_core_tpg.h b/include/target/target_core_tpg.h
new file mode 100644
index 0000000..77e1872
--- /dev/null
+++ b/include/target/target_core_tpg.h
@@ -0,0 +1,35 @@
+#ifndef TARGET_CORE_TPG_H
+#define TARGET_CORE_TPG_H
+
+extern struct se_node_acl *__core_tpg_get_initiator_node_acl(struct se_portal_group *tpg,
+ const char *);
+extern struct se_node_acl *core_tpg_get_initiator_node_acl(struct se_portal_group *tpg,
+ unsigned char *);
+extern void core_tpg_add_node_to_devs(struct se_node_acl *,
+ struct se_portal_group *);
+extern struct se_node_acl *core_tpg_check_initiator_node_acl(
+ struct se_portal_group *,
+ unsigned char *);
+extern void core_tpg_wait_for_nacl_pr_ref(struct se_node_acl *);
+extern void core_tpg_wait_for_mib_ref(struct se_node_acl *);
+extern void core_tpg_clear_object_luns(struct se_portal_group *);
+extern struct se_node_acl *core_tpg_add_initiator_node_acl(
+ struct se_portal_group *,
+ struct se_node_acl *,
+ const char *, u32);
+extern int core_tpg_del_initiator_node_acl(struct se_portal_group *,
+ struct se_node_acl *, int);
+extern int core_tpg_set_initiator_node_queue_depth(struct se_portal_group *,
+ unsigned char *, u32, int);
+extern int core_tpg_register(struct target_core_fabric_ops *,
+ struct se_wwn *,
+ struct se_portal_group *, void *,
+ int);
+extern int core_tpg_deregister(struct se_portal_group *);
+extern struct se_lun *core_tpg_pre_addlun(struct se_portal_group *, u32);
+extern int core_tpg_post_addlun(struct se_portal_group *, struct se_lun *, u32,
+ void *);
+extern struct se_lun *core_tpg_pre_dellun(struct se_portal_group *, u32, int *);
+extern int core_tpg_post_dellun(struct se_portal_group *, struct se_lun *);
+
+#endif /* TARGET_CORE_TPG_H */
diff --git a/include/target/target_core_transport.h b/include/target/target_core_transport.h
new file mode 100644
index 0000000..66f44e5
--- /dev/null
+++ b/include/target/target_core_transport.h
@@ -0,0 +1,351 @@
+#ifndef TARGET_CORE_TRANSPORT_H
+#define TARGET_CORE_TRANSPORT_H
+
+#define TARGET_CORE_VERSION TARGET_CORE_MOD_VERSION
+
+/* Attempts before moving from SHORT to LONG */
+#define PYX_TRANSPORT_WINDOW_CLOSED_THRESHOLD 3
+#define PYX_TRANSPORT_WINDOW_CLOSED_WAIT_SHORT 3 /* In milliseconds */
+#define PYX_TRANSPORT_WINDOW_CLOSED_WAIT_LONG 10 /* In milliseconds */
+
+#define PYX_TRANSPORT_STATUS_INTERVAL 5 /* In seconds */
+
+#define PYX_TRANSPORT_SENT_TO_TRANSPORT 0
+#define PYX_TRANSPORT_WRITE_PENDING 1
+
+#define PYX_TRANSPORT_UNKNOWN_SAM_OPCODE -1
+#define PYX_TRANSPORT_HBA_QUEUE_FULL -2
+#define PYX_TRANSPORT_REQ_TOO_MANY_SECTORS -3
+#define PYX_TRANSPORT_OUT_OF_MEMORY_RESOURCES -4
+#define PYX_TRANSPORT_INVALID_CDB_FIELD -5
+#define PYX_TRANSPORT_INVALID_PARAMETER_LIST -6
+#define PYX_TRANSPORT_LU_COMM_FAILURE -7
+#define PYX_TRANSPORT_UNKNOWN_MODE_PAGE -8
+#define PYX_TRANSPORT_WRITE_PROTECTED -9
+#define PYX_TRANSPORT_TASK_TIMEOUT -10
+#define PYX_TRANSPORT_RESERVATION_CONFLICT -11
+#define PYX_TRANSPORT_ILLEGAL_REQUEST -12
+#define PYX_TRANSPORT_USE_SENSE_REASON -13
+
+#ifndef SAM_STAT_RESERVATION_CONFLICT
+#define SAM_STAT_RESERVATION_CONFLICT 0x18
+#endif
+
+#define TRANSPORT_PLUGIN_FREE 0
+#define TRANSPORT_PLUGIN_REGISTERED 1
+
+#define TRANSPORT_PLUGIN_PHBA_PDEV 1
+#define TRANSPORT_PLUGIN_VHBA_PDEV 2
+#define TRANSPORT_PLUGIN_VHBA_VDEV 3
+
+/* For SE OBJ Plugins, in seconds */
+#define TRANSPORT_TIMEOUT_TUR 10
+#define TRANSPORT_TIMEOUT_TYPE_DISK 60
+#define TRANSPORT_TIMEOUT_TYPE_ROM 120
+#define TRANSPORT_TIMEOUT_TYPE_TAPE 600
+#define TRANSPORT_TIMEOUT_TYPE_OTHER 300
+
+/* For se_task->task_state_flags */
+#define TSF_EXCEPTION_CLEARED 0x01
+
+/*
+ * struct se_subsystem_dev->su_dev_flags
+*/
+#define SDF_FIRMWARE_VPD_UNIT_SERIAL 0x00000001
+#define SDF_EMULATED_VPD_UNIT_SERIAL 0x00000002
+#define SDF_USING_UDEV_PATH 0x00000004
+#define SDF_USING_ALIAS 0x00000008
+
+/*
+ * struct se_device->dev_flags
+ */
+#define DF_READ_ONLY 0x00000001
+#define DF_SPC2_RESERVATIONS 0x00000002
+#define DF_SPC2_RESERVATIONS_WITH_ISID 0x00000004
+
+/* struct se_dev_attrib sanity values */
+/* 10 Minutes */
+#define DA_TASK_TIMEOUT_MAX 600
+/* Default max_unmap_lba_count */
+#define DA_MAX_UNMAP_LBA_COUNT 0
+/* Default max_unmap_block_desc_count */
+#define DA_MAX_UNMAP_BLOCK_DESC_COUNT 0
+/* Default unmap_granularity */
+#define DA_UNMAP_GRANULARITY_DEFAULT 0
+/* Default unmap_granularity_alignment */
+#define DA_UNMAP_GRANULARITY_ALIGNMENT_DEFAULT 0
+/* Emulation for Direct Page Out */
+#define DA_EMULATE_DPO 0
+/* Emulation for Forced Unit Access WRITEs */
+#define DA_EMULATE_FUA_WRITE 1
+/* Emulation for Forced Unit Access READs */
+#define DA_EMULATE_FUA_READ 0
+/* Emulation for WriteCache and SYNCHRONIZE_CACHE */
+#define DA_EMULATE_WRITE_CACHE 0
+/* Emulation for UNIT ATTENTION Interlock Control */
+#define DA_EMULATE_UA_INTLLCK_CTRL 0
+/* Emulation for TASK_ABORTED status (TAS) by default */
+#define DA_EMULATE_TAS 1
+/* Emulation for Thin Provisioning UNMAP using block/blk-lib.c:blkdev_issue_discard() */
+#define DA_EMULATE_TPU 0
+/*
+ * Emulation for Thin Provisioning WRITE_SAME w/ UNMAP=1 bit using
+ * block/blk-lib.c:blkdev_issue_discard()
+ */
+#define DA_EMULATE_TPWS 0
+/* No Emulation for PSCSI by default */
+#define DA_EMULATE_RESERVATIONS 0
+/* No Emulation for PSCSI by default */
+#define DA_EMULATE_ALUA 0
+/* Enforce SCSI Initiator Port TransportID with 'ISID' for PR */
+#define DA_ENFORCE_PR_ISIDS 1
+#define DA_STATUS_MAX_SECTORS_MIN 16
+#define DA_STATUS_MAX_SECTORS_MAX 8192
+
+#define SE_MODE_PAGE_BUF 512
+
+#define MOD_MAX_SECTORS(ms, bs) (ms % (PAGE_SIZE / bs))
+
+struct se_mem;
+struct se_subsystem_api;
+
+extern int init_se_global(void);
+extern void release_se_global(void);
+extern void transport_init_queue_obj(struct se_queue_obj *);
+extern int transport_subsystem_check_init(void);
+extern int transport_subsystem_register(struct se_subsystem_api *);
+extern void transport_subsystem_release(struct se_subsystem_api *);
+extern void transport_load_plugins(void);
+extern struct se_session *transport_init_session(void);
+extern void __transport_register_session(struct se_portal_group *,
+ struct se_node_acl *,
+ struct se_session *, void *);
+extern void transport_register_session(struct se_portal_group *,
+ struct se_node_acl *,
+ struct se_session *, void *);
+extern void transport_free_session(struct se_session *);
+extern void transport_deregister_session_configfs(struct se_session *);
+extern void transport_deregister_session(struct se_session *);
+extern void transport_cmd_finish_abort(struct se_cmd *, int);
+extern void transport_cmd_finish_abort_tmr(struct se_cmd *);
+extern void transport_complete_sync_cache(struct se_cmd *, int);
+extern void transport_complete_task(struct se_task *, int);
+extern void transport_add_task_to_execute_queue(struct se_task *,
+ struct se_task *,
+ struct se_device *);
+unsigned char *transport_dump_cmd_direction(struct se_cmd *);
+extern void transport_dump_dev_state(struct se_device *, char *, int *);
+extern void transport_dump_dev_info(struct se_device *, struct se_lun *,
+ unsigned long long, char *, int *);
+extern void transport_dump_vpd_proto_id(struct t10_vpd *,
+ unsigned char *, int);
+extern void transport_set_vpd_proto_id(struct t10_vpd *, unsigned char *);
+extern int transport_dump_vpd_assoc(struct t10_vpd *,
+ unsigned char *, int);
+extern int transport_set_vpd_assoc(struct t10_vpd *, unsigned char *);
+extern int transport_dump_vpd_ident_type(struct t10_vpd *,
+ unsigned char *, int);
+extern int transport_set_vpd_ident_type(struct t10_vpd *, unsigned char *);
+extern int transport_dump_vpd_ident(struct t10_vpd *,
+ unsigned char *, int);
+extern int transport_set_vpd_ident(struct t10_vpd *, unsigned char *);
+extern struct se_device *transport_add_device_to_core_hba(struct se_hba *,
+ struct se_subsystem_api *,
+ struct se_subsystem_dev *, u32,
+ void *, struct se_dev_limits *,
+ const char *, const char *);
+extern void transport_device_setup_cmd(struct se_cmd *);
+extern void transport_init_se_cmd(struct se_cmd *,
+ struct target_core_fabric_ops *,
+ struct se_session *, u32, int, int,
+ unsigned char *);
+extern void transport_free_se_cmd(struct se_cmd *);
+extern int transport_generic_allocate_tasks(struct se_cmd *, unsigned char *);
+extern int transport_generic_handle_cdb(struct se_cmd *);
+extern int transport_generic_handle_cdb_map(struct se_cmd *);
+extern int transport_generic_handle_data(struct se_cmd *);
+extern void transport_new_cmd_failure(struct se_cmd *);
+extern int transport_generic_handle_tmr(struct se_cmd *);
+extern void __transport_stop_task_timer(struct se_task *, unsigned long *);
+extern unsigned char transport_asciihex_to_binaryhex(unsigned char val[2]);
+extern int transport_generic_map_mem_to_cmd(struct se_cmd *cmd, struct scatterlist *, u32,
+ struct scatterlist *, u32);
+extern int transport_clear_lun_from_sessions(struct se_lun *);
+extern int transport_check_aborted_status(struct se_cmd *, int);
+extern int transport_send_check_condition_and_sense(struct se_cmd *, u8, int);
+extern void transport_send_task_abort(struct se_cmd *);
+extern void transport_release_cmd_to_pool(struct se_cmd *);
+extern void transport_generic_free_cmd(struct se_cmd *, int, int, int);
+extern void transport_generic_wait_for_cmds(struct se_cmd *, int);
+extern u32 transport_calc_sg_num(struct se_task *, struct se_mem *, u32);
+extern int transport_map_mem_to_sg(struct se_task *, struct list_head *,
+ void *, struct se_mem *,
+ struct se_mem **, u32 *, u32 *);
+extern void transport_do_task_sg_chain(struct se_cmd *);
+extern void transport_generic_process_write(struct se_cmd *);
+extern int transport_generic_do_tmr(struct se_cmd *);
+/* From target_core_alua.c */
+extern int core_alua_check_nonop_delay(struct se_cmd *);
+
+/*
+ * Each se_transport_task_t can have N number of possible struct se_task's
+ * for the storage transport(s) to possibly execute.
+ * Used primarily for splitting up CDBs that exceed the physical storage
+ * HBA's maximum sector count per task.
+ */
+struct se_mem {
+ struct page *se_page;
+ u32 se_len;
+ u32 se_off;
+ struct list_head se_list;
+} ____cacheline_aligned;
+
+/*
+ * Each type of disk transport supported MUST have a template defined
+ * within its .h file.
+ */
+struct se_subsystem_api {
+ /*
+ * The Name. :-)
+ */
+ char name[16];
+ /*
+ * Transport Type.
+ */
+ u8 transport_type;
+ /*
+ * struct module for struct se_hba references
+ */
+ struct module *owner;
+ /*
+ * Used for global se_subsystem_api list_head
+ */
+ struct list_head sub_api_list;
+ /*
+ * For SCF_SCSI_NON_DATA_CDB
+ */
+ int (*cdb_none)(struct se_task *);
+ /*
+ * For SCF_SCSI_CONTROL_NONSG_IO_CDB
+ */
+ int (*map_task_non_SG)(struct se_task *);
+ /*
+ * For SCF_SCSI_DATA_SG_IO_CDB and SCF_SCSI_CONTROL_SG_IO_CDB
+ */
+ int (*map_task_SG)(struct se_task *);
+ /*
+ * attach_hba():
+ */
+ int (*attach_hba)(struct se_hba *, u32);
+ /*
+ * detach_hba():
+ */
+ void (*detach_hba)(struct se_hba *);
+ /*
+ * pmode_hba(): Used for TCM/pSCSI subsystem plugin HBA ->
+ * Linux/SCSI struct Scsi_Host passthrough
+ */
+ int (*pmode_enable_hba)(struct se_hba *, unsigned long);
+ /*
+ * allocate_virtdevice():
+ */
+ void *(*allocate_virtdevice)(struct se_hba *, const char *);
+ /*
+ * create_virtdevice(): Only for Virtual HBAs
+ */
+ struct se_device *(*create_virtdevice)(struct se_hba *,
+ struct se_subsystem_dev *, void *);
+ /*
+ * free_device():
+ */
+ void (*free_device)(void *);
+
+ /*
+ * dpo_emulated():
+ */
+ int (*dpo_emulated)(struct se_device *);
+ /*
+ * fua_write_emulated():
+ */
+ int (*fua_write_emulated)(struct se_device *);
+ /*
+ * fua_read_emulated():
+ */
+ int (*fua_read_emulated)(struct se_device *);
+ /*
+ * write_cache_emulated():
+ */
+ int (*write_cache_emulated)(struct se_device *);
+ /*
+ * transport_complete():
+ *
+ * Use transport_generic_complete() for majority of DAS transport
+ * drivers. Provided out of convenience.
+ */
+ int (*transport_complete)(struct se_task *task);
+ struct se_task *(*alloc_task)(struct se_cmd *);
+ /*
+ * do_task():
+ */
+ int (*do_task)(struct se_task *);
+ /*
+ * Used by virtual subsystem plugins IBLOCK and FILEIO to emulate
+ * UNMAP and WRITE_SAME_* w/ UNMAP=1 <-> Linux/Block Discard
+ */
+ int (*do_discard)(struct se_device *, sector_t, u32);
+ /*
+ * Used by virtual subsystem plugins IBLOCK and FILEIO to emulate
+ * SYNCHRONIZE_CACHE_* <-> Linux/Block blkdev_issue_flush()
+ */
+ void (*do_sync_cache)(struct se_task *);
+ /*
+ * free_task():
+ */
+ void (*free_task)(struct se_task *);
+ /*
+ * check_configfs_dev_params():
+ */
+ ssize_t (*check_configfs_dev_params)(struct se_hba *, struct se_subsystem_dev *);
+ /*
+ * set_configfs_dev_params():
+ */
+ ssize_t (*set_configfs_dev_params)(struct se_hba *, struct se_subsystem_dev *,
+ const char *, ssize_t);
+ /*
+ * show_configfs_dev_params():
+ */
+ ssize_t (*show_configfs_dev_params)(struct se_hba *, struct se_subsystem_dev *,
+ char *);
+ /*
+ * get_cdb():
+ */
+ unsigned char *(*get_cdb)(struct se_task *);
+ /*
+ * get_device_rev():
+ */
+ u32 (*get_device_rev)(struct se_device *);
+ /*
+ * get_device_type():
+ */
+ u32 (*get_device_type)(struct se_device *);
+ /*
+ * Get the sector_t from a subsystem backstore..
+ */
+ sector_t (*get_blocks)(struct se_device *);
+ /*
+ * do_se_mem_map():
+ */
+ int (*do_se_mem_map)(struct se_task *, struct list_head *, void *,
+ struct se_mem *, struct se_mem **, u32 *, u32 *);
+ /*
+ * get_sense_buffer():
+ */
+ unsigned char *(*get_sense_buffer)(struct se_task *);
+} ____cacheline_aligned;
+
+#define TRANSPORT(dev) ((dev)->transport)
+#define HBA_TRANSPORT(hba) ((hba)->transport)
+
+extern struct se_global *se_global;
+
+#endif /* TARGET_CORE_TRANSPORT_H */
diff --git a/include/trace/events/module.h b/include/trace/events/module.h
index c7bb2f0..c6bae36 100644
--- a/include/trace/events/module.h
+++ b/include/trace/events/module.h
@@ -1,5 +1,15 @@
+/*
+ * Because linux/module.h has tracepoints in the header, and ftrace.h
+ * eventually includes this file, define_trace.h includes linux/module.h
+ * But we do not want the module.h to override the TRACE_SYSTEM macro
+ * variable that define_trace.h is processing, so we only set it
+ * when module events are being processed, which would happen when
+ * CREATE_TRACE_POINTS is defined.
+ */
+#ifdef CREATE_TRACE_POINTS
#undef TRACE_SYSTEM
#define TRACE_SYSTEM module
+#endif
#if !defined(_TRACE_MODULE_H) || defined(TRACE_HEADER_MULTI_READ)
#define _TRACE_MODULE_H
diff --git a/init/Kconfig b/init/Kconfig
index 4f6cdbf..be788c0 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -515,21 +515,6 @@ config RCU_BOOST_DELAY
Accept the default if unsure.
-config SRCU_SYNCHRONIZE_DELAY
- int "Microseconds to delay before waiting for readers"
- range 0 20
- default 10
- help
- This option controls how long SRCU delays before entering its
- loop waiting on SRCU readers. The purpose of this loop is
- to avoid the unconditional context-switch penalty that would
- otherwise be incurred if there was an active SRCU reader,
- in a manner similar to adaptive locking schemes. This should
- be set to be a bit longer than the common-case SRCU read-side
- critical-section overhead.
-
- Accept the default if unsure.
-
endmenu # "RCU Subsystem"
config IKCONFIG
@@ -760,8 +745,8 @@ config DEBUG_BLK_CGROUP
endif # CGROUPS
menuconfig NAMESPACES
- bool "Namespaces support" if EMBEDDED
- default !EMBEDDED
+ bool "Namespaces support" if EXPERT
+ default !EXPERT
help
Provides the way to make tasks work with different objects using
the same id. For example same IPC id may refer to different objects
@@ -914,23 +899,31 @@ config SYSCTL
config ANON_INODES
bool
-menuconfig EMBEDDED
- bool "Configure standard kernel features (for small systems)"
+menuconfig EXPERT
+ bool "Configure standard kernel features (expert users)"
help
This option allows certain base kernel options and settings
to be disabled or tweaked. This is for specialized
environments which can tolerate a "non-standard" kernel.
Only use this if you really know what you are doing.
+config EMBEDDED
+ bool "Embedded system"
+ select EXPERT
+ help
+ This option should be enabled if compiling the kernel for
+ an embedded system so certain expert options are available
+ for configuration.
+
config UID16
- bool "Enable 16-bit UID system calls" if EMBEDDED
+ bool "Enable 16-bit UID system calls" if EXPERT
depends on ARM || BLACKFIN || CRIS || FRV || H8300 || X86_32 || M68K || (S390 && !64BIT) || SUPERH || SPARC32 || (SPARC64 && COMPAT) || UML || (X86_64 && IA32_EMULATION)
default y
help
This enables the legacy 16-bit UID syscall wrappers.
config SYSCTL_SYSCALL
- bool "Sysctl syscall support" if EMBEDDED
+ bool "Sysctl syscall support" if EXPERT
depends on PROC_SYSCTL
default y
select SYSCTL
@@ -947,7 +940,7 @@ config SYSCTL_SYSCALL
If unsure say Y here.
config KALLSYMS
- bool "Load all symbols for debugging/ksymoops" if EMBEDDED
+ bool "Load all symbols for debugging/ksymoops" if EXPERT
default y
help
Say Y here to let the kernel print out symbolic crash information and
@@ -978,7 +971,7 @@ config KALLSYMS_EXTRA_PASS
config HOTPLUG
- bool "Support for hot-pluggable devices" if EMBEDDED
+ bool "Support for hot-pluggable devices" if EXPERT
default y
help
This option is provided for the case where no hotplug or uevent
@@ -988,7 +981,7 @@ config HOTPLUG
config PRINTK
default y
- bool "Enable support for printk" if EMBEDDED
+ bool "Enable support for printk" if EXPERT
help
This option enables normal printk support. Removing it
eliminates most of the message strings from the kernel image
@@ -997,7 +990,7 @@ config PRINTK
strongly discouraged.
config BUG
- bool "BUG() support" if EMBEDDED
+ bool "BUG() support" if EXPERT
default y
help
Disabling this option eliminates support for BUG and WARN, reducing
@@ -1008,12 +1001,12 @@ config BUG
config ELF_CORE
default y
- bool "Enable ELF core dumps" if EMBEDDED
+ bool "Enable ELF core dumps" if EXPERT
help
Enable support for generating core dumps. Disabling saves about 4k.
config PCSPKR_PLATFORM
- bool "Enable PC-Speaker support" if EMBEDDED
+ bool "Enable PC-Speaker support" if EXPERT
depends on ALPHA || X86 || MIPS || PPC_PREP || PPC_CHRP || PPC_PSERIES
default y
help
@@ -1022,14 +1015,14 @@ config PCSPKR_PLATFORM
config BASE_FULL
default y
- bool "Enable full-sized data structures for core" if EMBEDDED
+ bool "Enable full-sized data structures for core" if EXPERT
help
Disabling this option reduces the size of miscellaneous core
kernel data structures. This saves memory on small machines,
but may reduce performance.
config FUTEX
- bool "Enable futex support" if EMBEDDED
+ bool "Enable futex support" if EXPERT
default y
select RT_MUTEXES
help
@@ -1038,7 +1031,7 @@ config FUTEX
run glibc-based applications correctly.
config EPOLL
- bool "Enable eventpoll support" if EMBEDDED
+ bool "Enable eventpoll support" if EXPERT
default y
select ANON_INODES
help
@@ -1046,7 +1039,7 @@ config EPOLL
support for epoll family of system calls.
config SIGNALFD
- bool "Enable signalfd() system call" if EMBEDDED
+ bool "Enable signalfd() system call" if EXPERT
select ANON_INODES
default y
help
@@ -1056,7 +1049,7 @@ config SIGNALFD
If unsure, say Y.
config TIMERFD
- bool "Enable timerfd() system call" if EMBEDDED
+ bool "Enable timerfd() system call" if EXPERT
select ANON_INODES
default y
help
@@ -1066,7 +1059,7 @@ config TIMERFD
If unsure, say Y.
config EVENTFD
- bool "Enable eventfd() system call" if EMBEDDED
+ bool "Enable eventfd() system call" if EXPERT
select ANON_INODES
default y
help
@@ -1076,7 +1069,7 @@ config EVENTFD
If unsure, say Y.
config SHMEM
- bool "Use full shmem filesystem" if EMBEDDED
+ bool "Use full shmem filesystem" if EXPERT
default y
depends on MMU
help
@@ -1087,7 +1080,7 @@ config SHMEM
which may be appropriate on small systems without swap.
config AIO
- bool "Enable AIO support" if EMBEDDED
+ bool "Enable AIO support" if EXPERT
default y
help
This option enables POSIX asynchronous I/O which may by used
@@ -1164,16 +1157,16 @@ endmenu
config VM_EVENT_COUNTERS
default y
- bool "Enable VM event counters for /proc/vmstat" if EMBEDDED
+ bool "Enable VM event counters for /proc/vmstat" if EXPERT
help
VM event counters are needed for event counts to be shown.
This option allows the disabling of the VM event counters
- on EMBEDDED systems. /proc/vmstat will only show page counts
+ on EXPERT systems. /proc/vmstat will only show page counts
if VM event counters are disabled.
config PCI_QUIRKS
default y
- bool "Enable PCI quirk workarounds" if EMBEDDED
+ bool "Enable PCI quirk workarounds" if EXPERT
depends on PCI
help
This enables workarounds for various PCI chipset
@@ -1182,7 +1175,7 @@ config PCI_QUIRKS
config SLUB_DEBUG
default y
- bool "Enable SLUB debugging support" if EMBEDDED
+ bool "Enable SLUB debugging support" if EXPERT
depends on SLUB && SYSFS
help
SLUB has extensive debug support features. Disabling these can
@@ -1226,7 +1219,7 @@ config SLUB
a slab allocator.
config SLOB
- depends on EMBEDDED
+ depends on EXPERT
bool "SLOB (Simple Allocator)"
help
SLOB replaces the stock allocator with a drastically simpler
@@ -1237,7 +1230,7 @@ endchoice
config MMAP_ALLOW_UNINITIALIZED
bool "Allow mmapped anonymous memory to be uninitialized"
- depends on EMBEDDED && !MMU
+ depends on EXPERT && !MMU
default n
help
Normally, and according to the Linux spec, anonymous memory obtained
diff --git a/init/main.c b/init/main.c
index 00799c1..33c37c3 100644
--- a/init/main.c
+++ b/init/main.c
@@ -96,6 +96,15 @@ static inline void mark_rodata_ro(void) { }
extern void tc_init(void);
#endif
+/*
+ * Debug helper: via this flag we know that we are in 'early bootup code'
+ * where only the boot processor is running with IRQ disabled. This means
+ * two things - IRQ must not be enabled before the flag is cleared and some
+ * operations which are not allowed with IRQ disabled are allowed while the
+ * flag is set.
+ */
+bool early_boot_irqs_disabled __read_mostly;
+
enum system_states system_state __read_mostly;
EXPORT_SYMBOL(system_state);
@@ -554,7 +563,7 @@ asmlinkage void __init start_kernel(void)
cgroup_init_early();
local_irq_disable();
- early_boot_irqs_off();
+ early_boot_irqs_disabled = true;
/*
* Interrupts are still disabled. Do necessary setups, then
@@ -621,7 +630,7 @@ asmlinkage void __init start_kernel(void)
if (!irqs_disabled())
printk(KERN_CRIT "start_kernel(): bug: interrupts were "
"enabled early\n");
- early_boot_irqs_on();
+ early_boot_irqs_disabled = false;
local_irq_enable();
/* Interrupts are enabled now so all GFP allocations are safe. */
diff --git a/kernel/cgroup.c b/kernel/cgroup.c
index 5c5f4cc..b24d702 100644
--- a/kernel/cgroup.c
+++ b/kernel/cgroup.c
@@ -764,6 +764,7 @@ EXPORT_SYMBOL_GPL(cgroup_unlock);
*/
static int cgroup_mkdir(struct inode *dir, struct dentry *dentry, int mode);
+static struct dentry *cgroup_lookup(struct inode *, struct dentry *, struct nameidata *);
static int cgroup_rmdir(struct inode *unused_dir, struct dentry *dentry);
static int cgroup_populate_dir(struct cgroup *cgrp);
static const struct inode_operations cgroup_dir_inode_operations;
@@ -860,6 +861,11 @@ static void cgroup_diput(struct dentry *dentry, struct inode *inode)
iput(inode);
}
+static int cgroup_delete(const struct dentry *d)
+{
+ return 1;
+}
+
static void remove_dir(struct dentry *d)
{
struct dentry *parent = dget(d->d_parent);
@@ -910,7 +916,7 @@ static void cgroup_d_remove_dir(struct dentry *dentry)
parent = dentry->d_parent;
spin_lock(&parent->d_lock);
- spin_lock(&dentry->d_lock);
+ spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED);
list_del_init(&dentry->d_u.d_child);
spin_unlock(&dentry->d_lock);
spin_unlock(&parent->d_lock);
@@ -1451,6 +1457,7 @@ static int cgroup_get_rootdir(struct super_block *sb)
{
static const struct dentry_operations cgroup_dops = {
.d_iput = cgroup_diput,
+ .d_delete = cgroup_delete,
};
struct inode *inode =
@@ -2195,12 +2202,20 @@ static const struct file_operations cgroup_file_operations = {
};
static const struct inode_operations cgroup_dir_inode_operations = {
- .lookup = simple_lookup,
+ .lookup = cgroup_lookup,
.mkdir = cgroup_mkdir,
.rmdir = cgroup_rmdir,
.rename = cgroup_rename,
};
+static struct dentry *cgroup_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
+{
+ if (dentry->d_name.len > NAME_MAX)
+ return ERR_PTR(-ENAMETOOLONG);
+ d_add(dentry, NULL);
+ return NULL;
+}
+
/*
* Check if a file is a control file
*/
diff --git a/kernel/futex.c b/kernel/futex.c
index 5207563..b766d28 100644
--- a/kernel/futex.c
+++ b/kernel/futex.c
@@ -826,10 +826,9 @@ static int wake_futex_pi(u32 __user *uaddr, u32 uval, struct futex_q *this)
new_owner = rt_mutex_next_owner(&pi_state->pi_mutex);
/*
- * This happens when we have stolen the lock and the original
- * pending owner did not enqueue itself back on the rt_mutex.
- * Thats not a tragedy. We know that way, that a lock waiter
- * is on the fly. We make the futex_q waiter the pending owner.
+ * It is possible that the next waiter (the one that brought
+ * this owner to the kernel) timed out and is no longer
+ * waiting on the lock.
*/
if (!new_owner)
new_owner = this->task;
diff --git a/kernel/irq/Kconfig b/kernel/irq/Kconfig
index 31d766b..8e42fec 100644
--- a/kernel/irq/Kconfig
+++ b/kernel/irq/Kconfig
@@ -9,9 +9,6 @@ menu "IRQ subsystem"
config GENERIC_HARDIRQS
def_bool y
-config GENERIC_HARDIRQS_NO__DO_IRQ
- def_bool y
-
# Select this to disable the deprecated stuff
config GENERIC_HARDIRQS_NO_DEPRECATED
def_bool n
diff --git a/kernel/irq/handle.c b/kernel/irq/handle.c
index e2347eb..3540a71 100644
--- a/kernel/irq/handle.c
+++ b/kernel/irq/handle.c
@@ -118,114 +118,3 @@ irqreturn_t handle_IRQ_event(unsigned int irq, struct irqaction *action)
return retval;
}
-
-#ifndef CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ
-
-#ifdef CONFIG_ENABLE_WARN_DEPRECATED
-# warning __do_IRQ is deprecated. Please convert to proper flow handlers
-#endif
-
-/**
- * __do_IRQ - original all in one highlevel IRQ handler
- * @irq: the interrupt number
- *
- * __do_IRQ handles all normal device IRQ's (the special
- * SMP cross-CPU interrupts have their own specific
- * handlers).
- *
- * This is the original x86 implementation which is used for every
- * interrupt type.
- */
-unsigned int __do_IRQ(unsigned int irq)
-{
- struct irq_desc *desc = irq_to_desc(irq);
- struct irqaction *action;
- unsigned int status;
-
- kstat_incr_irqs_this_cpu(irq, desc);
-
- if (CHECK_IRQ_PER_CPU(desc->status)) {
- irqreturn_t action_ret;
-
- /*
- * No locking required for CPU-local interrupts:
- */
- if (desc->irq_data.chip->ack)
- desc->irq_data.chip->ack(irq);
- if (likely(!(desc->status & IRQ_DISABLED))) {
- action_ret = handle_IRQ_event(irq, desc->action);
- if (!noirqdebug)
- note_interrupt(irq, desc, action_ret);
- }
- desc->irq_data.chip->end(irq);
- return 1;
- }
-
- raw_spin_lock(&desc->lock);
- if (desc->irq_data.chip->ack)
- desc->irq_data.chip->ack(irq);
- /*
- * REPLAY is when Linux resends an IRQ that was dropped earlier
- * WAITING is used by probe to mark irqs that are being tested
- */
- status = desc->status & ~(IRQ_REPLAY | IRQ_WAITING);
- status |= IRQ_PENDING; /* we _want_ to handle it */
-
- /*
- * If the IRQ is disabled for whatever reason, we cannot
- * use the action we have.
- */
- action = NULL;
- if (likely(!(status & (IRQ_DISABLED | IRQ_INPROGRESS)))) {
- action = desc->action;
- status &= ~IRQ_PENDING; /* we commit to handling */
- status |= IRQ_INPROGRESS; /* we are handling it */
- }
- desc->status = status;
-
- /*
- * If there is no IRQ handler or it was disabled, exit early.
- * Since we set PENDING, if another processor is handling
- * a different instance of this same irq, the other processor
- * will take care of it.
- */
- if (unlikely(!action))
- goto out;
-
- /*
- * Edge triggered interrupts need to remember
- * pending events.
- * This applies to any hw interrupts that allow a second
- * instance of the same irq to arrive while we are in do_IRQ
- * or in the handler. But the code here only handles the _second_
- * instance of the irq, not the third or fourth. So it is mostly
- * useful for irq hardware that does not mask cleanly in an
- * SMP environment.
- */
- for (;;) {
- irqreturn_t action_ret;
-
- raw_spin_unlock(&desc->lock);
-
- action_ret = handle_IRQ_event(irq, action);
- if (!noirqdebug)
- note_interrupt(irq, desc, action_ret);
-
- raw_spin_lock(&desc->lock);
- if (likely(!(desc->status & IRQ_PENDING)))
- break;
- desc->status &= ~IRQ_PENDING;
- }
- desc->status &= ~IRQ_INPROGRESS;
-
-out:
- /*
- * The ->end() handler has to deal with interrupts which got
- * disabled while the handler was running.
- */
- desc->irq_data.chip->end(irq);
- raw_spin_unlock(&desc->lock);
-
- return 1;
-}
-#endif
diff --git a/kernel/lockdep.c b/kernel/lockdep.c
index 42ba65d..0d2058d 100644
--- a/kernel/lockdep.c
+++ b/kernel/lockdep.c
@@ -2292,22 +2292,6 @@ mark_held_locks(struct task_struct *curr, enum mark_type mark)
}
/*
- * Debugging helper: via this flag we know that we are in
- * 'early bootup code', and will warn about any invalid irqs-on event:
- */
-static int early_boot_irqs_enabled;
-
-void early_boot_irqs_off(void)
-{
- early_boot_irqs_enabled = 0;
-}
-
-void early_boot_irqs_on(void)
-{
- early_boot_irqs_enabled = 1;
-}
-
-/*
* Hardirqs will be enabled:
*/
void trace_hardirqs_on_caller(unsigned long ip)
@@ -2319,7 +2303,7 @@ void trace_hardirqs_on_caller(unsigned long ip)
if (unlikely(!debug_locks || current->lockdep_recursion))
return;
- if (DEBUG_LOCKS_WARN_ON(unlikely(!early_boot_irqs_enabled)))
+ if (DEBUG_LOCKS_WARN_ON(unlikely(early_boot_irqs_disabled)))
return;
if (unlikely(curr->hardirqs_enabled)) {
diff --git a/kernel/panic.c b/kernel/panic.c
index 4c13b1a..991bb87 100644
--- a/kernel/panic.c
+++ b/kernel/panic.c
@@ -34,6 +34,7 @@ static int pause_on_oops_flag;
static DEFINE_SPINLOCK(pause_on_oops_lock);
int panic_timeout;
+EXPORT_SYMBOL_GPL(panic_timeout);
ATOMIC_NOTIFIER_HEAD(panic_notifier_list);
diff --git a/kernel/params.c b/kernel/params.c
index 08107d1..0da1411 100644
--- a/kernel/params.c
+++ b/kernel/params.c
@@ -719,9 +719,7 @@ void destroy_params(const struct kernel_param *params, unsigned num)
params[i].ops->free(params[i].arg);
}
-static void __init kernel_add_sysfs_param(const char *name,
- struct kernel_param *kparam,
- unsigned int name_skip)
+static struct module_kobject * __init locate_module_kobject(const char *name)
{
struct module_kobject *mk;
struct kobject *kobj;
@@ -729,10 +727,7 @@ static void __init kernel_add_sysfs_param(const char *name,
kobj = kset_find_obj(module_kset, name);
if (kobj) {
- /* We already have one. Remove params so we can add more. */
mk = to_module_kobject(kobj);
- /* We need to remove it before adding parameters. */
- sysfs_remove_group(&mk->kobj, &mk->mp->grp);
} else {
mk = kzalloc(sizeof(struct module_kobject), GFP_KERNEL);
BUG_ON(!mk);
@@ -743,15 +738,36 @@ static void __init kernel_add_sysfs_param(const char *name,
"%s", name);
if (err) {
kobject_put(&mk->kobj);
- printk(KERN_ERR "Module '%s' failed add to sysfs, "
- "error number %d\n", name, err);
- printk(KERN_ERR "The system will be unstable now.\n");
- return;
+ printk(KERN_ERR
+ "Module '%s' failed add to sysfs, error number %d\n",
+ name, err);
+ printk(KERN_ERR
+ "The system will be unstable now.\n");
+ return NULL;
}
- /* So that exit path is even. */
+
+ /* So that we hold reference in both cases. */
kobject_get(&mk->kobj);
}
+ return mk;
+}
+
+static void __init kernel_add_sysfs_param(const char *name,
+ struct kernel_param *kparam,
+ unsigned int name_skip)
+{
+ struct module_kobject *mk;
+ int err;
+
+ mk = locate_module_kobject(name);
+ if (!mk)
+ return;
+
+ /* We need to remove old parameters before adding more. */
+ if (mk->mp)
+ sysfs_remove_group(&mk->kobj, &mk->mp->grp);
+
/* These should not fail at boot. */
err = add_sysfs_param(mk, kparam, kparam->name + name_skip);
BUG_ON(err);
@@ -796,6 +812,32 @@ static void __init param_sysfs_builtin(void)
}
}
+ssize_t __modver_version_show(struct module_attribute *mattr,
+ struct module *mod, char *buf)
+{
+ struct module_version_attribute *vattr =
+ container_of(mattr, struct module_version_attribute, mattr);
+
+ return sprintf(buf, "%s\n", vattr->version);
+}
+
+extern struct module_version_attribute __start___modver[], __stop___modver[];
+
+static void __init version_sysfs_builtin(void)
+{
+ const struct module_version_attribute *vattr;
+ struct module_kobject *mk;
+ int err;
+
+ for (vattr = __start___modver; vattr < __stop___modver; vattr++) {
+ mk = locate_module_kobject(vattr->module_name);
+ if (mk) {
+ err = sysfs_create_file(&mk->kobj, &vattr->mattr.attr);
+ kobject_uevent(&mk->kobj, KOBJ_ADD);
+ kobject_put(&mk->kobj);
+ }
+ }
+}
/* module-related sysfs stuff */
@@ -875,6 +917,7 @@ static int __init param_sysfs_init(void)
}
module_sysfs_initialized = 1;
+ version_sysfs_builtin();
param_sysfs_builtin();
return 0;
diff --git a/kernel/perf_event.c b/kernel/perf_event.c
index 05ebe84..126a302 100644
--- a/kernel/perf_event.c
+++ b/kernel/perf_event.c
@@ -2201,13 +2201,6 @@ find_lively_task_by_vpid(pid_t vpid)
if (!task)
return ERR_PTR(-ESRCH);
- /*
- * Can't attach events to a dying task.
- */
- err = -ESRCH;
- if (task->flags & PF_EXITING)
- goto errout;
-
/* Reuse ptrace permission checks for now. */
err = -EACCES;
if (!ptrace_may_access(task, PTRACE_MODE_READ))
@@ -2228,14 +2221,11 @@ find_get_context(struct pmu *pmu, struct task_struct *task, int cpu)
unsigned long flags;
int ctxn, err;
- if (!task && cpu != -1) {
+ if (!task) {
/* Must be root to operate on a CPU event: */
if (perf_paranoid_cpu() && !capable(CAP_SYS_ADMIN))
return ERR_PTR(-EACCES);
- if (cpu < 0 || cpu >= nr_cpumask_bits)
- return ERR_PTR(-EINVAL);
-
/*
* We could be clever and allow to attach a event to an
* offline CPU and activate it when the CPU comes up, but
@@ -2271,14 +2261,27 @@ retry:
get_ctx(ctx);
- if (cmpxchg(&task->perf_event_ctxp[ctxn], NULL, ctx)) {
- /*
- * We raced with some other task; use
- * the context they set.
- */
+ err = 0;
+ mutex_lock(&task->perf_event_mutex);
+ /*
+ * If it has already passed perf_event_exit_task().
+ * we must see PF_EXITING, it takes this mutex too.
+ */
+ if (task->flags & PF_EXITING)
+ err = -ESRCH;
+ else if (task->perf_event_ctxp[ctxn])
+ err = -EAGAIN;
+ else
+ rcu_assign_pointer(task->perf_event_ctxp[ctxn], ctx);
+ mutex_unlock(&task->perf_event_mutex);
+
+ if (unlikely(err)) {
put_task_struct(task);
kfree(ctx);
- goto retry;
+
+ if (err == -EAGAIN)
+ goto retry;
+ goto errout;
}
}
@@ -5377,6 +5380,8 @@ free_dev:
goto out;
}
+static struct lock_class_key cpuctx_mutex;
+
int perf_pmu_register(struct pmu *pmu, char *name, int type)
{
int cpu, ret;
@@ -5425,6 +5430,7 @@ skip_type:
cpuctx = per_cpu_ptr(pmu->pmu_cpu_context, cpu);
__perf_event_init_context(&cpuctx->ctx);
+ lockdep_set_class(&cpuctx->ctx.mutex, &cpuctx_mutex);
cpuctx->ctx.type = cpu_context;
cpuctx->ctx.pmu = pmu;
cpuctx->jiffies_interval = 1;
@@ -5541,6 +5547,11 @@ perf_event_alloc(struct perf_event_attr *attr, int cpu,
struct hw_perf_event *hwc;
long err;
+ if ((unsigned)cpu >= nr_cpu_ids) {
+ if (!task || cpu != -1)
+ return ERR_PTR(-EINVAL);
+ }
+
event = kzalloc(sizeof(*event), GFP_KERNEL);
if (!event)
return ERR_PTR(-ENOMEM);
@@ -5589,7 +5600,7 @@ perf_event_alloc(struct perf_event_attr *attr, int cpu,
if (!overflow_handler && parent_event)
overflow_handler = parent_event->overflow_handler;
-
+
event->overflow_handler = overflow_handler;
if (attr->disabled)
@@ -6125,7 +6136,7 @@ static void perf_event_exit_task_context(struct task_struct *child, int ctxn)
* scheduled, so we are now safe from rescheduling changing
* our context.
*/
- child_ctx = child->perf_event_ctxp[ctxn];
+ child_ctx = rcu_dereference_raw(child->perf_event_ctxp[ctxn]);
task_ctx_sched_out(child_ctx, EVENT_ALL);
/*
@@ -6438,11 +6449,6 @@ int perf_event_init_context(struct task_struct *child, int ctxn)
unsigned long flags;
int ret = 0;
- child->perf_event_ctxp[ctxn] = NULL;
-
- mutex_init(&child->perf_event_mutex);
- INIT_LIST_HEAD(&child->perf_event_list);
-
if (likely(!parent->perf_event_ctxp[ctxn]))
return 0;
@@ -6494,7 +6500,6 @@ int perf_event_init_context(struct task_struct *child, int ctxn)
raw_spin_lock_irqsave(&parent_ctx->lock, flags);
parent_ctx->rotate_disable = 0;
- raw_spin_unlock_irqrestore(&parent_ctx->lock, flags);
child_ctx = child->perf_event_ctxp[ctxn];
@@ -6502,12 +6507,11 @@ int perf_event_init_context(struct task_struct *child, int ctxn)
/*
* Mark the child context as a clone of the parent
* context, or of whatever the parent is a clone of.
- * Note that if the parent is a clone, it could get
- * uncloned at any point, but that doesn't matter
- * because the list of events and the generation
- * count can't have changed since we took the mutex.
+ *
+ * Note that if the parent is a clone, the holding of
+ * parent_ctx->lock avoids it from being uncloned.
*/
- cloned_ctx = rcu_dereference(parent_ctx->parent_ctx);
+ cloned_ctx = parent_ctx->parent_ctx;
if (cloned_ctx) {
child_ctx->parent_ctx = cloned_ctx;
child_ctx->parent_gen = parent_ctx->parent_gen;
@@ -6518,6 +6522,7 @@ int perf_event_init_context(struct task_struct *child, int ctxn)
get_ctx(child_ctx->parent_ctx);
}
+ raw_spin_unlock_irqrestore(&parent_ctx->lock, flags);
mutex_unlock(&parent_ctx->mutex);
perf_unpin_context(parent_ctx);
@@ -6532,6 +6537,10 @@ int perf_event_init_task(struct task_struct *child)
{
int ctxn, ret;
+ memset(child->perf_event_ctxp, 0, sizeof(child->perf_event_ctxp));
+ mutex_init(&child->perf_event_mutex);
+ INIT_LIST_HEAD(&child->perf_event_list);
+
for_each_task_context_nr(ctxn) {
ret = perf_event_init_context(child, ctxn);
if (ret)
diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig
index a5aff3e..2657299 100644
--- a/kernel/power/Kconfig
+++ b/kernel/power/Kconfig
@@ -100,13 +100,9 @@ config PM_SLEEP_ADVANCED_DEBUG
depends on PM_ADVANCED_DEBUG
default n
-config SUSPEND_NVS
- bool
-
config SUSPEND
bool "Suspend to RAM and standby"
depends on PM && ARCH_SUSPEND_POSSIBLE
- select SUSPEND_NVS if HAS_IOMEM
default y
---help---
Allow the system to enter sleep states in which main memory is
@@ -140,7 +136,6 @@ config HIBERNATION
depends on PM && SWAP && ARCH_HIBERNATION_POSSIBLE
select LZO_COMPRESS
select LZO_DECOMPRESS
- select SUSPEND_NVS if HAS_IOMEM
---help---
Enable the suspend to disk (STD) functionality, which is usually
called "hibernation" in user interfaces. STD checkpoints the
diff --git a/kernel/power/Makefile b/kernel/power/Makefile
index b755972..c350e18 100644
--- a/kernel/power/Makefile
+++ b/kernel/power/Makefile
@@ -7,6 +7,5 @@ obj-$(CONFIG_SUSPEND) += suspend.o
obj-$(CONFIG_PM_TEST_SUSPEND) += suspend_test.o
obj-$(CONFIG_HIBERNATION) += hibernate.o snapshot.o swap.o user.o \
block_io.o
-obj-$(CONFIG_SUSPEND_NVS) += nvs.o
obj-$(CONFIG_MAGIC_SYSRQ) += poweroff.o
diff --git a/kernel/rcutiny.c b/kernel/rcutiny.c
index 0344937..0c343b9 100644
--- a/kernel/rcutiny.c
+++ b/kernel/rcutiny.c
@@ -189,7 +189,8 @@ static int rcu_kthread(void *arg)
unsigned long flags;
for (;;) {
- wait_event(rcu_kthread_wq, have_rcu_kthread_work != 0);
+ wait_event_interruptible(rcu_kthread_wq,
+ have_rcu_kthread_work != 0);
morework = rcu_boost();
local_irq_save(flags);
work = have_rcu_kthread_work;
diff --git a/kernel/sched.c b/kernel/sched.c
index ea3e5ef..18d38e4 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -553,9 +553,6 @@ struct rq {
/* try_to_wake_up() stats */
unsigned int ttwu_count;
unsigned int ttwu_local;
-
- /* BKL stats */
- unsigned int bkl_count;
#endif
};
@@ -609,6 +606,9 @@ static inline struct task_group *task_group(struct task_struct *p)
struct task_group *tg;
struct cgroup_subsys_state *css;
+ if (p->flags & PF_EXITING)
+ return &root_task_group;
+
css = task_subsys_state_check(p, cpu_cgroup_subsys_id,
lockdep_is_held(&task_rq(p)->lock));
tg = container_of(css, struct task_group, css);
@@ -3887,7 +3887,7 @@ static inline void schedule_debug(struct task_struct *prev)
schedstat_inc(this_rq(), sched_count);
#ifdef CONFIG_SCHEDSTATS
if (unlikely(prev->lock_depth >= 0)) {
- schedstat_inc(this_rq(), bkl_count);
+ schedstat_inc(this_rq(), rq_sched_info.bkl_count);
schedstat_inc(prev, sched_info.bkl_count);
}
#endif
@@ -4871,7 +4871,8 @@ recheck:
* assigned.
*/
if (rt_bandwidth_enabled() && rt_policy(policy) &&
- task_group(p)->rt_bandwidth.rt_runtime == 0) {
+ task_group(p)->rt_bandwidth.rt_runtime == 0 &&
+ !task_group_is_autogroup(task_group(p))) {
__task_rq_unlock(rq);
raw_spin_unlock_irqrestore(&p->pi_lock, flags);
return -EPERM;
@@ -8882,6 +8883,20 @@ cpu_cgroup_attach(struct cgroup_subsys *ss, struct cgroup *cgrp,
}
}
+static void
+cpu_cgroup_exit(struct cgroup_subsys *ss, struct task_struct *task)
+{
+ /*
+ * cgroup_exit() is called in the copy_process() failure path.
+ * Ignore this case since the task hasn't ran yet, this avoids
+ * trying to poke a half freed task state from generic code.
+ */
+ if (!(task->flags & PF_EXITING))
+ return;
+
+ sched_move_task(task);
+}
+
#ifdef CONFIG_FAIR_GROUP_SCHED
static int cpu_shares_write_u64(struct cgroup *cgrp, struct cftype *cftype,
u64 shareval)
@@ -8954,6 +8969,7 @@ struct cgroup_subsys cpu_cgroup_subsys = {
.destroy = cpu_cgroup_destroy,
.can_attach = cpu_cgroup_can_attach,
.attach = cpu_cgroup_attach,
+ .exit = cpu_cgroup_exit,
.populate = cpu_cgroup_populate,
.subsys_id = cpu_cgroup_subsys_id,
.early_init = 1,
diff --git a/kernel/sched_autogroup.c b/kernel/sched_autogroup.c
index 32a723b..9fb6562 100644
--- a/kernel/sched_autogroup.c
+++ b/kernel/sched_autogroup.c
@@ -27,6 +27,11 @@ static inline void autogroup_destroy(struct kref *kref)
{
struct autogroup *ag = container_of(kref, struct autogroup, kref);
+#ifdef CONFIG_RT_GROUP_SCHED
+ /* We've redirected RT tasks to the root task group... */
+ ag->tg->rt_se = NULL;
+ ag->tg->rt_rq = NULL;
+#endif
sched_destroy_group(ag->tg);
}
@@ -55,6 +60,10 @@ static inline struct autogroup *autogroup_task_get(struct task_struct *p)
return ag;
}
+#ifdef CONFIG_RT_GROUP_SCHED
+static void free_rt_sched_group(struct task_group *tg);
+#endif
+
static inline struct autogroup *autogroup_create(void)
{
struct autogroup *ag = kzalloc(sizeof(*ag), GFP_KERNEL);
@@ -72,6 +81,19 @@ static inline struct autogroup *autogroup_create(void)
init_rwsem(&ag->lock);
ag->id = atomic_inc_return(&autogroup_seq_nr);
ag->tg = tg;
+#ifdef CONFIG_RT_GROUP_SCHED
+ /*
+ * Autogroup RT tasks are redirected to the root task group
+ * so we don't have to move tasks around upon policy change,
+ * or flail around trying to allocate bandwidth on the fly.
+ * A bandwidth exception in __sched_setscheduler() allows
+ * the policy change to proceed. Thereafter, task_group()
+ * returns &root_task_group, so zero bandwidth is required.
+ */
+ free_rt_sched_group(tg);
+ tg->rt_se = root_task_group.rt_se;
+ tg->rt_rq = root_task_group.rt_rq;
+#endif
tg->autogroup = ag;
return ag;
@@ -106,6 +128,11 @@ task_wants_autogroup(struct task_struct *p, struct task_group *tg)
return true;
}
+static inline bool task_group_is_autogroup(struct task_group *tg)
+{
+ return tg != &root_task_group && tg->autogroup;
+}
+
static inline struct task_group *
autogroup_task_group(struct task_struct *p, struct task_group *tg)
{
@@ -231,6 +258,11 @@ void proc_sched_autogroup_show_task(struct task_struct *p, struct seq_file *m)
#ifdef CONFIG_SCHED_DEBUG
static inline int autogroup_path(struct task_group *tg, char *buf, int buflen)
{
+ int enabled = ACCESS_ONCE(sysctl_sched_autogroup_enabled);
+
+ if (!enabled || !tg->autogroup)
+ return 0;
+
return snprintf(buf, buflen, "%s-%ld", "/autogroup", tg->autogroup->id);
}
#endif /* CONFIG_SCHED_DEBUG */
diff --git a/kernel/sched_autogroup.h b/kernel/sched_autogroup.h
index 5358e24..7b859ff 100644
--- a/kernel/sched_autogroup.h
+++ b/kernel/sched_autogroup.h
@@ -15,6 +15,10 @@ autogroup_task_group(struct task_struct *p, struct task_group *tg);
static inline void autogroup_init(struct task_struct *init_task) { }
static inline void autogroup_free(struct task_group *tg) { }
+static inline bool task_group_is_autogroup(struct task_group *tg)
+{
+ return 0;
+}
static inline struct task_group *
autogroup_task_group(struct task_struct *p, struct task_group *tg)
diff --git a/kernel/sched_debug.c b/kernel/sched_debug.c
index 1dfae3d..eb6cb8e 100644
--- a/kernel/sched_debug.c
+++ b/kernel/sched_debug.c
@@ -16,6 +16,8 @@
#include <linux/kallsyms.h>
#include <linux/utsname.h>
+static DEFINE_SPINLOCK(sched_debug_lock);
+
/*
* This allows printing both to /proc/sched_debug and
* to the console
@@ -86,6 +88,26 @@ static void print_cfs_group_stats(struct seq_file *m, int cpu, struct task_group
}
#endif
+#ifdef CONFIG_CGROUP_SCHED
+static char group_path[PATH_MAX];
+
+static char *task_group_path(struct task_group *tg)
+{
+ if (autogroup_path(tg, group_path, PATH_MAX))
+ return group_path;
+
+ /*
+ * May be NULL if the underlying cgroup isn't fully-created yet
+ */
+ if (!tg->css.cgroup) {
+ group_path[0] = '\0';
+ return group_path;
+ }
+ cgroup_path(tg->css.cgroup, group_path, PATH_MAX);
+ return group_path;
+}
+#endif
+
static void
print_task(struct seq_file *m, struct rq *rq, struct task_struct *p)
{
@@ -108,6 +130,9 @@ print_task(struct seq_file *m, struct rq *rq, struct task_struct *p)
SEQ_printf(m, "%15Ld %15Ld %15Ld.%06ld %15Ld.%06ld %15Ld.%06ld",
0LL, 0LL, 0LL, 0L, 0LL, 0L, 0LL, 0L);
#endif
+#ifdef CONFIG_CGROUP_SCHED
+ SEQ_printf(m, " %s", task_group_path(task_group(p)));
+#endif
SEQ_printf(m, "\n");
}
@@ -144,7 +169,11 @@ void print_cfs_rq(struct seq_file *m, int cpu, struct cfs_rq *cfs_rq)
struct sched_entity *last;
unsigned long flags;
+#ifdef CONFIG_FAIR_GROUP_SCHED
+ SEQ_printf(m, "\ncfs_rq[%d]:%s\n", cpu, task_group_path(cfs_rq->tg));
+#else
SEQ_printf(m, "\ncfs_rq[%d]:\n", cpu);
+#endif
SEQ_printf(m, " .%-30s: %Ld.%06ld\n", "exec_clock",
SPLIT_NS(cfs_rq->exec_clock));
@@ -191,7 +220,11 @@ void print_cfs_rq(struct seq_file *m, int cpu, struct cfs_rq *cfs_rq)
void print_rt_rq(struct seq_file *m, int cpu, struct rt_rq *rt_rq)
{
+#ifdef CONFIG_RT_GROUP_SCHED
+ SEQ_printf(m, "\nrt_rq[%d]:%s\n", cpu, task_group_path(rt_rq->tg));
+#else
SEQ_printf(m, "\nrt_rq[%d]:\n", cpu);
+#endif
#define P(x) \
SEQ_printf(m, " .%-30s: %Ld\n", #x, (long long)(rt_rq->x))
@@ -212,6 +245,7 @@ extern __read_mostly int sched_clock_running;
static void print_cpu(struct seq_file *m, int cpu)
{
struct rq *rq = cpu_rq(cpu);
+ unsigned long flags;
#ifdef CONFIG_X86
{
@@ -262,14 +296,20 @@ static void print_cpu(struct seq_file *m, int cpu)
P(ttwu_count);
P(ttwu_local);
- P(bkl_count);
+ SEQ_printf(m, " .%-30s: %d\n", "bkl_count",
+ rq->rq_sched_info.bkl_count);
#undef P
+#undef P64
#endif
+ spin_lock_irqsave(&sched_debug_lock, flags);
print_cfs_stats(m, cpu);
print_rt_stats(m, cpu);
+ rcu_read_lock();
print_rq(m, rq, cpu);
+ rcu_read_unlock();
+ spin_unlock_irqrestore(&sched_debug_lock, flags);
}
static const char *sched_tunable_scaling_names[] = {
diff --git a/kernel/sched_fair.c b/kernel/sched_fair.c
index c62ebae..3547699 100644
--- a/kernel/sched_fair.c
+++ b/kernel/sched_fair.c
@@ -699,7 +699,8 @@ account_entity_dequeue(struct cfs_rq *cfs_rq, struct sched_entity *se)
cfs_rq->nr_running--;
}
-#if defined CONFIG_SMP && defined CONFIG_FAIR_GROUP_SCHED
+#ifdef CONFIG_FAIR_GROUP_SCHED
+# ifdef CONFIG_SMP
static void update_cfs_rq_load_contribution(struct cfs_rq *cfs_rq,
int global_update)
{
@@ -762,6 +763,51 @@ static void update_cfs_load(struct cfs_rq *cfs_rq, int global_update)
list_del_leaf_cfs_rq(cfs_rq);
}
+static long calc_cfs_shares(struct cfs_rq *cfs_rq, struct task_group *tg,
+ long weight_delta)
+{
+ long load_weight, load, shares;
+
+ load = cfs_rq->load.weight + weight_delta;
+
+ load_weight = atomic_read(&tg->load_weight);
+ load_weight -= cfs_rq->load_contribution;
+ load_weight += load;
+
+ shares = (tg->shares * load);
+ if (load_weight)
+ shares /= load_weight;
+
+ if (shares < MIN_SHARES)
+ shares = MIN_SHARES;
+ if (shares > tg->shares)
+ shares = tg->shares;
+
+ return shares;
+}
+
+static void update_entity_shares_tick(struct cfs_rq *cfs_rq)
+{
+ if (cfs_rq->load_unacc_exec_time > sysctl_sched_shares_window) {
+ update_cfs_load(cfs_rq, 0);
+ update_cfs_shares(cfs_rq, 0);
+ }
+}
+# else /* CONFIG_SMP */
+static void update_cfs_load(struct cfs_rq *cfs_rq, int global_update)
+{
+}
+
+static inline long calc_cfs_shares(struct cfs_rq *cfs_rq, struct task_group *tg,
+ long weight_delta)
+{
+ return tg->shares;
+}
+
+static inline void update_entity_shares_tick(struct cfs_rq *cfs_rq)
+{
+}
+# endif /* CONFIG_SMP */
static void reweight_entity(struct cfs_rq *cfs_rq, struct sched_entity *se,
unsigned long weight)
{
@@ -782,7 +828,7 @@ static void update_cfs_shares(struct cfs_rq *cfs_rq, long weight_delta)
{
struct task_group *tg;
struct sched_entity *se;
- long load_weight, load, shares;
+ long shares;
if (!cfs_rq)
return;
@@ -791,32 +837,14 @@ static void update_cfs_shares(struct cfs_rq *cfs_rq, long weight_delta)
se = tg->se[cpu_of(rq_of(cfs_rq))];
if (!se)
return;
-
- load = cfs_rq->load.weight + weight_delta;
-
- load_weight = atomic_read(&tg->load_weight);
- load_weight -= cfs_rq->load_contribution;
- load_weight += load;
-
- shares = (tg->shares * load);
- if (load_weight)
- shares /= load_weight;
-
- if (shares < MIN_SHARES)
- shares = MIN_SHARES;
- if (shares > tg->shares)
- shares = tg->shares;
+#ifndef CONFIG_SMP
+ if (likely(se->load.weight == tg->shares))
+ return;
+#endif
+ shares = calc_cfs_shares(cfs_rq, tg, weight_delta);
reweight_entity(cfs_rq_of(se), se, shares);
}
-
-static void update_entity_shares_tick(struct cfs_rq *cfs_rq)
-{
- if (cfs_rq->load_unacc_exec_time > sysctl_sched_shares_window) {
- update_cfs_load(cfs_rq, 0);
- update_cfs_shares(cfs_rq, 0);
- }
-}
#else /* CONFIG_FAIR_GROUP_SCHED */
static void update_cfs_load(struct cfs_rq *cfs_rq, int global_update)
{
@@ -1062,6 +1090,9 @@ check_preempt_tick(struct cfs_rq *cfs_rq, struct sched_entity *curr)
struct sched_entity *se = __pick_next_entity(cfs_rq);
s64 delta = curr->vruntime - se->vruntime;
+ if (delta < 0)
+ return;
+
if (delta > ideal_runtime)
resched_task(rq_of(cfs_rq)->curr);
}
@@ -1362,27 +1393,27 @@ static long effective_load(struct task_group *tg, int cpu, long wl, long wg)
return wl;
for_each_sched_entity(se) {
- long S, rw, s, a, b;
+ long lw, w;
- S = se->my_q->tg->shares;
- s = se->load.weight;
- rw = se->my_q->load.weight;
+ tg = se->my_q->tg;
+ w = se->my_q->load.weight;
- a = S*(rw + wl);
- b = S*rw + s*wg;
+ /* use this cpu's instantaneous contribution */
+ lw = atomic_read(&tg->load_weight);
+ lw -= se->my_q->load_contribution;
+ lw += w + wg;
- wl = s*(a-b);
+ wl += w;
- if (likely(b))
- wl /= b;
+ if (lw > 0 && wl < lw)
+ wl = (wl * tg->shares) / lw;
+ else
+ wl = tg->shares;
- /*
- * Assume the group is already running and will
- * thus already be accounted for in the weight.
- *
- * That is, moving shares between CPUs, does not
- * alter the group weight.
- */
+ /* zero point is MIN_SHARES */
+ if (wl < MIN_SHARES)
+ wl = MIN_SHARES;
+ wl -= se->load.weight;
wg = 0;
}
diff --git a/kernel/smp.c b/kernel/smp.c
index 4ec30e0..9910744 100644
--- a/kernel/smp.c
+++ b/kernel/smp.c
@@ -194,23 +194,52 @@ void generic_smp_call_function_interrupt(void)
*/
list_for_each_entry_rcu(data, &call_function.queue, csd.list) {
int refs;
+ void (*func) (void *info);
- if (!cpumask_test_and_clear_cpu(cpu, data->cpumask))
+ /*
+ * Since we walk the list without any locks, we might
+ * see an entry that was completed, removed from the
+ * list and is in the process of being reused.
+ *
+ * We must check that the cpu is in the cpumask before
+ * checking the refs, and both must be set before
+ * executing the callback on this cpu.
+ */
+
+ if (!cpumask_test_cpu(cpu, data->cpumask))
+ continue;
+
+ smp_rmb();
+
+ if (atomic_read(&data->refs) == 0)
continue;
+ func = data->csd.func; /* for later warn */
data->csd.func(data->csd.info);
+ /*
+ * If the cpu mask is not still set then it enabled interrupts,
+ * we took another smp interrupt, and executed the function
+ * twice on this cpu. In theory that copy decremented refs.
+ */
+ if (!cpumask_test_and_clear_cpu(cpu, data->cpumask)) {
+ WARN(1, "%pS enabled interrupts and double executed\n",
+ func);
+ continue;
+ }
+
refs = atomic_dec_return(&data->refs);
WARN_ON(refs < 0);
- if (!refs) {
- raw_spin_lock(&call_function.lock);
- list_del_rcu(&data->csd.list);
- raw_spin_unlock(&call_function.lock);
- }
if (refs)
continue;
+ WARN_ON(!cpumask_empty(data->cpumask));
+
+ raw_spin_lock(&call_function.lock);
+ list_del_rcu(&data->csd.list);
+ raw_spin_unlock(&call_function.lock);
+
csd_unlock(&data->csd);
}
@@ -430,7 +459,7 @@ void smp_call_function_many(const struct cpumask *mask,
* can't happen.
*/
WARN_ON_ONCE(cpu_online(this_cpu) && irqs_disabled()
- && !oops_in_progress);
+ && !oops_in_progress && !early_boot_irqs_disabled);
/* So, what's a CPU they want? Ignoring this one. */
cpu = cpumask_first_and(mask, cpu_online_mask);
@@ -454,11 +483,21 @@ void smp_call_function_many(const struct cpumask *mask,
data = &__get_cpu_var(cfd_data);
csd_lock(&data->csd);
+ BUG_ON(atomic_read(&data->refs) || !cpumask_empty(data->cpumask));
data->csd.func = func;
data->csd.info = info;
cpumask_and(data->cpumask, mask, cpu_online_mask);
cpumask_clear_cpu(this_cpu, data->cpumask);
+
+ /*
+ * To ensure the interrupt handler gets an complete view
+ * we order the cpumask and refs writes and order the read
+ * of them in the interrupt handler. In addition we may
+ * only clear our own cpu bit from the mask.
+ */
+ smp_wmb();
+
atomic_set(&data->refs, cpumask_weight(data->cpumask));
raw_spin_lock_irqsave(&call_function.lock, flags);
@@ -533,17 +572,20 @@ void ipi_call_unlock_irq(void)
#endif /* USE_GENERIC_SMP_HELPERS */
/*
- * Call a function on all processors
+ * Call a function on all processors. May be used during early boot while
+ * early_boot_irqs_disabled is set. Use local_irq_save/restore() instead
+ * of local_irq_disable/enable().
*/
int on_each_cpu(void (*func) (void *info), void *info, int wait)
{
+ unsigned long flags;
int ret = 0;
preempt_disable();
ret = smp_call_function(func, info, wait);
- local_irq_disable();
+ local_irq_save(flags);
func(info);
- local_irq_enable();
+ local_irq_restore(flags);
preempt_enable();
return ret;
}
diff --git a/kernel/srcu.c b/kernel/srcu.c
index 98d8c1e..73ce23f 100644
--- a/kernel/srcu.c
+++ b/kernel/srcu.c
@@ -156,6 +156,16 @@ void __srcu_read_unlock(struct srcu_struct *sp, int idx)
EXPORT_SYMBOL_GPL(__srcu_read_unlock);
/*
+ * We use an adaptive strategy for synchronize_srcu() and especially for
+ * synchronize_srcu_expedited(). We spin for a fixed time period
+ * (defined below) to allow SRCU readers to exit their read-side critical
+ * sections. If there are still some readers after 10 microseconds,
+ * we repeatedly block for 1-millisecond time periods. This approach
+ * has done well in testing, so there is no need for a config parameter.
+ */
+#define SYNCHRONIZE_SRCU_READER_DELAY 10
+
+/*
* Helper function for synchronize_srcu() and synchronize_srcu_expedited().
*/
static void __synchronize_srcu(struct srcu_struct *sp, void (*sync_func)(void))
@@ -207,11 +217,12 @@ static void __synchronize_srcu(struct srcu_struct *sp, void (*sync_func)(void))
* will have finished executing. We initially give readers
* an arbitrarily chosen 10 microseconds to get out of their
* SRCU read-side critical sections, then loop waiting 1/HZ
- * seconds per iteration.
+ * seconds per iteration. The 10-microsecond value has done
+ * very well in testing.
*/
if (srcu_readers_active_idx(sp, idx))
- udelay(CONFIG_SRCU_SYNCHRONIZE_DELAY);
+ udelay(SYNCHRONIZE_SRCU_READER_DELAY);
while (srcu_readers_active_idx(sp, idx))
schedule_timeout_interruptible(1);
diff --git a/kernel/time/clocksource.c b/kernel/time/clocksource.c
index c50a034..6519cf6 100644
--- a/kernel/time/clocksource.c
+++ b/kernel/time/clocksource.c
@@ -113,7 +113,7 @@ EXPORT_SYMBOL_GPL(timecounter_cyc2time);
* @shift: pointer to shift variable
* @from: frequency to convert from
* @to: frequency to convert to
- * @minsec: guaranteed runtime conversion range in seconds
+ * @maxsec: guaranteed runtime conversion range in seconds
*
* The function evaluates the shift/mult pair for the scaled math
* operations of clocksources and clockevents.
@@ -122,7 +122,7 @@ EXPORT_SYMBOL_GPL(timecounter_cyc2time);
* NSEC_PER_SEC == 1GHz and @from is the counter frequency. For clock
* event @to is the counter frequency and @from is NSEC_PER_SEC.
*
- * The @minsec conversion range argument controls the time frame in
+ * The @maxsec conversion range argument controls the time frame in
* seconds which must be covered by the runtime conversion with the
* calculated mult and shift factors. This guarantees that no 64bit
* overflow happens when the input value of the conversion is
@@ -131,7 +131,7 @@ EXPORT_SYMBOL_GPL(timecounter_cyc2time);
* factors.
*/
void
-clocks_calc_mult_shift(u32 *mult, u32 *shift, u32 from, u32 to, u32 minsec)
+clocks_calc_mult_shift(u32 *mult, u32 *shift, u32 from, u32 to, u32 maxsec)
{
u64 tmp;
u32 sft, sftacc= 32;
@@ -140,7 +140,7 @@ clocks_calc_mult_shift(u32 *mult, u32 *shift, u32 from, u32 to, u32 minsec)
* Calculate the shift factor which is limiting the conversion
* range:
*/
- tmp = ((u64)minsec * from) >> 32;
+ tmp = ((u64)maxsec * from) >> 32;
while (tmp) {
tmp >>=1;
sftacc--;
diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c
index 3e216e0..c55ea24 100644
--- a/kernel/time/tick-sched.c
+++ b/kernel/time/tick-sched.c
@@ -642,8 +642,7 @@ static void tick_nohz_switch_to_nohz(void)
}
local_irq_enable();
- printk(KERN_INFO "Switched to NOHz mode on CPU #%d\n",
- smp_processor_id());
+ printk(KERN_INFO "Switched to NOHz mode on CPU #%d\n", smp_processor_id());
}
/*
@@ -795,8 +794,10 @@ void tick_setup_sched_timer(void)
}
#ifdef CONFIG_NO_HZ
- if (tick_nohz_enabled)
+ if (tick_nohz_enabled) {
ts->nohz_mode = NOHZ_MODE_HIGHRES;
+ printk(KERN_INFO "Switched to NOHz mode on CPU #%d\n", smp_processor_id());
+ }
#endif
}
#endif /* HIGH_RES_TIMERS */
diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c
index 5536aaf..d27c756 100644
--- a/kernel/time/timekeeping.c
+++ b/kernel/time/timekeeping.c
@@ -49,7 +49,7 @@ struct timekeeper {
u32 mult;
};
-struct timekeeper timekeeper;
+static struct timekeeper timekeeper;
/**
* timekeeper_setup_internals - Set up internals to use clocksource clock.
@@ -164,7 +164,7 @@ static struct timespec total_sleep_time;
/*
* The raw monotonic time for the CLOCK_MONOTONIC_RAW posix clock.
*/
-struct timespec raw_time;
+static struct timespec raw_time;
/* flag for if timekeeping is suspended */
int __read_mostly timekeeping_suspended;
diff --git a/kernel/trace/trace_irqsoff.c b/kernel/trace/trace_irqsoff.c
index 5cf8c60..92b6e1e 100644
--- a/kernel/trace/trace_irqsoff.c
+++ b/kernel/trace/trace_irqsoff.c
@@ -453,14 +453,6 @@ void time_hardirqs_off(unsigned long a0, unsigned long a1)
* Stubs:
*/
-void early_boot_irqs_off(void)
-{
-}
-
-void early_boot_irqs_on(void)
-{
-}
-
void trace_softirqs_on(unsigned long ip)
{
}
diff --git a/kernel/trace/trace_syscalls.c b/kernel/trace/trace_syscalls.c
index bac752f..b706529 100644
--- a/kernel/trace/trace_syscalls.c
+++ b/kernel/trace/trace_syscalls.c
@@ -23,9 +23,6 @@ static int syscall_exit_register(struct ftrace_event_call *event,
static int syscall_enter_define_fields(struct ftrace_event_call *call);
static int syscall_exit_define_fields(struct ftrace_event_call *call);
-/* All syscall exit events have the same fields */
-static LIST_HEAD(syscall_exit_fields);
-
static struct list_head *
syscall_get_enter_fields(struct ftrace_event_call *call)
{
@@ -34,34 +31,28 @@ syscall_get_enter_fields(struct ftrace_event_call *call)
return &entry->enter_fields;
}
-static struct list_head *
-syscall_get_exit_fields(struct ftrace_event_call *call)
-{
- return &syscall_exit_fields;
-}
-
struct trace_event_functions enter_syscall_print_funcs = {
- .trace = print_syscall_enter,
+ .trace = print_syscall_enter,
};
struct trace_event_functions exit_syscall_print_funcs = {
- .trace = print_syscall_exit,
+ .trace = print_syscall_exit,
};
struct ftrace_event_class event_class_syscall_enter = {
- .system = "syscalls",
- .reg = syscall_enter_register,
- .define_fields = syscall_enter_define_fields,
- .get_fields = syscall_get_enter_fields,
- .raw_init = init_syscall_trace,
+ .system = "syscalls",
+ .reg = syscall_enter_register,
+ .define_fields = syscall_enter_define_fields,
+ .get_fields = syscall_get_enter_fields,
+ .raw_init = init_syscall_trace,
};
struct ftrace_event_class event_class_syscall_exit = {
- .system = "syscalls",
- .reg = syscall_exit_register,
- .define_fields = syscall_exit_define_fields,
- .get_fields = syscall_get_exit_fields,
- .raw_init = init_syscall_trace,
+ .system = "syscalls",
+ .reg = syscall_exit_register,
+ .define_fields = syscall_exit_define_fields,
+ .fields = LIST_HEAD_INIT(event_class_syscall_exit.fields),
+ .raw_init = init_syscall_trace,
};
extern unsigned long __start_syscalls_metadata[];
diff --git a/kernel/workqueue.c b/kernel/workqueue.c
index 8ee6ec8..11869fa 100644
--- a/kernel/workqueue.c
+++ b/kernel/workqueue.c
@@ -768,7 +768,11 @@ static inline void worker_clr_flags(struct worker *worker, unsigned int flags)
worker->flags &= ~flags;
- /* if transitioning out of NOT_RUNNING, increment nr_running */
+ /*
+ * If transitioning out of NOT_RUNNING, increment nr_running. Note
+ * that the nested NOT_RUNNING is not a noop. NOT_RUNNING is mask
+ * of multiple flags, not a single flag.
+ */
if ((flags & WORKER_NOT_RUNNING) && (oflags & WORKER_NOT_RUNNING))
if (!(worker->flags & WORKER_NOT_RUNNING))
atomic_inc(get_gcwq_nr_running(gcwq->cpu));
@@ -1840,7 +1844,7 @@ __acquires(&gcwq->lock)
spin_unlock_irq(&gcwq->lock);
work_clear_pending(work);
- lock_map_acquire(&cwq->wq->lockdep_map);
+ lock_map_acquire_read(&cwq->wq->lockdep_map);
lock_map_acquire(&lockdep_map);
trace_workqueue_execute_start(work);
f(work);
@@ -2384,8 +2388,18 @@ static bool start_flush_work(struct work_struct *work, struct wq_barrier *barr,
insert_wq_barrier(cwq, barr, work, worker);
spin_unlock_irq(&gcwq->lock);
- lock_map_acquire(&cwq->wq->lockdep_map);
+ /*
+ * If @max_active is 1 or rescuer is in use, flushing another work
+ * item on the same workqueue may lead to deadlock. Make sure the
+ * flusher is not running on the same workqueue by verifying write
+ * access.
+ */
+ if (cwq->wq->saved_max_active == 1 || cwq->wq->flags & WQ_RESCUER)
+ lock_map_acquire(&cwq->wq->lockdep_map);
+ else
+ lock_map_acquire_read(&cwq->wq->lockdep_map);
lock_map_release(&cwq->wq->lockdep_map);
+
return true;
already_gone:
spin_unlock_irq(&gcwq->lock);
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index 2d05adb..3967c235 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -657,7 +657,7 @@ config DEBUG_HIGHMEM
Disable for production systems.
config DEBUG_BUGVERBOSE
- bool "Verbose BUG() reporting (adds 70K)" if DEBUG_KERNEL && EMBEDDED
+ bool "Verbose BUG() reporting (adds 70K)" if DEBUG_KERNEL && EXPERT
depends on BUG
depends on ARM || AVR32 || M32R || M68K || SPARC32 || SPARC64 || \
FRV || SUPERH || GENERIC_BUG || BLACKFIN || MN10300
@@ -729,8 +729,8 @@ config DEBUG_WRITECOUNT
If unsure, say N.
config DEBUG_MEMORY_INIT
- bool "Debug memory initialisation" if EMBEDDED
- default !EMBEDDED
+ bool "Debug memory initialisation" if EXPERT
+ default !EXPERT
help
Enable this for additional checks during memory initialisation.
The sanity checks verify aspects of the VM such as the memory model
diff --git a/lib/ioremap.c b/lib/ioremap.c
index 5730ecd..da4e2ad 100644
--- a/lib/ioremap.c
+++ b/lib/ioremap.c
@@ -9,6 +9,7 @@
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/io.h>
+#include <linux/module.h>
#include <asm/cacheflush.h>
#include <asm/pgtable.h>
@@ -90,3 +91,4 @@ int ioremap_page_range(unsigned long addr,
return err;
}
+EXPORT_SYMBOL_GPL(ioremap_page_range);
diff --git a/lib/xz/Kconfig b/lib/xz/Kconfig
index e3b6e18..60a6088 100644
--- a/lib/xz/Kconfig
+++ b/lib/xz/Kconfig
@@ -7,37 +7,37 @@ config XZ_DEC
CRC32 is supported. See Documentation/xz.txt for more information.
config XZ_DEC_X86
- bool "x86 BCJ filter decoder" if EMBEDDED
+ bool "x86 BCJ filter decoder" if EXPERT
default y
depends on XZ_DEC
select XZ_DEC_BCJ
config XZ_DEC_POWERPC
- bool "PowerPC BCJ filter decoder" if EMBEDDED
+ bool "PowerPC BCJ filter decoder" if EXPERT
default y
depends on XZ_DEC
select XZ_DEC_BCJ
config XZ_DEC_IA64
- bool "IA-64 BCJ filter decoder" if EMBEDDED
+ bool "IA-64 BCJ filter decoder" if EXPERT
default y
depends on XZ_DEC
select XZ_DEC_BCJ
config XZ_DEC_ARM
- bool "ARM BCJ filter decoder" if EMBEDDED
+ bool "ARM BCJ filter decoder" if EXPERT
default y
depends on XZ_DEC
select XZ_DEC_BCJ
config XZ_DEC_ARMTHUMB
- bool "ARM-Thumb BCJ filter decoder" if EMBEDDED
+ bool "ARM-Thumb BCJ filter decoder" if EXPERT
default y
depends on XZ_DEC
select XZ_DEC_BCJ
config XZ_DEC_SPARC
- bool "SPARC BCJ filter decoder" if EMBEDDED
+ bool "SPARC BCJ filter decoder" if EXPERT
default y
depends on XZ_DEC
select XZ_DEC_BCJ
diff --git a/mm/compaction.c b/mm/compaction.c
index 6d592a0..8be430b 100644
--- a/mm/compaction.c
+++ b/mm/compaction.c
@@ -406,6 +406,10 @@ static int compact_finished(struct zone *zone,
if (!zone_watermark_ok(zone, cc->order, watermark, 0, 0))
return COMPACT_CONTINUE;
+ /*
+ * order == -1 is expected when compacting via
+ * /proc/sys/vm/compact_memory
+ */
if (cc->order == -1)
return COMPACT_CONTINUE;
@@ -454,6 +458,13 @@ unsigned long compaction_suitable(struct zone *zone, int order)
return COMPACT_SKIPPED;
/*
+ * order == -1 is expected when compacting via
+ * /proc/sys/vm/compact_memory
+ */
+ if (order == -1)
+ return COMPACT_CONTINUE;
+
+ /*
* fragmentation index determines if allocation failures are due to
* low memory or external fragmentation
*
diff --git a/mm/huge_memory.c b/mm/huge_memory.c
index 004c9c2..e187454 100644
--- a/mm/huge_memory.c
+++ b/mm/huge_memory.c
@@ -1203,6 +1203,8 @@ static void __split_huge_page_refcount(struct page *page)
BUG_ON(!PageDirty(page_tail));
BUG_ON(!PageSwapBacked(page_tail));
+ mem_cgroup_split_huge_fixup(page, page_tail);
+
lru_add_page_tail(zone, page, page_tail);
}
@@ -1837,9 +1839,9 @@ static void collapse_huge_page(struct mm_struct *mm,
spin_lock(ptl);
isolated = __collapse_huge_page_isolate(vma, address, pte);
spin_unlock(ptl);
- pte_unmap(pte);
if (unlikely(!isolated)) {
+ pte_unmap(pte);
spin_lock(&mm->page_table_lock);
BUG_ON(!pmd_none(*pmd));
set_pmd_at(mm, address, pmd, _pmd);
@@ -1856,6 +1858,7 @@ static void collapse_huge_page(struct mm_struct *mm,
anon_vma_unlock(vma->anon_vma);
__collapse_huge_page_copy(pte, new_page, vma, address, ptl);
+ pte_unmap(pte);
__SetPageUptodate(new_page);
pgtable = pmd_pgtable(_pmd);
VM_BUG_ON(page_count(pgtable) != 1);
diff --git a/mm/internal.h b/mm/internal.h
index 4c98630..6948820 100644
--- a/mm/internal.h
+++ b/mm/internal.h
@@ -39,15 +39,6 @@ static inline void __put_page(struct page *page)
extern unsigned long highest_memmap_pfn;
-#ifdef CONFIG_SMP
-extern int putback_active_lru_page(struct zone *zone, struct page *page);
-#else
-static inline int putback_active_lru_page(struct zone *zone, struct page *page)
-{
- return 0;
-}
-#endif
-
/*
* in mm/vmscan.c:
*/
diff --git a/mm/memblock.c b/mm/memblock.c
index 400dc62..bdba245 100644
--- a/mm/memblock.c
+++ b/mm/memblock.c
@@ -683,13 +683,13 @@ int __init_memblock memblock_is_memory(phys_addr_t addr)
int __init_memblock memblock_is_region_memory(phys_addr_t base, phys_addr_t size)
{
- int idx = memblock_search(&memblock.reserved, base);
+ int idx = memblock_search(&memblock.memory, base);
if (idx == -1)
return 0;
- return memblock.reserved.regions[idx].base <= base &&
- (memblock.reserved.regions[idx].base +
- memblock.reserved.regions[idx].size) >= (base + size);
+ return memblock.memory.regions[idx].base <= base &&
+ (memblock.memory.regions[idx].base +
+ memblock.memory.regions[idx].size) >= (base + size);
}
int __init_memblock memblock_is_region_reserved(phys_addr_t base, phys_addr_t size)
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index 8ab8410..db76ef7 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -600,23 +600,22 @@ static void mem_cgroup_swap_statistics(struct mem_cgroup *mem,
}
static void mem_cgroup_charge_statistics(struct mem_cgroup *mem,
- struct page_cgroup *pc,
- bool charge)
+ bool file, int nr_pages)
{
- int val = (charge) ? 1 : -1;
-
preempt_disable();
- if (PageCgroupCache(pc))
- __this_cpu_add(mem->stat->count[MEM_CGROUP_STAT_CACHE], val);
+ if (file)
+ __this_cpu_add(mem->stat->count[MEM_CGROUP_STAT_CACHE], nr_pages);
else
- __this_cpu_add(mem->stat->count[MEM_CGROUP_STAT_RSS], val);
+ __this_cpu_add(mem->stat->count[MEM_CGROUP_STAT_RSS], nr_pages);
- if (charge)
+ /* pagein of a big page is an event. So, ignore page size */
+ if (nr_pages > 0)
__this_cpu_inc(mem->stat->count[MEM_CGROUP_STAT_PGPGIN_COUNT]);
else
__this_cpu_inc(mem->stat->count[MEM_CGROUP_STAT_PGPGOUT_COUNT]);
- __this_cpu_inc(mem->stat->count[MEM_CGROUP_EVENTS]);
+
+ __this_cpu_add(mem->stat->count[MEM_CGROUP_EVENTS], nr_pages);
preempt_enable();
}
@@ -815,7 +814,8 @@ void mem_cgroup_del_lru_list(struct page *page, enum lru_list lru)
* removed from global LRU.
*/
mz = page_cgroup_zoneinfo(pc);
- MEM_CGROUP_ZSTAT(mz, lru) -= 1;
+ /* huge page split is done under lru_lock. so, we have no races. */
+ MEM_CGROUP_ZSTAT(mz, lru) -= 1 << compound_order(page);
if (mem_cgroup_is_root(pc->mem_cgroup))
return;
VM_BUG_ON(list_empty(&pc->lru));
@@ -836,13 +836,12 @@ void mem_cgroup_rotate_lru_list(struct page *page, enum lru_list lru)
return;
pc = lookup_page_cgroup(page);
- /*
- * Used bit is set without atomic ops but after smp_wmb().
- * For making pc->mem_cgroup visible, insert smp_rmb() here.
- */
- smp_rmb();
/* unused or root page is not rotated. */
- if (!PageCgroupUsed(pc) || mem_cgroup_is_root(pc->mem_cgroup))
+ if (!PageCgroupUsed(pc))
+ return;
+ /* Ensure pc->mem_cgroup is visible after reading PCG_USED. */
+ smp_rmb();
+ if (mem_cgroup_is_root(pc->mem_cgroup))
return;
mz = page_cgroup_zoneinfo(pc);
list_move(&pc->lru, &mz->lists[lru]);
@@ -857,16 +856,13 @@ void mem_cgroup_add_lru_list(struct page *page, enum lru_list lru)
return;
pc = lookup_page_cgroup(page);
VM_BUG_ON(PageCgroupAcctLRU(pc));
- /*
- * Used bit is set without atomic ops but after smp_wmb().
- * For making pc->mem_cgroup visible, insert smp_rmb() here.
- */
- smp_rmb();
if (!PageCgroupUsed(pc))
return;
-
+ /* Ensure pc->mem_cgroup is visible after reading PCG_USED. */
+ smp_rmb();
mz = page_cgroup_zoneinfo(pc);
- MEM_CGROUP_ZSTAT(mz, lru) += 1;
+ /* huge page split is done under lru_lock. so, we have no races. */
+ MEM_CGROUP_ZSTAT(mz, lru) += 1 << compound_order(page);
SetPageCgroupAcctLRU(pc);
if (mem_cgroup_is_root(pc->mem_cgroup))
return;
@@ -1030,14 +1026,10 @@ mem_cgroup_get_reclaim_stat_from_page(struct page *page)
return NULL;
pc = lookup_page_cgroup(page);
- /*
- * Used bit is set without atomic ops but after smp_wmb().
- * For making pc->mem_cgroup visible, insert smp_rmb() here.
- */
- smp_rmb();
if (!PageCgroupUsed(pc))
return NULL;
-
+ /* Ensure pc->mem_cgroup is visible after reading PCG_USED. */
+ smp_rmb();
mz = page_cgroup_zoneinfo(pc);
if (!mz)
return NULL;
@@ -1615,7 +1607,7 @@ void mem_cgroup_update_page_stat(struct page *page,
if (unlikely(!mem || !PageCgroupUsed(pc)))
goto out;
/* pc->mem_cgroup is unstable ? */
- if (unlikely(mem_cgroup_stealed(mem))) {
+ if (unlikely(mem_cgroup_stealed(mem)) || PageTransHuge(page)) {
/* take a lock against to access pc->mem_cgroup */
move_lock_page_cgroup(pc, &flags);
need_unlock = true;
@@ -2084,14 +2076,27 @@ struct mem_cgroup *try_get_mem_cgroup_from_page(struct page *page)
return mem;
}
-/*
- * commit a charge got by __mem_cgroup_try_charge() and makes page_cgroup to be
- * USED state. If already USED, uncharge and return.
- */
-static void ____mem_cgroup_commit_charge(struct mem_cgroup *mem,
- struct page_cgroup *pc,
- enum charge_type ctype)
+static void __mem_cgroup_commit_charge(struct mem_cgroup *mem,
+ struct page_cgroup *pc,
+ enum charge_type ctype,
+ int page_size)
{
+ int nr_pages = page_size >> PAGE_SHIFT;
+
+ /* try_charge() can return NULL to *memcg, taking care of it. */
+ if (!mem)
+ return;
+
+ lock_page_cgroup(pc);
+ if (unlikely(PageCgroupUsed(pc))) {
+ unlock_page_cgroup(pc);
+ mem_cgroup_cancel_charge(mem, page_size);
+ return;
+ }
+ /*
+ * we don't need page_cgroup_lock about tail pages, becase they are not
+ * accessed by any other context at this point.
+ */
pc->mem_cgroup = mem;
/*
* We access a page_cgroup asynchronously without lock_page_cgroup().
@@ -2115,35 +2120,7 @@ static void ____mem_cgroup_commit_charge(struct mem_cgroup *mem,
break;
}
- mem_cgroup_charge_statistics(mem, pc, true);
-}
-
-static void __mem_cgroup_commit_charge(struct mem_cgroup *mem,
- struct page_cgroup *pc,
- enum charge_type ctype,
- int page_size)
-{
- int i;
- int count = page_size >> PAGE_SHIFT;
-
- /* try_charge() can return NULL to *memcg, taking care of it. */
- if (!mem)
- return;
-
- lock_page_cgroup(pc);
- if (unlikely(PageCgroupUsed(pc))) {
- unlock_page_cgroup(pc);
- mem_cgroup_cancel_charge(mem, page_size);
- return;
- }
-
- /*
- * we don't need page_cgroup_lock about tail pages, becase they are not
- * accessed by any other context at this point.
- */
- for (i = 0; i < count; i++)
- ____mem_cgroup_commit_charge(mem, pc + i, ctype);
-
+ mem_cgroup_charge_statistics(mem, PageCgroupCache(pc), nr_pages);
unlock_page_cgroup(pc);
/*
* "charge_statistics" updated event counter. Then, check it.
@@ -2153,6 +2130,46 @@ static void __mem_cgroup_commit_charge(struct mem_cgroup *mem,
memcg_check_events(mem, pc->page);
}
+#ifdef CONFIG_TRANSPARENT_HUGEPAGE
+
+#define PCGF_NOCOPY_AT_SPLIT ((1 << PCG_LOCK) | (1 << PCG_MOVE_LOCK) |\
+ (1 << PCG_ACCT_LRU) | (1 << PCG_MIGRATION))
+/*
+ * Because tail pages are not marked as "used", set it. We're under
+ * zone->lru_lock, 'splitting on pmd' and compund_lock.
+ */
+void mem_cgroup_split_huge_fixup(struct page *head, struct page *tail)
+{
+ struct page_cgroup *head_pc = lookup_page_cgroup(head);
+ struct page_cgroup *tail_pc = lookup_page_cgroup(tail);
+ unsigned long flags;
+
+ /*
+ * We have no races with charge/uncharge but will have races with
+ * page state accounting.
+ */
+ move_lock_page_cgroup(head_pc, &flags);
+
+ tail_pc->mem_cgroup = head_pc->mem_cgroup;
+ smp_wmb(); /* see __commit_charge() */
+ if (PageCgroupAcctLRU(head_pc)) {
+ enum lru_list lru;
+ struct mem_cgroup_per_zone *mz;
+
+ /*
+ * LRU flags cannot be copied because we need to add tail
+ *.page to LRU by generic call and our hook will be called.
+ * We hold lru_lock, then, reduce counter directly.
+ */
+ lru = page_lru(head);
+ mz = page_cgroup_zoneinfo(head_pc);
+ MEM_CGROUP_ZSTAT(mz, lru) -= 1;
+ }
+ tail_pc->flags = head_pc->flags & ~PCGF_NOCOPY_AT_SPLIT;
+ move_unlock_page_cgroup(head_pc, &flags);
+}
+#endif
+
/**
* __mem_cgroup_move_account - move account of the page
* @pc: page_cgroup of the page.
@@ -2171,8 +2188,11 @@ static void __mem_cgroup_commit_charge(struct mem_cgroup *mem,
*/
static void __mem_cgroup_move_account(struct page_cgroup *pc,
- struct mem_cgroup *from, struct mem_cgroup *to, bool uncharge)
+ struct mem_cgroup *from, struct mem_cgroup *to, bool uncharge,
+ int charge_size)
{
+ int nr_pages = charge_size >> PAGE_SHIFT;
+
VM_BUG_ON(from == to);
VM_BUG_ON(PageLRU(pc->page));
VM_BUG_ON(!page_is_cgroup_locked(pc));
@@ -2186,14 +2206,14 @@ static void __mem_cgroup_move_account(struct page_cgroup *pc,
__this_cpu_inc(to->stat->count[MEM_CGROUP_STAT_FILE_MAPPED]);
preempt_enable();
}
- mem_cgroup_charge_statistics(from, pc, false);
+ mem_cgroup_charge_statistics(from, PageCgroupCache(pc), -nr_pages);
if (uncharge)
/* This is not "cancel", but cancel_charge does all we need. */
- mem_cgroup_cancel_charge(from, PAGE_SIZE);
+ mem_cgroup_cancel_charge(from, charge_size);
/* caller should have done css_get */
pc->mem_cgroup = to;
- mem_cgroup_charge_statistics(to, pc, true);
+ mem_cgroup_charge_statistics(to, PageCgroupCache(pc), nr_pages);
/*
* We charges against "to" which may not have any tasks. Then, "to"
* can be under rmdir(). But in current implementation, caller of
@@ -2208,15 +2228,19 @@ static void __mem_cgroup_move_account(struct page_cgroup *pc,
* __mem_cgroup_move_account()
*/
static int mem_cgroup_move_account(struct page_cgroup *pc,
- struct mem_cgroup *from, struct mem_cgroup *to, bool uncharge)
+ struct mem_cgroup *from, struct mem_cgroup *to,
+ bool uncharge, int charge_size)
{
int ret = -EINVAL;
unsigned long flags;
+ if ((charge_size > PAGE_SIZE) && !PageTransHuge(pc->page))
+ return -EBUSY;
+
lock_page_cgroup(pc);
if (PageCgroupUsed(pc) && pc->mem_cgroup == from) {
move_lock_page_cgroup(pc, &flags);
- __mem_cgroup_move_account(pc, from, to, uncharge);
+ __mem_cgroup_move_account(pc, from, to, uncharge, charge_size);
move_unlock_page_cgroup(pc, &flags);
ret = 0;
}
@@ -2241,6 +2265,8 @@ static int mem_cgroup_move_parent(struct page_cgroup *pc,
struct cgroup *cg = child->css.cgroup;
struct cgroup *pcg = cg->parent;
struct mem_cgroup *parent;
+ int charge = PAGE_SIZE;
+ unsigned long flags;
int ret;
/* Is ROOT ? */
@@ -2252,17 +2278,23 @@ static int mem_cgroup_move_parent(struct page_cgroup *pc,
goto out;
if (isolate_lru_page(page))
goto put;
+ /* The page is isolated from LRU and we have no race with splitting */
+ charge = PAGE_SIZE << compound_order(page);
parent = mem_cgroup_from_cont(pcg);
- ret = __mem_cgroup_try_charge(NULL, gfp_mask, &parent, false,
- PAGE_SIZE);
+ ret = __mem_cgroup_try_charge(NULL, gfp_mask, &parent, false, charge);
if (ret || !parent)
goto put_back;
- ret = mem_cgroup_move_account(pc, child, parent, true);
+ if (charge > PAGE_SIZE)
+ flags = compound_lock_irqsave(page);
+
+ ret = mem_cgroup_move_account(pc, child, parent, true, charge);
if (ret)
- mem_cgroup_cancel_charge(parent, PAGE_SIZE);
+ mem_cgroup_cancel_charge(parent, charge);
put_back:
+ if (charge > PAGE_SIZE)
+ compound_unlock_irqrestore(page, flags);
putback_lru_page(page);
put:
put_page(page);
@@ -2546,7 +2578,6 @@ direct_uncharge:
static struct mem_cgroup *
__mem_cgroup_uncharge_common(struct page *page, enum charge_type ctype)
{
- int i;
int count;
struct page_cgroup *pc;
struct mem_cgroup *mem = NULL;
@@ -2596,8 +2627,7 @@ __mem_cgroup_uncharge_common(struct page *page, enum charge_type ctype)
break;
}
- for (i = 0; i < count; i++)
- mem_cgroup_charge_statistics(mem, pc + i, false);
+ mem_cgroup_charge_statistics(mem, PageCgroupCache(pc), -count);
ClearPageCgroupUsed(pc);
/*
@@ -4844,7 +4874,7 @@ retry:
goto put;
pc = lookup_page_cgroup(page);
if (!mem_cgroup_move_account(pc,
- mc.from, mc.to, false)) {
+ mc.from, mc.to, false, PAGE_SIZE)) {
mc.precharge--;
/* we uncharge from mc.from later. */
mc.moved_charge++;
diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c
index e92f047..321fc74 100644
--- a/mm/memory_hotplug.c
+++ b/mm/memory_hotplug.c
@@ -409,6 +409,7 @@ int online_pages(unsigned long pfn, unsigned long nr_pages)
int ret;
struct memory_notify arg;
+ lock_memory_hotplug();
arg.start_pfn = pfn;
arg.nr_pages = nr_pages;
arg.status_change_nid = -1;
@@ -421,6 +422,7 @@ int online_pages(unsigned long pfn, unsigned long nr_pages)
ret = notifier_to_errno(ret);
if (ret) {
memory_notify(MEM_CANCEL_ONLINE, &arg);
+ unlock_memory_hotplug();
return ret;
}
/*
@@ -445,6 +447,7 @@ int online_pages(unsigned long pfn, unsigned long nr_pages)
printk(KERN_DEBUG "online_pages %lx at %lx failed\n",
nr_pages, pfn);
memory_notify(MEM_CANCEL_ONLINE, &arg);
+ unlock_memory_hotplug();
return ret;
}
@@ -469,6 +472,7 @@ int online_pages(unsigned long pfn, unsigned long nr_pages)
if (onlined_pages)
memory_notify(MEM_ONLINE, &arg);
+ unlock_memory_hotplug();
return 0;
}
diff --git a/mm/pgtable-generic.c b/mm/pgtable-generic.c
index d030548..0369f5b 100644
--- a/mm/pgtable-generic.c
+++ b/mm/pgtable-generic.c
@@ -92,32 +92,29 @@ pte_t ptep_clear_flush(struct vm_area_struct *vma, unsigned long address,
#endif
#ifndef __HAVE_ARCH_PMDP_CLEAR_FLUSH
+#ifdef CONFIG_TRANSPARENT_HUGEPAGE
pmd_t pmdp_clear_flush(struct vm_area_struct *vma, unsigned long address,
pmd_t *pmdp)
{
pmd_t pmd;
-#ifndef CONFIG_TRANSPARENT_HUGEPAGE
- BUG();
-#endif /* CONFIG_TRANSPARENT_HUGEPAGE */
VM_BUG_ON(address & ~HPAGE_PMD_MASK);
pmd = pmdp_get_and_clear(vma->vm_mm, address, pmdp);
flush_tlb_range(vma, address, address + HPAGE_PMD_SIZE);
return pmd;
}
+#endif /* CONFIG_TRANSPARENT_HUGEPAGE */
#endif
#ifndef __HAVE_ARCH_PMDP_SPLITTING_FLUSH
+#ifdef CONFIG_TRANSPARENT_HUGEPAGE
pmd_t pmdp_splitting_flush(struct vm_area_struct *vma, unsigned long address,
pmd_t *pmdp)
{
-#ifdef CONFIG_TRANSPARENT_HUGEPAGE
pmd_t pmd = pmd_mksplitting(*pmdp);
VM_BUG_ON(address & ~HPAGE_PMD_MASK);
set_pmd_at(vma->vm_mm, address, pmdp, pmd);
/* tlb flush only to serialize against gup-fast */
flush_tlb_range(vma, address, address + HPAGE_PMD_SIZE);
-#else /* CONFIG_TRANSPARENT_HUGEPAGE */
- BUG();
-#endif /* CONFIG_TRANSPARENT_HUGEPAGE */
}
+#endif /* CONFIG_TRANSPARENT_HUGEPAGE */
#endif
diff --git a/mm/slab.c b/mm/slab.c
index 2640374..37961d1 100644
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -284,7 +284,7 @@ struct kmem_list3 {
* Need this for bootstrapping a per node allocator.
*/
#define NUM_INIT_LISTS (3 * MAX_NUMNODES)
-struct kmem_list3 __initdata initkmem_list3[NUM_INIT_LISTS];
+static struct kmem_list3 __initdata initkmem_list3[NUM_INIT_LISTS];
#define CACHE_CACHE 0
#define SIZE_AC MAX_NUMNODES
#define SIZE_L3 (2 * MAX_NUMNODES)
@@ -4053,7 +4053,7 @@ static int enable_cpucache(struct kmem_cache *cachep, gfp_t gfp)
* necessary. Note that the l3 listlock also protects the array_cache
* if drain_array() is used on the shared array.
*/
-void drain_array(struct kmem_cache *cachep, struct kmem_list3 *l3,
+static void drain_array(struct kmem_cache *cachep, struct kmem_list3 *l3,
struct array_cache *ac, int force, int node)
{
int tofree;
@@ -4317,7 +4317,7 @@ static const struct seq_operations slabinfo_op = {
* @count: data length
* @ppos: unused
*/
-ssize_t slabinfo_write(struct file *file, const char __user * buffer,
+static ssize_t slabinfo_write(struct file *file, const char __user *buffer,
size_t count, loff_t *ppos)
{
char kbuf[MAX_SLABINFO_WRITE + 1], *tmp;
diff --git a/mm/slub.c b/mm/slub.c
index c7ef007..e15aa7f 100644
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -3797,7 +3797,7 @@ static ssize_t show_slab_objects(struct kmem_cache *s,
}
}
- down_read(&slub_lock);
+ lock_memory_hotplug();
#ifdef CONFIG_SLUB_DEBUG
if (flags & SO_ALL) {
for_each_node_state(node, N_NORMAL_MEMORY) {
@@ -3838,7 +3838,7 @@ static ssize_t show_slab_objects(struct kmem_cache *s,
x += sprintf(buf + x, " N%d=%lu",
node, nodes[node]);
#endif
- up_read(&slub_lock);
+ unlock_memory_hotplug();
kfree(nodes);
return x + sprintf(buf + x, "\n");
}
diff --git a/mm/swap.c b/mm/swap.c
index bbc1ce9..c02f936 100644
--- a/mm/swap.c
+++ b/mm/swap.c
@@ -178,13 +178,15 @@ void put_pages_list(struct list_head *pages)
}
EXPORT_SYMBOL(put_pages_list);
-static void pagevec_lru_move_fn(struct pagevec *pvec,
- void (*move_fn)(struct page *page, void *arg),
- void *arg)
+/*
+ * pagevec_move_tail() must be called with IRQ disabled.
+ * Otherwise this may cause nasty races.
+ */
+static void pagevec_move_tail(struct pagevec *pvec)
{
int i;
+ int pgmoved = 0;
struct zone *zone = NULL;
- unsigned long flags = 0;
for (i = 0; i < pagevec_count(pvec); i++) {
struct page *page = pvec->pages[i];
@@ -192,41 +194,21 @@ static void pagevec_lru_move_fn(struct pagevec *pvec,
if (pagezone != zone) {
if (zone)
- spin_unlock_irqrestore(&zone->lru_lock, flags);
+ spin_unlock(&zone->lru_lock);
zone = pagezone;
- spin_lock_irqsave(&zone->lru_lock, flags);
+ spin_lock(&zone->lru_lock);
+ }
+ if (PageLRU(page) && !PageActive(page) && !PageUnevictable(page)) {
+ int lru = page_lru_base_type(page);
+ list_move_tail(&page->lru, &zone->lru[lru].list);
+ pgmoved++;
}
-
- (*move_fn)(page, arg);
}
if (zone)
- spin_unlock_irqrestore(&zone->lru_lock, flags);
- release_pages(pvec->pages, pagevec_count(pvec), pvec->cold);
- pagevec_reinit(pvec);
-}
-
-static void pagevec_move_tail_fn(struct page *page, void *arg)
-{
- int *pgmoved = arg;
- struct zone *zone = page_zone(page);
-
- if (PageLRU(page) && !PageActive(page) && !PageUnevictable(page)) {
- int lru = page_lru_base_type(page);
- list_move_tail(&page->lru, &zone->lru[lru].list);
- (*pgmoved)++;
- }
-}
-
-/*
- * pagevec_move_tail() must be called with IRQ disabled.
- * Otherwise this may cause nasty races.
- */
-static void pagevec_move_tail(struct pagevec *pvec)
-{
- int pgmoved = 0;
-
- pagevec_lru_move_fn(pvec, pagevec_move_tail_fn, &pgmoved);
+ spin_unlock(&zone->lru_lock);
__count_vm_events(PGROTATED, pgmoved);
+ release_pages(pvec->pages, pvec->nr, pvec->cold);
+ pagevec_reinit(pvec);
}
/*
@@ -234,7 +216,7 @@ static void pagevec_move_tail(struct pagevec *pvec)
* reclaim. If it still appears to be reclaimable, move it to the tail of the
* inactive list.
*/
-void rotate_reclaimable_page(struct page *page)
+void rotate_reclaimable_page(struct page *page)
{
if (!PageLocked(page) && !PageDirty(page) && !PageActive(page) &&
!PageUnevictable(page) && PageLRU(page)) {
@@ -271,94 +253,27 @@ static void update_page_reclaim_stat(struct zone *zone, struct page *page,
}
/*
- * A page will go to active list either by activate_page or putback_lru_page.
- * In the activate_page case, the page hasn't active bit set. The page might
- * not in LRU list because it's isolated before it gets a chance to be moved to
- * active list. The window is small because pagevec just stores several pages.
- * For such case, we do nothing for such page.
- * In the putback_lru_page case, the page isn't in lru list but has active
- * bit set
+ * FIXME: speed this up?
*/
-static void __activate_page(struct page *page, void *arg)
+void activate_page(struct page *page)
{
struct zone *zone = page_zone(page);
- int file = page_is_file_cache(page);
- int lru = page_lru_base_type(page);
- bool putback = !PageLRU(page);
-
- /* The page is isolated before it's moved to active list */
- if (!PageLRU(page) && !PageActive(page))
- return;
- if ((PageLRU(page) && PageActive(page)) || PageUnevictable(page))
- return;
-
- if (!putback)
- del_page_from_lru_list(zone, page, lru);
- else
- SetPageLRU(page);
-
- SetPageActive(page);
- lru += LRU_ACTIVE;
- add_page_to_lru_list(zone, page, lru);
-
- if (putback)
- return;
- __count_vm_event(PGACTIVATE);
- update_page_reclaim_stat(zone, page, file, 1);
-}
-#ifdef CONFIG_SMP
-static DEFINE_PER_CPU(struct pagevec, activate_page_pvecs);
-
-static void activate_page_drain(int cpu)
-{
- struct pagevec *pvec = &per_cpu(activate_page_pvecs, cpu);
-
- if (pagevec_count(pvec))
- pagevec_lru_move_fn(pvec, __activate_page, NULL);
-}
-
-void activate_page(struct page *page)
-{
+ spin_lock_irq(&zone->lru_lock);
if (PageLRU(page) && !PageActive(page) && !PageUnevictable(page)) {
- struct pagevec *pvec = &get_cpu_var(activate_page_pvecs);
-
- page_cache_get(page);
- if (!pagevec_add(pvec, page))
- pagevec_lru_move_fn(pvec, __activate_page, NULL);
- put_cpu_var(activate_page_pvecs);
- }
-}
+ int file = page_is_file_cache(page);
+ int lru = page_lru_base_type(page);
+ del_page_from_lru_list(zone, page, lru);
-/* Caller should hold zone->lru_lock */
-int putback_active_lru_page(struct zone *zone, struct page *page)
-{
- struct pagevec *pvec = &get_cpu_var(activate_page_pvecs);
+ SetPageActive(page);
+ lru += LRU_ACTIVE;
+ add_page_to_lru_list(zone, page, lru);
+ __count_vm_event(PGACTIVATE);
- if (!pagevec_add(pvec, page)) {
- spin_unlock_irq(&zone->lru_lock);
- pagevec_lru_move_fn(pvec, __activate_page, NULL);
- spin_lock_irq(&zone->lru_lock);
+ update_page_reclaim_stat(zone, page, file, 1);
}
- put_cpu_var(activate_page_pvecs);
- return 1;
-}
-
-#else
-static inline void activate_page_drain(int cpu)
-{
-}
-
-void activate_page(struct page *page)
-{
- struct zone *zone = page_zone(page);
-
- spin_lock_irq(&zone->lru_lock);
- if (PageLRU(page) && !PageActive(page) && !PageUnevictable(page))
- __activate_page(page, NULL);
spin_unlock_irq(&zone->lru_lock);
}
-#endif
/*
* Mark a page as having seen activity.
@@ -457,7 +372,6 @@ static void drain_cpu_pagevecs(int cpu)
pagevec_move_tail(pvec);
local_irq_restore(flags);
}
- activate_page_drain(cpu);
}
void lru_add_drain(void)
@@ -602,33 +516,44 @@ void lru_add_page_tail(struct zone* zone,
}
}
-static void ____pagevec_lru_add_fn(struct page *page, void *arg)
-{
- enum lru_list lru = (enum lru_list)arg;
- struct zone *zone = page_zone(page);
- int file = is_file_lru(lru);
- int active = is_active_lru(lru);
-
- VM_BUG_ON(PageActive(page));
- VM_BUG_ON(PageUnevictable(page));
- VM_BUG_ON(PageLRU(page));
-
- SetPageLRU(page);
- if (active)
- SetPageActive(page);
- update_page_reclaim_stat(zone, page, file, active);
- add_page_to_lru_list(zone, page, lru);
-}
-
/*
* Add the passed pages to the LRU, then drop the caller's refcount
* on them. Reinitialises the caller's pagevec.
*/
void ____pagevec_lru_add(struct pagevec *pvec, enum lru_list lru)
{
+ int i;
+ struct zone *zone = NULL;
+
VM_BUG_ON(is_unevictable_lru(lru));
- pagevec_lru_move_fn(pvec, ____pagevec_lru_add_fn, (void *)lru);
+ for (i = 0; i < pagevec_count(pvec); i++) {
+ struct page *page = pvec->pages[i];
+ struct zone *pagezone = page_zone(page);
+ int file;
+ int active;
+
+ if (pagezone != zone) {
+ if (zone)
+ spin_unlock_irq(&zone->lru_lock);
+ zone = pagezone;
+ spin_lock_irq(&zone->lru_lock);
+ }
+ VM_BUG_ON(PageActive(page));
+ VM_BUG_ON(PageUnevictable(page));
+ VM_BUG_ON(PageLRU(page));
+ SetPageLRU(page);
+ active = is_active_lru(lru);
+ file = is_file_lru(lru);
+ if (active)
+ SetPageActive(page);
+ update_page_reclaim_stat(zone, page, file, active);
+ add_page_to_lru_list(zone, page, lru);
+ }
+ if (zone)
+ spin_unlock_irq(&zone->lru_lock);
+ release_pages(pvec->pages, pvec->nr, pvec->cold);
+ pagevec_reinit(pvec);
}
EXPORT_SYMBOL(____pagevec_lru_add);
diff --git a/mm/truncate.c b/mm/truncate.c
index 3c2d5dd..49feb46 100644
--- a/mm/truncate.c
+++ b/mm/truncate.c
@@ -549,13 +549,12 @@ EXPORT_SYMBOL(truncate_pagecache);
* @inode: inode
* @newsize: new file size
*
- * truncate_setsize updastes i_size update and performs pagecache
- * truncation (if necessary) for a file size updates. It will be
- * typically be called from the filesystem's setattr function when
- * ATTR_SIZE is passed in.
+ * truncate_setsize updates i_size and performs pagecache truncation (if
+ * necessary) to @newsize. It will be typically be called from the filesystem's
+ * setattr function when ATTR_SIZE is passed in.
*
- * Must be called with inode_mutex held and after all filesystem
- * specific block truncation has been performed.
+ * Must be called with inode_mutex held and before all filesystem specific
+ * block truncation has been performed.
*/
void truncate_setsize(struct inode *inode, loff_t newsize)
{
diff --git a/mm/vmalloc.c b/mm/vmalloc.c
index cac13b4..f9b1667 100644
--- a/mm/vmalloc.c
+++ b/mm/vmalloc.c
@@ -1175,6 +1175,7 @@ void unmap_kernel_range_noflush(unsigned long addr, unsigned long size)
{
vunmap_page_range(addr, addr + size);
}
+EXPORT_SYMBOL_GPL(unmap_kernel_range_noflush);
/**
* unmap_kernel_range - unmap kernel VM area and flush cache and TLB
diff --git a/mm/vmscan.c b/mm/vmscan.c
index 99999a9..f5d90de 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -41,7 +41,6 @@
#include <linux/memcontrol.h>
#include <linux/delayacct.h>
#include <linux/sysctl.h>
-#include <linux/compaction.h>
#include <asm/tlbflush.h>
#include <asm/div64.h>
@@ -1271,16 +1270,14 @@ putback_lru_pages(struct zone *zone, struct scan_control *sc,
spin_lock_irq(&zone->lru_lock);
continue;
}
+ SetPageLRU(page);
lru = page_lru(page);
+ add_page_to_lru_list(zone, page, lru);
if (is_active_lru(lru)) {
int file = is_file_lru(lru);
int numpages = hpage_nr_pages(page);
reclaim_stat->recent_rotated[file] += numpages;
- if (putback_active_lru_page(zone, page))
- continue;
}
- SetPageLRU(page);
- add_page_to_lru_list(zone, page, lru);
if (!pagevec_add(&pvec, page)) {
spin_unlock_irq(&zone->lru_lock);
__pagevec_release(&pvec);
diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c
index bb86d29..6da5dae 100644
--- a/net/ax25/af_ax25.c
+++ b/net/ax25/af_ax25.c
@@ -1392,7 +1392,7 @@ static int ax25_getname(struct socket *sock, struct sockaddr *uaddr,
ax25_cb *ax25;
int err = 0;
- memset(fsa, 0, sizeof(fsa));
+ memset(fsa, 0, sizeof(*fsa));
lock_sock(sk);
ax25 = ax25_sk(sk);
diff --git a/net/batman-adv/main.h b/net/batman-adv/main.h
index d4d9926..65106fb 100644
--- a/net/batman-adv/main.h
+++ b/net/batman-adv/main.h
@@ -151,9 +151,9 @@ int debug_log(struct bat_priv *bat_priv, char *fmt, ...);
} \
while (0)
#else /* !CONFIG_BATMAN_ADV_DEBUG */
-static inline void bat_dbg(char type __attribute__((unused)),
- struct bat_priv *bat_priv __attribute__((unused)),
- char *fmt __attribute__((unused)), ...)
+static inline void bat_dbg(char type __always_unused,
+ struct bat_priv *bat_priv __always_unused,
+ char *fmt __always_unused, ...)
{
}
#endif
diff --git a/net/batman-adv/packet.h b/net/batman-adv/packet.h
index b49fdf7..2284e81 100644
--- a/net/batman-adv/packet.h
+++ b/net/batman-adv/packet.h
@@ -63,7 +63,7 @@ struct batman_packet {
uint8_t num_hna;
uint8_t gw_flags; /* flags related to gateway class */
uint8_t align;
-} __attribute__((packed));
+} __packed;
#define BAT_PACKET_LEN sizeof(struct batman_packet)
@@ -76,7 +76,7 @@ struct icmp_packet {
uint8_t orig[6];
uint16_t seqno;
uint8_t uid;
-} __attribute__((packed));
+} __packed;
#define BAT_RR_LEN 16
@@ -93,14 +93,14 @@ struct icmp_packet_rr {
uint8_t uid;
uint8_t rr_cur;
uint8_t rr[BAT_RR_LEN][ETH_ALEN];
-} __attribute__((packed));
+} __packed;
struct unicast_packet {
uint8_t packet_type;
uint8_t version; /* batman version field */
uint8_t dest[6];
uint8_t ttl;
-} __attribute__((packed));
+} __packed;
struct unicast_frag_packet {
uint8_t packet_type;
@@ -110,7 +110,7 @@ struct unicast_frag_packet {
uint8_t flags;
uint8_t orig[6];
uint16_t seqno;
-} __attribute__((packed));
+} __packed;
struct bcast_packet {
uint8_t packet_type;
@@ -118,7 +118,7 @@ struct bcast_packet {
uint8_t orig[6];
uint8_t ttl;
uint32_t seqno;
-} __attribute__((packed));
+} __packed;
struct vis_packet {
uint8_t packet_type;
@@ -131,6 +131,6 @@ struct vis_packet {
* neighbors */
uint8_t target_orig[6]; /* who should receive this packet */
uint8_t sender_orig[6]; /* who sent or rebroadcasted this packet */
-} __attribute__((packed));
+} __packed;
#endif /* _NET_BATMAN_ADV_PACKET_H_ */
diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h
index 97cb23d..bf3f6f5 100644
--- a/net/batman-adv/types.h
+++ b/net/batman-adv/types.h
@@ -246,13 +246,13 @@ struct vis_info {
/* this packet might be part of the vis send queue. */
struct sk_buff *skb_packet;
/* vis_info may follow here*/
-} __attribute__((packed));
+} __packed;
struct vis_info_entry {
uint8_t src[ETH_ALEN];
uint8_t dest[ETH_ALEN];
uint8_t quality; /* quality = 0 means HNA */
-} __attribute__((packed));
+} __packed;
struct recvlist_node {
struct list_head list;
diff --git a/net/batman-adv/unicast.c b/net/batman-adv/unicast.c
index dc2e28b..ee41fef 100644
--- a/net/batman-adv/unicast.c
+++ b/net/batman-adv/unicast.c
@@ -229,10 +229,12 @@ int frag_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv,
if (!bat_priv->primary_if)
goto dropped;
- unicast_packet = (struct unicast_packet *) skb->data;
+ frag_skb = dev_alloc_skb(data_len - (data_len / 2) + ucf_hdr_len);
+ if (!frag_skb)
+ goto dropped;
+ unicast_packet = (struct unicast_packet *) skb->data;
memcpy(&tmp_uc, unicast_packet, uc_hdr_len);
- frag_skb = dev_alloc_skb(data_len - (data_len / 2) + ucf_hdr_len);
skb_split(skb, frag_skb, data_len / 2);
if (my_skb_head_push(skb, ucf_hdr_len - uc_hdr_len) < 0 ||
diff --git a/net/caif/cfcnfg.c b/net/caif/cfcnfg.c
index 21ede14..c665de7 100644
--- a/net/caif/cfcnfg.c
+++ b/net/caif/cfcnfg.c
@@ -191,6 +191,7 @@ int cfcnfg_disconn_adapt_layer(struct cfcnfg *cnfg, struct cflayer *adap_layer)
struct cflayer *servl = NULL;
struct cfcnfg_phyinfo *phyinfo = NULL;
u8 phyid = 0;
+
caif_assert(adap_layer != NULL);
channel_id = adap_layer->id;
if (adap_layer->dn == NULL || channel_id == 0) {
@@ -199,16 +200,16 @@ int cfcnfg_disconn_adapt_layer(struct cfcnfg *cnfg, struct cflayer *adap_layer)
goto end;
}
servl = cfmuxl_remove_uplayer(cnfg->mux, channel_id);
- if (servl == NULL)
- goto end;
- layer_set_up(servl, NULL);
- ret = cfctrl_linkdown_req(cnfg->ctrl, channel_id, adap_layer);
if (servl == NULL) {
pr_err("PROTOCOL ERROR - Error removing service_layer Channel_Id(%d)",
channel_id);
ret = -EINVAL;
goto end;
}
+ layer_set_up(servl, NULL);
+ ret = cfctrl_linkdown_req(cnfg->ctrl, channel_id, adap_layer);
+ if (ret)
+ goto end;
caif_assert(channel_id == servl->id);
if (adap_layer->dn != NULL) {
phyid = cfsrvl_getphyid(adap_layer->dn);
diff --git a/net/can/bcm.c b/net/can/bcm.c
index 9d5e8ac..092dc88 100644
--- a/net/can/bcm.c
+++ b/net/can/bcm.c
@@ -1256,6 +1256,9 @@ static int bcm_sendmsg(struct kiocb *iocb, struct socket *sock,
struct sockaddr_can *addr =
(struct sockaddr_can *)msg->msg_name;
+ if (msg->msg_namelen < sizeof(*addr))
+ return -EINVAL;
+
if (addr->can_family != AF_CAN)
return -EINVAL;
diff --git a/net/can/raw.c b/net/can/raw.c
index e88f610..883e9d7 100644
--- a/net/can/raw.c
+++ b/net/can/raw.c
@@ -649,6 +649,9 @@ static int raw_sendmsg(struct kiocb *iocb, struct socket *sock,
struct sockaddr_can *addr =
(struct sockaddr_can *)msg->msg_name;
+ if (msg->msg_namelen < sizeof(*addr))
+ return -EINVAL;
+
if (addr->can_family != AF_CAN)
return -EINVAL;
diff --git a/net/core/dev.c b/net/core/dev.c
index 06d0e7b..7c6a46f 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -2001,7 +2001,7 @@ static bool can_checksum_protocol(unsigned long features, __be16 protocol)
static int harmonize_features(struct sk_buff *skb, __be16 protocol, int features)
{
- if (!can_checksum_protocol(protocol, features)) {
+ if (!can_checksum_protocol(features, protocol)) {
features &= ~NETIF_F_ALL_CSUM;
features &= ~NETIF_F_SG;
} else if (illegal_highdma(skb->dev, skb)) {
@@ -2023,13 +2023,13 @@ int netif_skb_features(struct sk_buff *skb)
return harmonize_features(skb, protocol, features);
}
- features &= skb->dev->vlan_features;
+ features &= (skb->dev->vlan_features | NETIF_F_HW_VLAN_TX);
if (protocol != htons(ETH_P_8021Q)) {
return harmonize_features(skb, protocol, features);
} else {
features &= NETIF_F_SG | NETIF_F_HIGHDMA | NETIF_F_FRAGLIST |
- NETIF_F_GEN_CSUM;
+ NETIF_F_GEN_CSUM | NETIF_F_HW_VLAN_TX;
return harmonize_features(skb, protocol, features);
}
}
@@ -5523,34 +5523,6 @@ void netdev_run_todo(void)
}
}
-/**
- * dev_txq_stats_fold - fold tx_queues stats
- * @dev: device to get statistics from
- * @stats: struct rtnl_link_stats64 to hold results
- */
-void dev_txq_stats_fold(const struct net_device *dev,
- struct rtnl_link_stats64 *stats)
-{
- u64 tx_bytes = 0, tx_packets = 0, tx_dropped = 0;
- unsigned int i;
- struct netdev_queue *txq;
-
- for (i = 0; i < dev->num_tx_queues; i++) {
- txq = netdev_get_tx_queue(dev, i);
- spin_lock_bh(&txq->_xmit_lock);
- tx_bytes += txq->tx_bytes;
- tx_packets += txq->tx_packets;
- tx_dropped += txq->tx_dropped;
- spin_unlock_bh(&txq->_xmit_lock);
- }
- if (tx_bytes || tx_packets || tx_dropped) {
- stats->tx_bytes = tx_bytes;
- stats->tx_packets = tx_packets;
- stats->tx_dropped = tx_dropped;
- }
-}
-EXPORT_SYMBOL(dev_txq_stats_fold);
-
/* Convert net_device_stats to rtnl_link_stats64. They have the same
* fields in the same order, with only the type differing.
*/
@@ -5594,7 +5566,6 @@ struct rtnl_link_stats64 *dev_get_stats(struct net_device *dev,
netdev_stats_to_stats64(storage, ops->ndo_get_stats(dev));
} else {
netdev_stats_to_stats64(storage, &dev->stats);
- dev_txq_stats_fold(dev, storage);
}
storage->rx_dropped += atomic_long_read(&dev->rx_dropped);
return storage;
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index a5f7535..750db57 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -1820,7 +1820,7 @@ static int rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
if (kind != 2 && security_netlink_recv(skb, CAP_NET_ADMIN))
return -EPERM;
- if (kind == 2 && (nlh->nlmsg_flags & NLM_F_DUMP) == NLM_F_DUMP) {
+ if (kind == 2 && nlh->nlmsg_flags&NLM_F_DUMP) {
struct sock *rtnl;
rtnl_dumpit_func dumpit;
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 19d6c21..d31bb36 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -380,6 +380,8 @@ static void skb_release_head_state(struct sk_buff *skb)
}
#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
nf_conntrack_put(skb->nfct);
+#endif
+#ifdef NET_SKBUFF_NF_DEFRAG_NEEDED
nf_conntrack_put_reasm(skb->nfct_reasm);
#endif
#ifdef CONFIG_BRIDGE_NETFILTER
diff --git a/net/dsa/dsa.c b/net/dsa/dsa.c
index 0c877a7..3fb14b7 100644
--- a/net/dsa/dsa.c
+++ b/net/dsa/dsa.c
@@ -428,7 +428,7 @@ static void __exit dsa_cleanup_module(void)
}
module_exit(dsa_cleanup_module);
-MODULE_AUTHOR("Lennert Buytenhek <buytenh@wantstofly.org>")
+MODULE_AUTHOR("Lennert Buytenhek <buytenh@wantstofly.org>");
MODULE_DESCRIPTION("Driver for Distributed Switch Architecture switch chips");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:dsa");
diff --git a/net/ethernet/eth.c b/net/ethernet/eth.c
index f9d7ac9..44d2b42 100644
--- a/net/ethernet/eth.c
+++ b/net/ethernet/eth.c
@@ -351,7 +351,7 @@ EXPORT_SYMBOL(ether_setup);
* @sizeof_priv: Size of additional driver-private structure to be allocated
* for this Ethernet device
* @txqs: The number of TX queues this device has.
- * @txqs: The number of RX queues this device has.
+ * @rxqs: The number of RX queues this device has.
*
* Fill in the fields of the device structure with Ethernet-generic
* values. Basically does everything except registering the device.
diff --git a/net/ipv4/inet_diag.c b/net/ipv4/inet_diag.c
index 2746c1f..2ada171 100644
--- a/net/ipv4/inet_diag.c
+++ b/net/ipv4/inet_diag.c
@@ -858,7 +858,7 @@ static int inet_diag_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
nlmsg_len(nlh) < hdrlen)
return -EINVAL;
- if ((nlh->nlmsg_flags & NLM_F_DUMP) == NLM_F_DUMP) {
+ if (nlh->nlmsg_flags & NLM_F_DUMP) {
if (nlmsg_attrlen(nlh, hdrlen)) {
struct nlattr *attr;
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 5b189c9..24a1cf1 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -420,9 +420,6 @@ static struct inet6_dev * ipv6_add_dev(struct net_device *dev)
dev->type == ARPHRD_TUNNEL6 ||
dev->type == ARPHRD_SIT ||
dev->type == ARPHRD_NONE) {
- printk(KERN_INFO
- "%s: Disabled Privacy Extensions\n",
- dev->name);
ndev->cnf.use_tempaddr = -1;
} else {
in6_dev_hold(ndev);
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index 94b5bf1..5f8d242 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -401,6 +401,9 @@ int ip6_forward(struct sk_buff *skb)
goto drop;
}
+ if (skb->pkt_type != PACKET_HOST)
+ goto drop;
+
skb_forward_csum(skb);
/*
diff --git a/net/ipv6/netfilter/nf_defrag_ipv6_hooks.c b/net/ipv6/netfilter/nf_defrag_ipv6_hooks.c
index 99abfb5..97c5b21 100644
--- a/net/ipv6/netfilter/nf_defrag_ipv6_hooks.c
+++ b/net/ipv6/netfilter/nf_defrag_ipv6_hooks.c
@@ -19,13 +19,15 @@
#include <linux/netfilter_ipv6.h>
#include <linux/netfilter_bridge.h>
+#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
#include <net/netfilter/nf_conntrack.h>
#include <net/netfilter/nf_conntrack_helper.h>
#include <net/netfilter/nf_conntrack_l4proto.h>
#include <net/netfilter/nf_conntrack_l3proto.h>
#include <net/netfilter/nf_conntrack_core.h>
-#include <net/netfilter/nf_conntrack_zones.h>
#include <net/netfilter/ipv6/nf_conntrack_ipv6.h>
+#endif
+#include <net/netfilter/nf_conntrack_zones.h>
#include <net/netfilter/ipv6/nf_defrag_ipv6.h>
static enum ip6_defrag_users nf_ct6_defrag_user(unsigned int hooknum,
@@ -33,8 +35,10 @@ static enum ip6_defrag_users nf_ct6_defrag_user(unsigned int hooknum,
{
u16 zone = NF_CT_DEFAULT_ZONE;
+#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
if (skb->nfct)
zone = nf_ct_zone((struct nf_conn *)skb->nfct);
+#endif
#ifdef CONFIG_BRIDGE_NETFILTER
if (skb->nf_bridge &&
@@ -56,9 +60,11 @@ static unsigned int ipv6_defrag(unsigned int hooknum,
{
struct sk_buff *reasm;
+#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
/* Previously seen (loopback)? */
if (skb->nfct && !nf_ct_is_template((struct nf_conn *)skb->nfct))
return NF_ACCEPT;
+#endif
reasm = nf_ct_frag6_gather(skb, nf_ct6_defrag_user(hooknum, skb));
/* queued */
diff --git a/net/mac80211/Kconfig b/net/mac80211/Kconfig
index 9109262..c766056 100644
--- a/net/mac80211/Kconfig
+++ b/net/mac80211/Kconfig
@@ -20,7 +20,7 @@ config MAC80211_HAS_RC
def_bool n
config MAC80211_RC_PID
- bool "PID controller based rate control algorithm" if EMBEDDED
+ bool "PID controller based rate control algorithm" if EXPERT
select MAC80211_HAS_RC
---help---
This option enables a TX rate control algorithm for
@@ -28,14 +28,14 @@ config MAC80211_RC_PID
rate.
config MAC80211_RC_MINSTREL
- bool "Minstrel" if EMBEDDED
+ bool "Minstrel" if EXPERT
select MAC80211_HAS_RC
default y
---help---
This option enables the 'minstrel' TX rate control algorithm
config MAC80211_RC_MINSTREL_HT
- bool "Minstrel 802.11n support" if EMBEDDED
+ bool "Minstrel 802.11n support" if EXPERT
depends on MAC80211_RC_MINSTREL
default y
---help---
diff --git a/net/mac80211/agg-rx.c b/net/mac80211/agg-rx.c
index f138b19..227ca82 100644
--- a/net/mac80211/agg-rx.c
+++ b/net/mac80211/agg-rx.c
@@ -185,8 +185,6 @@ void ieee80211_process_addba_request(struct ieee80211_local *local,
struct ieee80211_mgmt *mgmt,
size_t len)
{
- struct ieee80211_hw *hw = &local->hw;
- struct ieee80211_conf *conf = &hw->conf;
struct tid_ampdu_rx *tid_agg_rx;
u16 capab, tid, timeout, ba_policy, buf_size, start_seq_num, status;
u8 dialog_token;
@@ -231,13 +229,8 @@ void ieee80211_process_addba_request(struct ieee80211_local *local,
goto end_no_lock;
}
/* determine default buffer size */
- if (buf_size == 0) {
- struct ieee80211_supported_band *sband;
-
- sband = local->hw.wiphy->bands[conf->channel->band];
- buf_size = IEEE80211_MIN_AMPDU_BUF;
- buf_size = buf_size << sband->ht_cap.ampdu_factor;
- }
+ if (buf_size == 0)
+ buf_size = IEEE80211_MAX_AMPDU_BUF;
/* examine state machine */
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 485d36b..a46ff06 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -39,6 +39,8 @@ module_param(ieee80211_disable_40mhz_24ghz, bool, 0644);
MODULE_PARM_DESC(ieee80211_disable_40mhz_24ghz,
"Disable 40MHz support in the 2.4GHz band");
+static struct lock_class_key ieee80211_rx_skb_queue_class;
+
void ieee80211_configure_filter(struct ieee80211_local *local)
{
u64 mc;
@@ -569,7 +571,15 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
spin_lock_init(&local->filter_lock);
spin_lock_init(&local->queue_stop_reason_lock);
- skb_queue_head_init(&local->rx_skb_queue);
+ /*
+ * The rx_skb_queue is only accessed from tasklets,
+ * but other SKB queues are used from within IRQ
+ * context. Therefore, this one needs a different
+ * locking class so our direct, non-irq-safe use of
+ * the queue's lock doesn't throw lockdep warnings.
+ */
+ skb_queue_head_init_class(&local->rx_skb_queue,
+ &ieee80211_rx_skb_queue_class);
INIT_DELAYED_WORK(&local->scan_work, ieee80211_scan_work);
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
index 5cb8d30..93297aa 100644
--- a/net/netfilter/nf_conntrack_netlink.c
+++ b/net/netfilter/nf_conntrack_netlink.c
@@ -924,7 +924,7 @@ ctnetlink_get_conntrack(struct sock *ctnl, struct sk_buff *skb,
u16 zone;
int err;
- if ((nlh->nlmsg_flags & NLM_F_DUMP) == NLM_F_DUMP)
+ if (nlh->nlmsg_flags & NLM_F_DUMP)
return netlink_dump_start(ctnl, skb, nlh, ctnetlink_dump_table,
ctnetlink_done);
@@ -972,7 +972,8 @@ ctnetlink_get_conntrack(struct sock *ctnl, struct sk_buff *skb,
free:
kfree_skb(skb2);
out:
- return err;
+ /* this avoids a loop in nfnetlink. */
+ return err == -EAGAIN ? -ENOBUFS : err;
}
#ifdef CONFIG_NF_NAT_NEEDED
@@ -1786,7 +1787,7 @@ ctnetlink_get_expect(struct sock *ctnl, struct sk_buff *skb,
u16 zone;
int err;
- if ((nlh->nlmsg_flags & NLM_F_DUMP) == NLM_F_DUMP) {
+ if (nlh->nlmsg_flags & NLM_F_DUMP) {
return netlink_dump_start(ctnl, skb, nlh,
ctnetlink_exp_dump_table,
ctnetlink_exp_done);
diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c
index f83cb37..1781d99 100644
--- a/net/netlink/genetlink.c
+++ b/net/netlink/genetlink.c
@@ -519,7 +519,7 @@ static int genl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
security_netlink_recv(skb, CAP_NET_ADMIN))
return -EPERM;
- if ((nlh->nlmsg_flags & NLM_F_DUMP) == NLM_F_DUMP) {
+ if (nlh->nlmsg_flags & NLM_F_DUMP) {
if (ops->dumpit == NULL)
return -EOPNOTSUPP;
diff --git a/net/rfkill/Kconfig b/net/rfkill/Kconfig
index eaf7658..7fce6df 100644
--- a/net/rfkill/Kconfig
+++ b/net/rfkill/Kconfig
@@ -18,7 +18,7 @@ config RFKILL_LEDS
default y
config RFKILL_INPUT
- bool "RF switch input support" if EMBEDDED
+ bool "RF switch input support" if EXPERT
depends on RFKILL
depends on INPUT = y || RFKILL = INPUT
- default y if !EMBEDDED
+ default y if !EXPERT
diff --git a/net/rxrpc/af_rxrpc.c b/net/rxrpc/af_rxrpc.c
index 0b9bb20..74c064c 100644
--- a/net/rxrpc/af_rxrpc.c
+++ b/net/rxrpc/af_rxrpc.c
@@ -808,7 +808,7 @@ static int __init af_rxrpc_init(void)
goto error_call_jar;
}
- rxrpc_workqueue = create_workqueue("krxrpcd");
+ rxrpc_workqueue = alloc_workqueue("krxrpcd", 0, 1);
if (!rxrpc_workqueue) {
printk(KERN_NOTICE "RxRPC: Failed to allocate work queue\n");
goto error_work_queue;
diff --git a/net/sched/sch_teql.c b/net/sched/sch_teql.c
index af9360d..84ce48e 100644
--- a/net/sched/sch_teql.c
+++ b/net/sched/sch_teql.c
@@ -59,6 +59,10 @@ struct teql_master
struct net_device *dev;
struct Qdisc *slaves;
struct list_head master_list;
+ unsigned long tx_bytes;
+ unsigned long tx_packets;
+ unsigned long tx_errors;
+ unsigned long tx_dropped;
};
struct teql_sched_data
@@ -274,7 +278,6 @@ static inline int teql_resolve(struct sk_buff *skb,
static netdev_tx_t teql_master_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct teql_master *master = netdev_priv(dev);
- struct netdev_queue *txq = netdev_get_tx_queue(dev, 0);
struct Qdisc *start, *q;
int busy;
int nores;
@@ -314,8 +317,8 @@ restart:
__netif_tx_unlock(slave_txq);
master->slaves = NEXT_SLAVE(q);
netif_wake_queue(dev);
- txq->tx_packets++;
- txq->tx_bytes += length;
+ master->tx_packets++;
+ master->tx_bytes += length;
return NETDEV_TX_OK;
}
__netif_tx_unlock(slave_txq);
@@ -342,10 +345,10 @@ restart:
netif_stop_queue(dev);
return NETDEV_TX_BUSY;
}
- dev->stats.tx_errors++;
+ master->tx_errors++;
drop:
- txq->tx_dropped++;
+ master->tx_dropped++;
dev_kfree_skb(skb);
return NETDEV_TX_OK;
}
@@ -398,6 +401,18 @@ static int teql_master_close(struct net_device *dev)
return 0;
}
+static struct rtnl_link_stats64 *teql_master_stats64(struct net_device *dev,
+ struct rtnl_link_stats64 *stats)
+{
+ struct teql_master *m = netdev_priv(dev);
+
+ stats->tx_packets = m->tx_packets;
+ stats->tx_bytes = m->tx_bytes;
+ stats->tx_errors = m->tx_errors;
+ stats->tx_dropped = m->tx_dropped;
+ return stats;
+}
+
static int teql_master_mtu(struct net_device *dev, int new_mtu)
{
struct teql_master *m = netdev_priv(dev);
@@ -422,6 +437,7 @@ static const struct net_device_ops teql_netdev_ops = {
.ndo_open = teql_master_open,
.ndo_stop = teql_master_close,
.ndo_start_xmit = teql_master_xmit,
+ .ndo_get_stats64 = teql_master_stats64,
.ndo_change_mtu = teql_master_mtu,
};
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index a09b0dd..8e02550 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -3428,7 +3428,7 @@ SCTP_STATIC int sctp_setsockopt(struct sock *sk, int level, int optname,
retval = sctp_setsockopt_peer_addr_params(sk, optval, optlen);
break;
- case SCTP_DELAYED_ACK:
+ case SCTP_DELAYED_SACK:
retval = sctp_setsockopt_delayed_ack(sk, optval, optlen);
break;
case SCTP_PARTIAL_DELIVERY_POINT:
@@ -5333,7 +5333,7 @@ SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname,
retval = sctp_getsockopt_peer_addr_params(sk, len, optval,
optlen);
break;
- case SCTP_DELAYED_ACK:
+ case SCTP_DELAYED_SACK:
retval = sctp_getsockopt_delayed_ack(sk, len, optval,
optlen);
break;
diff --git a/net/sunrpc/auth_gss/gss_krb5_crypto.c b/net/sunrpc/auth_gss/gss_krb5_crypto.c
index 75ee993..9576f35 100644
--- a/net/sunrpc/auth_gss/gss_krb5_crypto.c
+++ b/net/sunrpc/auth_gss/gss_krb5_crypto.c
@@ -137,7 +137,7 @@ arcfour_hmac_md5_usage_to_salt(unsigned int usage, u8 salt[4])
ms_usage = 13;
break;
default:
- return EINVAL;;
+ return -EINVAL;
}
salt[0] = (ms_usage >> 0) & 0xff;
salt[1] = (ms_usage >> 8) & 0xff;
diff --git a/net/sunrpc/auth_gss/svcauth_gss.c b/net/sunrpc/auth_gss/svcauth_gss.c
index dec2a6f..bcdae78 100644
--- a/net/sunrpc/auth_gss/svcauth_gss.c
+++ b/net/sunrpc/auth_gss/svcauth_gss.c
@@ -67,7 +67,6 @@ static int netobj_equal(struct xdr_netobj *a, struct xdr_netobj *b)
#define RSI_HASHBITS 6
#define RSI_HASHMAX (1<<RSI_HASHBITS)
-#define RSI_HASHMASK (RSI_HASHMAX-1)
struct rsi {
struct cache_head h;
@@ -319,7 +318,6 @@ static struct rsi *rsi_update(struct rsi *new, struct rsi *old)
#define RSC_HASHBITS 10
#define RSC_HASHMAX (1<<RSC_HASHBITS)
-#define RSC_HASHMASK (RSC_HASHMAX-1)
#define GSS_SEQ_WIN 128
diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c
index e433e75..72ad836 100644
--- a/net/sunrpc/cache.c
+++ b/net/sunrpc/cache.c
@@ -37,7 +37,7 @@
#define RPCDBG_FACILITY RPCDBG_CACHE
-static void cache_defer_req(struct cache_req *req, struct cache_head *item);
+static bool cache_defer_req(struct cache_req *req, struct cache_head *item);
static void cache_revisit_request(struct cache_head *item);
static void cache_init(struct cache_head *h)
@@ -128,6 +128,7 @@ static void cache_fresh_locked(struct cache_head *head, time_t expiry)
{
head->expiry_time = expiry;
head->last_refresh = seconds_since_boot();
+ smp_wmb(); /* paired with smp_rmb() in cache_is_valid() */
set_bit(CACHE_VALID, &head->flags);
}
@@ -208,11 +209,36 @@ static inline int cache_is_valid(struct cache_detail *detail, struct cache_head
/* entry is valid */
if (test_bit(CACHE_NEGATIVE, &h->flags))
return -ENOENT;
- else
+ else {
+ /*
+ * In combination with write barrier in
+ * sunrpc_cache_update, ensures that anyone
+ * using the cache entry after this sees the
+ * updated contents:
+ */
+ smp_rmb();
return 0;
+ }
}
}
+static int try_to_negate_entry(struct cache_detail *detail, struct cache_head *h)
+{
+ int rv;
+
+ write_lock(&detail->hash_lock);
+ rv = cache_is_valid(detail, h);
+ if (rv != -EAGAIN) {
+ write_unlock(&detail->hash_lock);
+ return rv;
+ }
+ set_bit(CACHE_NEGATIVE, &h->flags);
+ cache_fresh_locked(h, seconds_since_boot()+CACHE_NEW_EXPIRY);
+ write_unlock(&detail->hash_lock);
+ cache_fresh_unlocked(h, detail);
+ return -ENOENT;
+}
+
/*
* This is the generic cache management routine for all
* the authentication caches.
@@ -251,14 +277,8 @@ int cache_check(struct cache_detail *detail,
case -EINVAL:
clear_bit(CACHE_PENDING, &h->flags);
cache_revisit_request(h);
- if (rv == -EAGAIN) {
- set_bit(CACHE_NEGATIVE, &h->flags);
- cache_fresh_locked(h, seconds_since_boot()+CACHE_NEW_EXPIRY);
- cache_fresh_unlocked(h, detail);
- rv = -ENOENT;
- }
+ rv = try_to_negate_entry(detail, h);
break;
-
case -EAGAIN:
clear_bit(CACHE_PENDING, &h->flags);
cache_revisit_request(h);
@@ -268,9 +288,11 @@ int cache_check(struct cache_detail *detail,
}
if (rv == -EAGAIN) {
- cache_defer_req(rqstp, h);
- if (!test_bit(CACHE_PENDING, &h->flags)) {
- /* Request is not deferred */
+ if (!cache_defer_req(rqstp, h)) {
+ /*
+ * Request was not deferred; handle it as best
+ * we can ourselves:
+ */
rv = cache_is_valid(detail, h);
if (rv == -EAGAIN)
rv = -ETIMEDOUT;
@@ -618,18 +640,19 @@ static void cache_limit_defers(void)
discard->revisit(discard, 1);
}
-static void cache_defer_req(struct cache_req *req, struct cache_head *item)
+/* Return true if and only if a deferred request is queued. */
+static bool cache_defer_req(struct cache_req *req, struct cache_head *item)
{
struct cache_deferred_req *dreq;
if (req->thread_wait) {
cache_wait_req(req, item);
if (!test_bit(CACHE_PENDING, &item->flags))
- return;
+ return false;
}
dreq = req->defer(req);
if (dreq == NULL)
- return;
+ return false;
setup_deferral(dreq, item, 1);
if (!test_bit(CACHE_PENDING, &item->flags))
/* Bit could have been cleared before we managed to
@@ -638,6 +661,7 @@ static void cache_defer_req(struct cache_req *req, struct cache_head *item)
cache_revisit_request(item);
cache_limit_defers();
+ return true;
}
static void cache_revisit_request(struct cache_head *item)
diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c
index 0e659c6..08e05a8 100644
--- a/net/sunrpc/svc.c
+++ b/net/sunrpc/svc.c
@@ -1001,6 +1001,7 @@ svc_process_common(struct svc_rqst *rqstp, struct kvec *argv, struct kvec *resv)
rqstp->rq_splice_ok = 1;
/* Will be turned off only when NFSv4 Sessions are used */
rqstp->rq_usedeferral = 1;
+ rqstp->rq_dropme = false;
/* Setup reply header */
rqstp->rq_xprt->xpt_ops->xpo_prep_reply_hdr(rqstp);
@@ -1102,7 +1103,7 @@ svc_process_common(struct svc_rqst *rqstp, struct kvec *argv, struct kvec *resv)
*statp = procp->pc_func(rqstp, rqstp->rq_argp, rqstp->rq_resp);
/* Encode reply */
- if (*statp == rpc_drop_reply) {
+ if (rqstp->rq_dropme) {
if (procp->pc_release)
procp->pc_release(rqstp, NULL, rqstp->rq_resp);
goto dropit;
diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c
index 3f2c555..ab86b79 100644
--- a/net/sunrpc/svc_xprt.c
+++ b/net/sunrpc/svc_xprt.c
@@ -13,6 +13,7 @@
#include <linux/sunrpc/stats.h>
#include <linux/sunrpc/svc_xprt.h>
#include <linux/sunrpc/svcsock.h>
+#include <linux/sunrpc/xprt.h>
#define RPCDBG_FACILITY RPCDBG_SVCXPRT
@@ -128,6 +129,9 @@ static void svc_xprt_free(struct kref *kref)
if (test_bit(XPT_CACHE_AUTH, &xprt->xpt_flags))
svcauth_unix_info_release(xprt);
put_net(xprt->xpt_net);
+ /* See comment on corresponding get in xs_setup_bc_tcp(): */
+ if (xprt->xpt_bc_xprt)
+ xprt_put(xprt->xpt_bc_xprt);
xprt->xpt_ops->xpo_free(xprt);
module_put(owner);
}
@@ -303,6 +307,15 @@ static void svc_thread_dequeue(struct svc_pool *pool, struct svc_rqst *rqstp)
list_del(&rqstp->rq_list);
}
+static bool svc_xprt_has_something_to_do(struct svc_xprt *xprt)
+{
+ if (xprt->xpt_flags & ((1<<XPT_CONN)|(1<<XPT_CLOSE)))
+ return true;
+ if (xprt->xpt_flags & ((1<<XPT_DATA)|(1<<XPT_DEFERRED)))
+ return xprt->xpt_ops->xpo_has_wspace(xprt);
+ return false;
+}
+
/*
* Queue up a transport with data pending. If there are idle nfsd
* processes, wake 'em up.
@@ -315,8 +328,7 @@ void svc_xprt_enqueue(struct svc_xprt *xprt)
struct svc_rqst *rqstp;
int cpu;
- if (!(xprt->xpt_flags &
- ((1<<XPT_CONN)|(1<<XPT_DATA)|(1<<XPT_CLOSE)|(1<<XPT_DEFERRED))))
+ if (!svc_xprt_has_something_to_do(xprt))
return;
cpu = get_cpu();
@@ -343,28 +355,7 @@ void svc_xprt_enqueue(struct svc_xprt *xprt)
dprintk("svc: transport %p busy, not enqueued\n", xprt);
goto out_unlock;
}
- BUG_ON(xprt->xpt_pool != NULL);
- xprt->xpt_pool = pool;
-
- /* Handle pending connection */
- if (test_bit(XPT_CONN, &xprt->xpt_flags))
- goto process;
-
- /* Handle close in-progress */
- if (test_bit(XPT_CLOSE, &xprt->xpt_flags))
- goto process;
-
- /* Check if we have space to reply to a request */
- if (!xprt->xpt_ops->xpo_has_wspace(xprt)) {
- /* Don't enqueue while not enough space for reply */
- dprintk("svc: no write space, transport %p not enqueued\n",
- xprt);
- xprt->xpt_pool = NULL;
- clear_bit(XPT_BUSY, &xprt->xpt_flags);
- goto out_unlock;
- }
- process:
if (!list_empty(&pool->sp_threads)) {
rqstp = list_entry(pool->sp_threads.next,
struct svc_rqst,
@@ -381,13 +372,11 @@ void svc_xprt_enqueue(struct svc_xprt *xprt)
rqstp->rq_reserved = serv->sv_max_mesg;
atomic_add(rqstp->rq_reserved, &xprt->xpt_reserved);
pool->sp_stats.threads_woken++;
- BUG_ON(xprt->xpt_pool != pool);
wake_up(&rqstp->rq_wait);
} else {
dprintk("svc: transport %p put into queue\n", xprt);
list_add_tail(&xprt->xpt_ready, &pool->sp_sockets);
pool->sp_stats.sockets_queued++;
- BUG_ON(xprt->xpt_pool != pool);
}
out_unlock:
@@ -426,7 +415,6 @@ static struct svc_xprt *svc_xprt_dequeue(struct svc_pool *pool)
void svc_xprt_received(struct svc_xprt *xprt)
{
BUG_ON(!test_bit(XPT_BUSY, &xprt->xpt_flags));
- xprt->xpt_pool = NULL;
/* As soon as we clear busy, the xprt could be closed and
* 'put', so we need a reference to call svc_xprt_enqueue with:
*/
@@ -722,7 +710,10 @@ int svc_recv(struct svc_rqst *rqstp, long timeout)
if (test_bit(XPT_CLOSE, &xprt->xpt_flags)) {
dprintk("svc_recv: found XPT_CLOSE\n");
svc_delete_xprt(xprt);
- } else if (test_bit(XPT_LISTENER, &xprt->xpt_flags)) {
+ /* Leave XPT_BUSY set on the dead xprt: */
+ goto out;
+ }
+ if (test_bit(XPT_LISTENER, &xprt->xpt_flags)) {
struct svc_xprt *newxpt;
newxpt = xprt->xpt_ops->xpo_accept(xprt);
if (newxpt) {
@@ -747,28 +738,23 @@ int svc_recv(struct svc_rqst *rqstp, long timeout)
spin_unlock_bh(&serv->sv_lock);
svc_xprt_received(newxpt);
}
- svc_xprt_received(xprt);
- } else {
+ } else if (xprt->xpt_ops->xpo_has_wspace(xprt)) {
dprintk("svc: server %p, pool %u, transport %p, inuse=%d\n",
rqstp, pool->sp_id, xprt,
atomic_read(&xprt->xpt_ref.refcount));
rqstp->rq_deferred = svc_deferred_dequeue(xprt);
- if (rqstp->rq_deferred) {
- svc_xprt_received(xprt);
+ if (rqstp->rq_deferred)
len = svc_deferred_recv(rqstp);
- } else {
+ else
len = xprt->xpt_ops->xpo_recvfrom(rqstp);
- svc_xprt_received(xprt);
- }
dprintk("svc: got len=%d\n", len);
}
+ svc_xprt_received(xprt);
/* No data, incomplete (TCP) read, or accept() */
- if (len == 0 || len == -EAGAIN) {
- rqstp->rq_res.len = 0;
- svc_xprt_release(rqstp);
- return -EAGAIN;
- }
+ if (len == 0 || len == -EAGAIN)
+ goto out;
+
clear_bit(XPT_OLD, &xprt->xpt_flags);
rqstp->rq_secure = svc_port_is_privileged(svc_addr(rqstp));
@@ -777,6 +763,10 @@ int svc_recv(struct svc_rqst *rqstp, long timeout)
if (serv->sv_stats)
serv->sv_stats->netcnt++;
return len;
+out:
+ rqstp->rq_res.len = 0;
+ svc_xprt_release(rqstp);
+ return -EAGAIN;
}
EXPORT_SYMBOL_GPL(svc_recv);
@@ -935,7 +925,12 @@ void svc_close_xprt(struct svc_xprt *xprt)
if (test_and_set_bit(XPT_BUSY, &xprt->xpt_flags))
/* someone else will have to effect the close */
return;
-
+ /*
+ * We expect svc_close_xprt() to work even when no threads are
+ * running (e.g., while configuring the server before starting
+ * any threads), so if the transport isn't busy, we delete
+ * it ourself:
+ */
svc_delete_xprt(xprt);
}
EXPORT_SYMBOL_GPL(svc_close_xprt);
@@ -945,16 +940,16 @@ void svc_close_all(struct list_head *xprt_list)
struct svc_xprt *xprt;
struct svc_xprt *tmp;
+ /*
+ * The server is shutting down, and no more threads are running.
+ * svc_xprt_enqueue() might still be running, but at worst it
+ * will re-add the xprt to sp_sockets, which will soon get
+ * freed. So we don't bother with any more locking, and don't
+ * leave the close to the (nonexistent) server threads:
+ */
list_for_each_entry_safe(xprt, tmp, xprt_list, xpt_list) {
set_bit(XPT_CLOSE, &xprt->xpt_flags);
- if (test_bit(XPT_BUSY, &xprt->xpt_flags)) {
- /* Waiting to be processed, but no threads left,
- * So just remove it from the waiting list
- */
- list_del_init(&xprt->xpt_ready);
- clear_bit(XPT_BUSY, &xprt->xpt_flags);
- }
- svc_close_xprt(xprt);
+ svc_delete_xprt(xprt);
}
}
@@ -1028,6 +1023,7 @@ static struct cache_deferred_req *svc_defer(struct cache_req *req)
}
svc_xprt_get(rqstp->rq_xprt);
dr->xprt = rqstp->rq_xprt;
+ rqstp->rq_dropme = true;
dr->handle.revisit = svc_revisit;
return &dr->handle;
@@ -1065,14 +1061,13 @@ static struct svc_deferred_req *svc_deferred_dequeue(struct svc_xprt *xprt)
if (!test_bit(XPT_DEFERRED, &xprt->xpt_flags))
return NULL;
spin_lock(&xprt->xpt_lock);
- clear_bit(XPT_DEFERRED, &xprt->xpt_flags);
if (!list_empty(&xprt->xpt_deferred)) {
dr = list_entry(xprt->xpt_deferred.next,
struct svc_deferred_req,
handle.recent);
list_del_init(&dr->handle.recent);
- set_bit(XPT_DEFERRED, &xprt->xpt_flags);
- }
+ } else
+ clear_bit(XPT_DEFERRED, &xprt->xpt_flags);
spin_unlock(&xprt->xpt_lock);
return dr;
}
diff --git a/net/sunrpc/svcauth.c b/net/sunrpc/svcauth.c
index 4e9393c..7963569 100644
--- a/net/sunrpc/svcauth.c
+++ b/net/sunrpc/svcauth.c
@@ -118,7 +118,6 @@ EXPORT_SYMBOL_GPL(svc_auth_unregister);
#define DN_HASHBITS 6
#define DN_HASHMAX (1<<DN_HASHBITS)
-#define DN_HASHMASK (DN_HASHMAX-1)
static struct hlist_head auth_domain_table[DN_HASHMAX];
static spinlock_t auth_domain_lock =
diff --git a/net/sunrpc/svcauth_unix.c b/net/sunrpc/svcauth_unix.c
index 560677d..30916b0 100644
--- a/net/sunrpc/svcauth_unix.c
+++ b/net/sunrpc/svcauth_unix.c
@@ -30,7 +30,9 @@
struct unix_domain {
struct auth_domain h;
+#ifdef CONFIG_NFSD_DEPRECATED
int addr_changes;
+#endif /* CONFIG_NFSD_DEPRECATED */
/* other stuff later */
};
@@ -64,7 +66,9 @@ struct auth_domain *unix_domain_find(char *name)
return NULL;
}
new->h.flavour = &svcauth_unix;
+#ifdef CONFIG_NFSD_DEPRECATED
new->addr_changes = 0;
+#endif /* CONFIG_NFSD_DEPRECATED */
rv = auth_domain_lookup(name, &new->h);
}
}
@@ -85,14 +89,15 @@ static void svcauth_unix_domain_release(struct auth_domain *dom)
*/
#define IP_HASHBITS 8
#define IP_HASHMAX (1<<IP_HASHBITS)
-#define IP_HASHMASK (IP_HASHMAX-1)
struct ip_map {
struct cache_head h;
char m_class[8]; /* e.g. "nfsd" */
struct in6_addr m_addr;
struct unix_domain *m_client;
+#ifdef CONFIG_NFSD_DEPRECATED
int m_add_change;
+#endif /* CONFIG_NFSD_DEPRECATED */
};
static void ip_map_put(struct kref *kref)
@@ -146,7 +151,9 @@ static void update(struct cache_head *cnew, struct cache_head *citem)
kref_get(&item->m_client->h.ref);
new->m_client = item->m_client;
+#ifdef CONFIG_NFSD_DEPRECATED
new->m_add_change = item->m_add_change;
+#endif /* CONFIG_NFSD_DEPRECATED */
}
static struct cache_head *ip_map_alloc(void)
{
@@ -331,6 +338,7 @@ static int __ip_map_update(struct cache_detail *cd, struct ip_map *ipm,
ip.h.flags = 0;
if (!udom)
set_bit(CACHE_NEGATIVE, &ip.h.flags);
+#ifdef CONFIG_NFSD_DEPRECATED
else {
ip.m_add_change = udom->addr_changes;
/* if this is from the legacy set_client system call,
@@ -339,6 +347,7 @@ static int __ip_map_update(struct cache_detail *cd, struct ip_map *ipm,
if (expiry == NEVER)
ip.m_add_change++;
}
+#endif /* CONFIG_NFSD_DEPRECATED */
ip.h.expiry_time = expiry;
ch = sunrpc_cache_update(cd, &ip.h, &ipm->h,
hash_str(ipm->m_class, IP_HASHBITS) ^
@@ -358,6 +367,7 @@ static inline int ip_map_update(struct net *net, struct ip_map *ipm,
return __ip_map_update(sn->ip_map_cache, ipm, udom, expiry);
}
+#ifdef CONFIG_NFSD_DEPRECATED
int auth_unix_add_addr(struct net *net, struct in6_addr *addr, struct auth_domain *dom)
{
struct unix_domain *udom;
@@ -402,8 +412,7 @@ struct auth_domain *auth_unix_lookup(struct net *net, struct in6_addr *addr)
return NULL;
if ((ipm->m_client->addr_changes - ipm->m_add_change) >0) {
- if (test_and_set_bit(CACHE_NEGATIVE, &ipm->h.flags) == 0)
- auth_domain_put(&ipm->m_client->h);
+ sunrpc_invalidate(&ipm->h, sn->ip_map_cache);
rv = NULL;
} else {
rv = &ipm->m_client->h;
@@ -413,6 +422,7 @@ struct auth_domain *auth_unix_lookup(struct net *net, struct in6_addr *addr)
return rv;
}
EXPORT_SYMBOL_GPL(auth_unix_lookup);
+#endif /* CONFIG_NFSD_DEPRECATED */
void svcauth_unix_purge(void)
{
@@ -497,7 +507,6 @@ svcauth_unix_info_release(struct svc_xprt *xpt)
*/
#define GID_HASHBITS 8
#define GID_HASHMAX (1<<GID_HASHBITS)
-#define GID_HASHMASK (GID_HASHMAX - 1)
struct unix_gid {
struct cache_head h;
diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c
index d265aa7..7bd3bbb 100644
--- a/net/sunrpc/svcsock.c
+++ b/net/sunrpc/svcsock.c
@@ -331,19 +331,21 @@ int svc_sock_names(struct svc_serv *serv, char *buf, const size_t buflen,
len = onelen;
break;
}
- if (toclose && strcmp(toclose, buf + len) == 0)
+ if (toclose && strcmp(toclose, buf + len) == 0) {
closesk = svsk;
- else
+ svc_xprt_get(&closesk->sk_xprt);
+ } else
len += onelen;
}
spin_unlock_bh(&serv->sv_lock);
- if (closesk)
+ if (closesk) {
/* Should unregister with portmap, but you cannot
* unregister just one protocol...
*/
svc_close_xprt(&closesk->sk_xprt);
- else if (toclose)
+ svc_xprt_put(&closesk->sk_xprt);
+ } else if (toclose)
return -ENOENT;
return len;
}
@@ -992,15 +994,17 @@ static int svc_process_calldir(struct svc_sock *svsk, struct svc_rqst *rqstp,
vec[0] = rqstp->rq_arg.head[0];
} else {
/* REPLY */
- if (svsk->sk_bc_xprt)
- req = xprt_lookup_rqst(svsk->sk_bc_xprt, xid);
+ struct rpc_xprt *bc_xprt = svsk->sk_xprt.xpt_bc_xprt;
+
+ if (bc_xprt)
+ req = xprt_lookup_rqst(bc_xprt, xid);
if (!req) {
printk(KERN_NOTICE
"%s: Got unrecognized reply: "
- "calldir 0x%x sk_bc_xprt %p xid %08x\n",
+ "calldir 0x%x xpt_bc_xprt %p xid %08x\n",
__func__, ntohl(calldir),
- svsk->sk_bc_xprt, xid);
+ bc_xprt, xid);
vec[0] = rqstp->rq_arg.head[0];
goto out;
}
diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c
index 4c8f18a..856274d 100644
--- a/net/sunrpc/xprt.c
+++ b/net/sunrpc/xprt.c
@@ -965,6 +965,7 @@ struct rpc_xprt *xprt_alloc(struct net *net, int size, int max_req)
xprt = kzalloc(size, GFP_KERNEL);
if (xprt == NULL)
goto out;
+ kref_init(&xprt->kref);
xprt->max_reqs = max_req;
xprt->slot = kcalloc(max_req, sizeof(struct rpc_rqst), GFP_KERNEL);
@@ -1101,8 +1102,10 @@ found:
-PTR_ERR(xprt));
return xprt;
}
+ if (test_and_set_bit(XPRT_INITIALIZED, &xprt->state))
+ /* ->setup returned a pre-initialized xprt: */
+ return xprt;
- kref_init(&xprt->kref);
spin_lock_init(&xprt->transport_lock);
spin_lock_init(&xprt->reserve_lock);
diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c
index 96549df..c431f5a 100644
--- a/net/sunrpc/xprtsock.c
+++ b/net/sunrpc/xprtsock.c
@@ -2359,6 +2359,15 @@ static struct rpc_xprt *xs_setup_bc_tcp(struct xprt_create *args)
struct svc_sock *bc_sock;
struct rpc_xprt *ret;
+ if (args->bc_xprt->xpt_bc_xprt) {
+ /*
+ * This server connection already has a backchannel
+ * export; we can't create a new one, as we wouldn't be
+ * able to match replies based on xid any more. So,
+ * reuse the already-existing one:
+ */
+ return args->bc_xprt->xpt_bc_xprt;
+ }
xprt = xs_setup_xprt(args, xprt_tcp_slot_table_entries);
if (IS_ERR(xprt))
return xprt;
@@ -2375,16 +2384,6 @@ static struct rpc_xprt *xs_setup_bc_tcp(struct xprt_create *args)
xprt->reestablish_timeout = 0;
xprt->idle_timeout = 0;
- /*
- * The backchannel uses the same socket connection as the
- * forechannel
- */
- xprt->bc_xprt = args->bc_xprt;
- bc_sock = container_of(args->bc_xprt, struct svc_sock, sk_xprt);
- bc_sock->sk_bc_xprt = xprt;
- transport->sock = bc_sock->sk_sock;
- transport->inet = bc_sock->sk_sk;
-
xprt->ops = &bc_tcp_ops;
switch (addr->sa_family) {
@@ -2407,6 +2406,20 @@ static struct rpc_xprt *xs_setup_bc_tcp(struct xprt_create *args)
xprt->address_strings[RPC_DISPLAY_PROTO]);
/*
+ * Once we've associated a backchannel xprt with a connection,
+ * we want to keep it around as long as long as the connection
+ * lasts, in case we need to start using it for a backchannel
+ * again; this reference won't be dropped until bc_xprt is
+ * destroyed.
+ */
+ xprt_get(xprt);
+ args->bc_xprt->xpt_bc_xprt = xprt;
+ xprt->bc_xprt = args->bc_xprt;
+ bc_sock = container_of(args->bc_xprt, struct svc_sock, sk_xprt);
+ transport->sock = bc_sock->sk_sock;
+ transport->inet = bc_sock->sk_sk;
+
+ /*
* Since we don't want connections for the backchannel, we set
* the xprt status to connected
*/
@@ -2415,6 +2428,7 @@ static struct rpc_xprt *xs_setup_bc_tcp(struct xprt_create *args)
if (try_module_get(THIS_MODULE))
return xprt;
+ xprt_put(xprt);
ret = ERR_PTR(-EINVAL);
out_err:
xprt_free(xprt);
diff --git a/net/wireless/Kconfig b/net/wireless/Kconfig
index d0ee290..1f1ef70 100644
--- a/net/wireless/Kconfig
+++ b/net/wireless/Kconfig
@@ -95,7 +95,7 @@ config CFG80211_DEBUGFS
If unsure, say N.
config CFG80211_INTERNAL_REGDB
- bool "use statically compiled regulatory rules database" if EMBEDDED
+ bool "use statically compiled regulatory rules database" if EXPERT
default n
depends on CFG80211
---help---
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
index d5e1e0b..6129196 100644
--- a/net/xfrm/xfrm_user.c
+++ b/net/xfrm/xfrm_user.c
@@ -2189,7 +2189,7 @@ static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
if ((type == (XFRM_MSG_GETSA - XFRM_MSG_BASE) ||
type == (XFRM_MSG_GETPOLICY - XFRM_MSG_BASE)) &&
- (nlh->nlmsg_flags & NLM_F_DUMP) == NLM_F_DUMP) {
+ (nlh->nlmsg_flags & NLM_F_DUMP)) {
if (link->dump == NULL)
return -EINVAL;
diff --git a/security/keys/Makefile b/security/keys/Makefile
index 6c94105..1bf090a 100644
--- a/security/keys/Makefile
+++ b/security/keys/Makefile
@@ -13,8 +13,8 @@ obj-y := \
request_key_auth.o \
user_defined.o
-obj-$(CONFIG_TRUSTED_KEYS) += trusted_defined.o
-obj-$(CONFIG_ENCRYPTED_KEYS) += encrypted_defined.o
+obj-$(CONFIG_TRUSTED_KEYS) += trusted.o
+obj-$(CONFIG_ENCRYPTED_KEYS) += encrypted.o
obj-$(CONFIG_KEYS_COMPAT) += compat.o
obj-$(CONFIG_PROC_FS) += proc.o
obj-$(CONFIG_SYSCTL) += sysctl.o
diff --git a/security/keys/compat.c b/security/keys/compat.c
index 792c0a6..07a5f35 100644
--- a/security/keys/compat.c
+++ b/security/keys/compat.c
@@ -1,4 +1,4 @@
-/* compat.c: 32-bit compatibility syscall for 64-bit systems
+/* 32-bit compatibility syscall for 64-bit systems
*
* Copyright (C) 2004-5 Red Hat, Inc. All Rights Reserved.
* Written by David Howells (dhowells@redhat.com)
@@ -14,13 +14,13 @@
#include <linux/compat.h>
#include "internal.h"
-/*****************************************************************************/
/*
- * the key control system call, 32-bit compatibility version for 64-bit archs
- * - this should only be called if the 64-bit arch uses weird pointers in
- * 32-bit mode or doesn't guarantee that the top 32-bits of the argument
- * registers on taking a 32-bit syscall are zero
- * - if you can, you should call sys_keyctl directly
+ * The key control system call, 32-bit compatibility version for 64-bit archs
+ *
+ * This should only be called if the 64-bit arch uses weird pointers in 32-bit
+ * mode or doesn't guarantee that the top 32-bits of the argument registers on
+ * taking a 32-bit syscall are zero. If you can, you should call sys_keyctl()
+ * directly.
*/
asmlinkage long compat_sys_keyctl(u32 option,
u32 arg2, u32 arg3, u32 arg4, u32 arg5)
@@ -88,5 +88,4 @@ asmlinkage long compat_sys_keyctl(u32 option,
default:
return -EOPNOTSUPP;
}
-
-} /* end compat_sys_keyctl() */
+}
diff --git a/security/keys/encrypted_defined.c b/security/keys/encrypted.c
index 32d27c8..9e7e4ce 100644
--- a/security/keys/encrypted_defined.c
+++ b/security/keys/encrypted.c
@@ -30,7 +30,7 @@
#include <crypto/sha.h>
#include <crypto/aes.h>
-#include "encrypted_defined.h"
+#include "encrypted.h"
static const char KEY_TRUSTED_PREFIX[] = "trusted:";
static const char KEY_USER_PREFIX[] = "user:";
diff --git a/security/keys/encrypted_defined.h b/security/keys/encrypted.h
index cef5e2f..cef5e2f 100644
--- a/security/keys/encrypted_defined.h
+++ b/security/keys/encrypted.h
diff --git a/security/keys/gc.c b/security/keys/gc.c
index a46e825..89df6b5 100644
--- a/security/keys/gc.c
+++ b/security/keys/gc.c
@@ -32,8 +32,8 @@ static time_t key_gc_next_run = LONG_MAX;
static time_t key_gc_new_timer;
/*
- * Schedule a garbage collection run
- * - precision isn't particularly important
+ * Schedule a garbage collection run.
+ * - time precision isn't particularly important
*/
void key_schedule_gc(time_t gc_at)
{
@@ -61,8 +61,9 @@ static void key_gc_timer_func(unsigned long data)
}
/*
- * Garbage collect pointers from a keyring
- * - return true if we altered the keyring
+ * Garbage collect pointers from a keyring.
+ *
+ * Return true if we altered the keyring.
*/
static bool key_gc_keyring(struct key *keyring, time_t limit)
__releases(key_serial_lock)
@@ -107,9 +108,8 @@ do_gc:
}
/*
- * Garbage collector for keys
- * - this involves scanning the keyrings for dead, expired and revoked keys
- * that have overstayed their welcome
+ * Garbage collector for keys. This involves scanning the keyrings for dead,
+ * expired and revoked keys that have overstayed their welcome
*/
static void key_garbage_collector(struct work_struct *work)
{
diff --git a/security/keys/internal.h b/security/keys/internal.h
index 56a133d..a52aa7c 100644
--- a/security/keys/internal.h
+++ b/security/keys/internal.h
@@ -1,4 +1,4 @@
-/* internal.h: authentication token and access key management internal defs
+/* Authentication token and access key management internal defs
*
* Copyright (C) 2003-5, 2007 Red Hat, Inc. All Rights Reserved.
* Written by David Howells (dhowells@redhat.com)
@@ -35,10 +35,12 @@ extern struct key_type key_type_user;
/*****************************************************************************/
/*
- * keep track of keys for a user
- * - this needs to be separate to user_struct to avoid a refcount-loop
- * (user_struct pins some keyrings which pin this struct)
- * - this also keeps track of keys under request from userspace for this UID
+ * Keep track of keys for a user.
+ *
+ * This needs to be separate to user_struct to avoid a refcount-loop
+ * (user_struct pins some keyrings which pin this struct).
+ *
+ * We also keep track of keys under request from userspace for this UID here.
*/
struct key_user {
struct rb_node node;
@@ -62,7 +64,7 @@ extern struct key_user *key_user_lookup(uid_t uid,
extern void key_user_put(struct key_user *user);
/*
- * key quota limits
+ * Key quota limits.
* - root has its own separate limits to everyone else
*/
extern unsigned key_quota_root_maxkeys;
@@ -85,13 +87,13 @@ extern void key_type_put(struct key_type *ktype);
extern int __key_link_begin(struct key *keyring,
const struct key_type *type,
const char *description,
- struct keyring_list **_prealloc);
+ unsigned long *_prealloc);
extern int __key_link_check_live_key(struct key *keyring, struct key *key);
extern void __key_link(struct key *keyring, struct key *key,
- struct keyring_list **_prealloc);
+ unsigned long *_prealloc);
extern void __key_link_end(struct key *keyring,
struct key_type *type,
- struct keyring_list *prealloc);
+ unsigned long prealloc);
extern key_ref_t __keyring_search_one(key_ref_t keyring_ref,
const struct key_type *type,
@@ -146,13 +148,13 @@ extern unsigned key_gc_delay;
extern void keyring_gc(struct key *keyring, time_t limit);
extern void key_schedule_gc(time_t expiry_at);
-/*
- * check to see whether permission is granted to use a key in the desired way
- */
extern int key_task_permission(const key_ref_t key_ref,
const struct cred *cred,
key_perm_t perm);
+/*
+ * Check to see whether permission is granted to use a key in the desired way.
+ */
static inline int key_permission(const key_ref_t key_ref, key_perm_t perm)
{
return key_task_permission(key_ref, current_cred(), perm);
@@ -168,7 +170,7 @@ static inline int key_permission(const key_ref_t key_ref, key_perm_t perm)
#define KEY_ALL 0x3f /* all the above permissions */
/*
- * request_key authorisation
+ * Authorisation record for request_key().
*/
struct request_key_auth {
struct key *target_key;
@@ -188,7 +190,7 @@ extern struct key *request_key_auth_new(struct key *target,
extern struct key *key_get_instantiation_authkey(key_serial_t target_id);
/*
- * keyctl functions
+ * keyctl() functions
*/
extern long keyctl_get_keyring_ID(key_serial_t, int);
extern long keyctl_join_session_keyring(const char __user *);
@@ -214,7 +216,7 @@ extern long keyctl_get_security(key_serial_t keyid, char __user *buffer,
extern long keyctl_session_to_parent(void);
/*
- * debugging key validation
+ * Debugging key validation
*/
#ifdef KEY_DEBUGGING
extern void __key_check(const struct key *);
diff --git a/security/keys/key.c b/security/keys/key.c
index c1eac80..1c2d43d 100644
--- a/security/keys/key.c
+++ b/security/keys/key.c
@@ -39,10 +39,10 @@ static DECLARE_RWSEM(key_types_sem);
static void key_cleanup(struct work_struct *work);
static DECLARE_WORK(key_cleanup_task, key_cleanup);
-/* we serialise key instantiation and link */
+/* We serialise key instantiation and link */
DEFINE_MUTEX(key_construction_mutex);
-/* any key who's type gets unegistered will be re-typed to this */
+/* Any key who's type gets unegistered will be re-typed to this */
static struct key_type key_type_dead = {
.name = "dead",
};
@@ -56,10 +56,9 @@ void __key_check(const struct key *key)
}
#endif
-/*****************************************************************************/
/*
- * get the key quota record for a user, allocating a new record if one doesn't
- * already exist
+ * Get the key quota record for a user, allocating a new record if one doesn't
+ * already exist.
*/
struct key_user *key_user_lookup(uid_t uid, struct user_namespace *user_ns)
{
@@ -67,7 +66,7 @@ struct key_user *key_user_lookup(uid_t uid, struct user_namespace *user_ns)
struct rb_node *parent = NULL;
struct rb_node **p;
- try_again:
+try_again:
p = &key_user_tree.rb_node;
spin_lock(&key_user_lock);
@@ -124,18 +123,16 @@ struct key_user *key_user_lookup(uid_t uid, struct user_namespace *user_ns)
goto out;
/* okay - we found a user record for this UID */
- found:
+found:
atomic_inc(&user->usage);
spin_unlock(&key_user_lock);
kfree(candidate);
- out:
+out:
return user;
+}
-} /* end key_user_lookup() */
-
-/*****************************************************************************/
/*
- * dispose of a user structure
+ * Dispose of a user structure
*/
void key_user_put(struct key_user *user)
{
@@ -146,14 +143,11 @@ void key_user_put(struct key_user *user)
kfree(user);
}
+}
-} /* end key_user_put() */
-
-/*****************************************************************************/
/*
- * assign a key the next unique serial number
- * - these are assigned randomly to avoid security issues through covert
- * channel problems
+ * Allocate a serial number for a key. These are assigned randomly to avoid
+ * security issues through covert channel problems.
*/
static inline void key_alloc_serial(struct key *key)
{
@@ -211,18 +205,36 @@ serial_exists:
if (key->serial < xkey->serial)
goto attempt_insertion;
}
+}
-} /* end key_alloc_serial() */
-
-/*****************************************************************************/
-/*
- * allocate a key of the specified type
- * - update the user's quota to reflect the existence of the key
- * - called from a key-type operation with key_types_sem read-locked by
- * key_create_or_update()
- * - this prevents unregistration of the key type
- * - upon return the key is as yet uninstantiated; the caller needs to either
- * instantiate the key or discard it before returning
+/**
+ * key_alloc - Allocate a key of the specified type.
+ * @type: The type of key to allocate.
+ * @desc: The key description to allow the key to be searched out.
+ * @uid: The owner of the new key.
+ * @gid: The group ID for the new key's group permissions.
+ * @cred: The credentials specifying UID namespace.
+ * @perm: The permissions mask of the new key.
+ * @flags: Flags specifying quota properties.
+ *
+ * Allocate a key of the specified type with the attributes given. The key is
+ * returned in an uninstantiated state and the caller needs to instantiate the
+ * key before returning.
+ *
+ * The user's key count quota is updated to reflect the creation of the key and
+ * the user's key data quota has the default for the key type reserved. The
+ * instantiation function should amend this as necessary. If insufficient
+ * quota is available, -EDQUOT will be returned.
+ *
+ * The LSM security modules can prevent a key being created, in which case
+ * -EACCES will be returned.
+ *
+ * Returns a pointer to the new key if successful and an error code otherwise.
+ *
+ * Note that the caller needs to ensure the key type isn't uninstantiated.
+ * Internally this can be done by locking key_types_sem. Externally, this can
+ * be done by either never unregistering the key type, or making sure
+ * key_alloc() calls don't race with module unloading.
*/
struct key *key_alloc(struct key_type *type, const char *desc,
uid_t uid, gid_t gid, const struct cred *cred,
@@ -344,14 +356,19 @@ no_quota:
key_user_put(user);
key = ERR_PTR(-EDQUOT);
goto error;
-
-} /* end key_alloc() */
-
+}
EXPORT_SYMBOL(key_alloc);
-/*****************************************************************************/
-/*
- * reserve an amount of quota for the key's payload
+/**
+ * key_payload_reserve - Adjust data quota reservation for the key's payload
+ * @key: The key to make the reservation for.
+ * @datalen: The amount of data payload the caller now wants.
+ *
+ * Adjust the amount of the owning user's key data quota that a key reserves.
+ * If the amount is increased, then -EDQUOT may be returned if there isn't
+ * enough free quota available.
+ *
+ * If successful, 0 is returned.
*/
int key_payload_reserve(struct key *key, size_t datalen)
{
@@ -384,22 +401,21 @@ int key_payload_reserve(struct key *key, size_t datalen)
key->datalen = datalen;
return ret;
-
-} /* end key_payload_reserve() */
-
+}
EXPORT_SYMBOL(key_payload_reserve);
-/*****************************************************************************/
/*
- * instantiate a key and link it into the target keyring atomically
- * - called with the target keyring's semaphore writelocked
+ * Instantiate a key and link it into the target keyring atomically. Must be
+ * called with the target keyring's semaphore writelocked. The target key's
+ * semaphore need not be locked as instantiation is serialised by
+ * key_construction_mutex.
*/
static int __key_instantiate_and_link(struct key *key,
const void *data,
size_t datalen,
struct key *keyring,
struct key *authkey,
- struct keyring_list **_prealloc)
+ unsigned long *_prealloc)
{
int ret, awaken;
@@ -441,12 +457,23 @@ static int __key_instantiate_and_link(struct key *key,
wake_up_bit(&key->flags, KEY_FLAG_USER_CONSTRUCT);
return ret;
+}
-} /* end __key_instantiate_and_link() */
-
-/*****************************************************************************/
-/*
- * instantiate a key and link it into the target keyring atomically
+/**
+ * key_instantiate_and_link - Instantiate a key and link it into the keyring.
+ * @key: The key to instantiate.
+ * @data: The data to use to instantiate the keyring.
+ * @datalen: The length of @data.
+ * @keyring: Keyring to create a link in on success (or NULL).
+ * @authkey: The authorisation token permitting instantiation.
+ *
+ * Instantiate a key that's in the uninstantiated state using the provided data
+ * and, if successful, link it in to the destination keyring if one is
+ * supplied.
+ *
+ * If successful, 0 is returned, the authorisation token is revoked and anyone
+ * waiting for the key is woken up. If the key was already instantiated,
+ * -EBUSY will be returned.
*/
int key_instantiate_and_link(struct key *key,
const void *data,
@@ -454,7 +481,7 @@ int key_instantiate_and_link(struct key *key,
struct key *keyring,
struct key *authkey)
{
- struct keyring_list *prealloc;
+ unsigned long prealloc;
int ret;
if (keyring) {
@@ -471,21 +498,35 @@ int key_instantiate_and_link(struct key *key,
__key_link_end(keyring, key->type, prealloc);
return ret;
-
-} /* end key_instantiate_and_link() */
+}
EXPORT_SYMBOL(key_instantiate_and_link);
-/*****************************************************************************/
-/*
- * negatively instantiate a key and link it into the target keyring atomically
+/**
+ * key_negate_and_link - Negatively instantiate a key and link it into the keyring.
+ * @key: The key to instantiate.
+ * @timeout: The timeout on the negative key.
+ * @keyring: Keyring to create a link in on success (or NULL).
+ * @authkey: The authorisation token permitting instantiation.
+ *
+ * Negatively instantiate a key that's in the uninstantiated state and, if
+ * successful, set its timeout and link it in to the destination keyring if one
+ * is supplied. The key and any links to the key will be automatically garbage
+ * collected after the timeout expires.
+ *
+ * Negative keys are used to rate limit repeated request_key() calls by causing
+ * them to return -ENOKEY until the negative key expires.
+ *
+ * If successful, 0 is returned, the authorisation token is revoked and anyone
+ * waiting for the key is woken up. If the key was already instantiated,
+ * -EBUSY will be returned.
*/
int key_negate_and_link(struct key *key,
unsigned timeout,
struct key *keyring,
struct key *authkey)
{
- struct keyring_list *prealloc;
+ unsigned long prealloc;
struct timespec now;
int ret, awaken, link_ret = 0;
@@ -535,22 +576,23 @@ int key_negate_and_link(struct key *key,
wake_up_bit(&key->flags, KEY_FLAG_USER_CONSTRUCT);
return ret == 0 ? link_ret : ret;
-
-} /* end key_negate_and_link() */
+}
EXPORT_SYMBOL(key_negate_and_link);
-/*****************************************************************************/
/*
- * do cleaning up in process context so that we don't have to disable
- * interrupts all over the place
+ * Garbage collect keys in process context so that we don't have to disable
+ * interrupts all over the place.
+ *
+ * key_put() schedules this rather than trying to do the cleanup itself, which
+ * means key_put() doesn't have to sleep.
*/
static void key_cleanup(struct work_struct *work)
{
struct rb_node *_n;
struct key *key;
- go_again:
+go_again:
/* look for a dead key in the tree */
spin_lock(&key_serial_lock);
@@ -564,7 +606,7 @@ static void key_cleanup(struct work_struct *work)
spin_unlock(&key_serial_lock);
return;
- found_dead_key:
+found_dead_key:
/* we found a dead key - once we've removed it from the tree, we can
* drop the lock */
rb_erase(&key->serial_node, &key_serial_tree);
@@ -601,14 +643,15 @@ static void key_cleanup(struct work_struct *work)
/* there may, of course, be more than one key to destroy */
goto go_again;
+}
-} /* end key_cleanup() */
-
-/*****************************************************************************/
-/*
- * dispose of a reference to a key
- * - when all the references are gone, we schedule the cleanup task to come and
- * pull it out of the tree in definite process context
+/**
+ * key_put - Discard a reference to a key.
+ * @key: The key to discard a reference from.
+ *
+ * Discard a reference to a key, and when all the references are gone, we
+ * schedule the cleanup task to come and pull it out of the tree in process
+ * context at some later time.
*/
void key_put(struct key *key)
{
@@ -618,14 +661,11 @@ void key_put(struct key *key)
if (atomic_dec_and_test(&key->usage))
schedule_work(&key_cleanup_task);
}
-
-} /* end key_put() */
-
+}
EXPORT_SYMBOL(key_put);
-/*****************************************************************************/
/*
- * find a key by its serial number
+ * Find a key by its serial number.
*/
struct key *key_lookup(key_serial_t id)
{
@@ -647,11 +687,11 @@ struct key *key_lookup(key_serial_t id)
goto found;
}
- not_found:
+not_found:
key = ERR_PTR(-ENOKEY);
goto error;
- found:
+found:
/* pretend it doesn't exist if it is awaiting deletion */
if (atomic_read(&key->usage) == 0)
goto not_found;
@@ -661,16 +701,16 @@ struct key *key_lookup(key_serial_t id)
*/
atomic_inc(&key->usage);
- error:
+error:
spin_unlock(&key_serial_lock);
return key;
+}
-} /* end key_lookup() */
-
-/*****************************************************************************/
/*
- * find and lock the specified key type against removal
- * - we return with the sem readlocked
+ * Find and lock the specified key type against removal.
+ *
+ * We return with the sem read-locked if successful. If the type wasn't
+ * available -ENOKEY is returned instead.
*/
struct key_type *key_type_lookup(const char *type)
{
@@ -688,26 +728,23 @@ struct key_type *key_type_lookup(const char *type)
up_read(&key_types_sem);
ktype = ERR_PTR(-ENOKEY);
- found_kernel_type:
+found_kernel_type:
return ktype;
+}
-} /* end key_type_lookup() */
-
-/*****************************************************************************/
/*
- * unlock a key type
+ * Unlock a key type locked by key_type_lookup().
*/
void key_type_put(struct key_type *ktype)
{
up_read(&key_types_sem);
+}
-} /* end key_type_put() */
-
-/*****************************************************************************/
/*
- * attempt to update an existing key
- * - the key has an incremented refcount
- * - we need to put the key if we get an error
+ * Attempt to update an existing key.
+ *
+ * The key is given to us with an incremented refcount that we need to discard
+ * if we get an error.
*/
static inline key_ref_t __key_update(key_ref_t key_ref,
const void *payload, size_t plen)
@@ -742,13 +779,32 @@ error:
key_put(key);
key_ref = ERR_PTR(ret);
goto out;
+}
-} /* end __key_update() */
-
-/*****************************************************************************/
-/*
- * search the specified keyring for a key of the same description; if one is
- * found, update it, otherwise add a new one
+/**
+ * key_create_or_update - Update or create and instantiate a key.
+ * @keyring_ref: A pointer to the destination keyring with possession flag.
+ * @type: The type of key.
+ * @description: The searchable description for the key.
+ * @payload: The data to use to instantiate or update the key.
+ * @plen: The length of @payload.
+ * @perm: The permissions mask for a new key.
+ * @flags: The quota flags for a new key.
+ *
+ * Search the destination keyring for a key of the same description and if one
+ * is found, update it, otherwise create and instantiate a new one and create a
+ * link to it from that keyring.
+ *
+ * If perm is KEY_PERM_UNDEF then an appropriate key permissions mask will be
+ * concocted.
+ *
+ * Returns a pointer to the new key if successful, -ENODEV if the key type
+ * wasn't available, -ENOTDIR if the keyring wasn't a keyring, -EACCES if the
+ * caller isn't permitted to modify the keyring or the LSM did not permit
+ * creation of the key.
+ *
+ * On success, the possession flag from the keyring ref will be tacked on to
+ * the key ref before it is returned.
*/
key_ref_t key_create_or_update(key_ref_t keyring_ref,
const char *type,
@@ -758,7 +814,7 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
key_perm_t perm,
unsigned long flags)
{
- struct keyring_list *prealloc;
+ unsigned long prealloc;
const struct cred *cred = current_cred();
struct key_type *ktype;
struct key *keyring, *key = NULL;
@@ -855,14 +911,21 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
key_ref = __key_update(key_ref, payload, plen);
goto error;
-
-} /* end key_create_or_update() */
-
+}
EXPORT_SYMBOL(key_create_or_update);
-/*****************************************************************************/
-/*
- * update a key
+/**
+ * key_update - Update a key's contents.
+ * @key_ref: The pointer (plus possession flag) to the key.
+ * @payload: The data to be used to update the key.
+ * @plen: The length of @payload.
+ *
+ * Attempt to update the contents of a key with the given payload data. The
+ * caller must be granted Write permission on the key. Negative keys can be
+ * instantiated by this method.
+ *
+ * Returns 0 on success, -EACCES if not permitted and -EOPNOTSUPP if the key
+ * type does not support updating. The key type may return other errors.
*/
int key_update(key_ref_t key_ref, const void *payload, size_t plen)
{
@@ -891,14 +954,17 @@ int key_update(key_ref_t key_ref, const void *payload, size_t plen)
error:
return ret;
-
-} /* end key_update() */
-
+}
EXPORT_SYMBOL(key_update);
-/*****************************************************************************/
-/*
- * revoke a key
+/**
+ * key_revoke - Revoke a key.
+ * @key: The key to be revoked.
+ *
+ * Mark a key as being revoked and ask the type to free up its resources. The
+ * revocation timeout is set and the key and all its links will be
+ * automatically garbage collected after key_gc_delay amount of time if they
+ * are not manually dealt with first.
*/
void key_revoke(struct key *key)
{
@@ -926,14 +992,16 @@ void key_revoke(struct key *key)
}
up_write(&key->sem);
-
-} /* end key_revoke() */
-
+}
EXPORT_SYMBOL(key_revoke);
-/*****************************************************************************/
-/*
- * register a type of key
+/**
+ * register_key_type - Register a type of key.
+ * @ktype: The new key type.
+ *
+ * Register a new key type.
+ *
+ * Returns 0 on success or -EEXIST if a type of this name already exists.
*/
int register_key_type(struct key_type *ktype)
{
@@ -953,17 +1021,19 @@ int register_key_type(struct key_type *ktype)
list_add(&ktype->link, &key_types_list);
ret = 0;
- out:
+out:
up_write(&key_types_sem);
return ret;
-
-} /* end register_key_type() */
-
+}
EXPORT_SYMBOL(register_key_type);
-/*****************************************************************************/
-/*
- * unregister a type of key
+/**
+ * unregister_key_type - Unregister a type of key.
+ * @ktype: The key type.
+ *
+ * Unregister a key type and mark all the extant keys of this type as dead.
+ * Those keys of this type are then destroyed to get rid of their payloads and
+ * they and their links will be garbage collected as soon as possible.
*/
void unregister_key_type(struct key_type *ktype)
{
@@ -1010,14 +1080,11 @@ void unregister_key_type(struct key_type *ktype)
up_write(&key_types_sem);
key_schedule_gc(0);
-
-} /* end unregister_key_type() */
-
+}
EXPORT_SYMBOL(unregister_key_type);
-/*****************************************************************************/
/*
- * initialise the key management stuff
+ * Initialise the key management state.
*/
void __init key_init(void)
{
@@ -1037,5 +1104,4 @@ void __init key_init(void)
rb_insert_color(&root_key_user.node,
&key_user_tree);
-
-} /* end key_init() */
+}
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c
index 60924f6..31a0fd8 100644
--- a/security/keys/keyctl.c
+++ b/security/keys/keyctl.c
@@ -1,4 +1,4 @@
-/* keyctl.c: userspace keyctl operations
+/* Userspace key control operations
*
* Copyright (C) 2004-5 Red Hat, Inc. All Rights Reserved.
* Written by David Howells (dhowells@redhat.com)
@@ -31,28 +31,24 @@ static int key_get_type_from_user(char *type,
int ret;
ret = strncpy_from_user(type, _type, len);
-
if (ret < 0)
return ret;
-
if (ret == 0 || ret >= len)
return -EINVAL;
-
if (type[0] == '.')
return -EPERM;
-
type[len - 1] = '\0';
-
return 0;
}
-/*****************************************************************************/
/*
- * extract the description of a new key from userspace and either add it as a
- * new key to the specified keyring or update a matching key in that keyring
- * - the keyring must be writable
- * - returns the new key's serial number
- * - implements add_key()
+ * Extract the description of a new key from userspace and either add it as a
+ * new key to the specified keyring or update a matching key in that keyring.
+ *
+ * The keyring must be writable so that we can attach the key to it.
+ *
+ * If successful, the new key's serial number is returned, otherwise an error
+ * code is returned.
*/
SYSCALL_DEFINE5(add_key, const char __user *, _type,
const char __user *, _description,
@@ -132,19 +128,20 @@ SYSCALL_DEFINE5(add_key, const char __user *, _type,
kfree(description);
error:
return ret;
+}
-} /* end sys_add_key() */
-
-/*****************************************************************************/
/*
- * search the process keyrings for a matching key
- * - nested keyrings may also be searched if they have Search permission
- * - if a key is found, it will be attached to the destination keyring if
- * there's one specified
- * - /sbin/request-key will be invoked if _callout_info is non-NULL
- * - the _callout_info string will be passed to /sbin/request-key
- * - if the _callout_info string is empty, it will be rendered as "-"
- * - implements request_key()
+ * Search the process keyrings and keyring trees linked from those for a
+ * matching key. Keyrings must have appropriate Search permission to be
+ * searched.
+ *
+ * If a key is found, it will be attached to the destination keyring if there's
+ * one specified and the serial number of the key will be returned.
+ *
+ * If no key is found, /sbin/request-key will be invoked if _callout_info is
+ * non-NULL in an attempt to create a key. The _callout_info string will be
+ * passed to /sbin/request-key to aid with completing the request. If the
+ * _callout_info string is "" then it will be changed to "-".
*/
SYSCALL_DEFINE4(request_key, const char __user *, _type,
const char __user *, _description,
@@ -222,14 +219,14 @@ error2:
kfree(description);
error:
return ret;
+}
-} /* end sys_request_key() */
-
-/*****************************************************************************/
/*
- * get the ID of the specified process keyring
- * - the keyring must have search permission to be found
- * - implements keyctl(KEYCTL_GET_KEYRING_ID)
+ * Get the ID of the specified process keyring.
+ *
+ * The requested keyring must have search permission to be found.
+ *
+ * If successful, the ID of the requested keyring will be returned.
*/
long keyctl_get_keyring_ID(key_serial_t id, int create)
{
@@ -248,13 +245,17 @@ long keyctl_get_keyring_ID(key_serial_t id, int create)
key_ref_put(key_ref);
error:
return ret;
+}
-} /* end keyctl_get_keyring_ID() */
-
-/*****************************************************************************/
/*
- * join the session keyring
- * - implements keyctl(KEYCTL_JOIN_SESSION_KEYRING)
+ * Join a (named) session keyring.
+ *
+ * Create and join an anonymous session keyring or join a named session
+ * keyring, creating it if necessary. A named session keyring must have Search
+ * permission for it to be joined. Session keyrings without this permit will
+ * be skipped over.
+ *
+ * If successful, the ID of the joined session keyring will be returned.
*/
long keyctl_join_session_keyring(const char __user *_name)
{
@@ -277,14 +278,17 @@ long keyctl_join_session_keyring(const char __user *_name)
error:
return ret;
+}
-} /* end keyctl_join_session_keyring() */
-
-/*****************************************************************************/
/*
- * update a key's data payload
- * - the key must be writable
- * - implements keyctl(KEYCTL_UPDATE)
+ * Update a key's data payload from the given data.
+ *
+ * The key must grant the caller Write permission and the key type must support
+ * updating for this to work. A negative key can be positively instantiated
+ * with this call.
+ *
+ * If successful, 0 will be returned. If the key type does not support
+ * updating, then -EOPNOTSUPP will be returned.
*/
long keyctl_update_key(key_serial_t id,
const void __user *_payload,
@@ -326,14 +330,17 @@ error2:
kfree(payload);
error:
return ret;
+}
-} /* end keyctl_update_key() */
-
-/*****************************************************************************/
/*
- * revoke a key
- * - the key must be writable
- * - implements keyctl(KEYCTL_REVOKE)
+ * Revoke a key.
+ *
+ * The key must be grant the caller Write or Setattr permission for this to
+ * work. The key type should give up its quota claim when revoked. The key
+ * and any links to the key will be automatically garbage collected after a
+ * certain amount of time (/proc/sys/kernel/keys/gc_delay).
+ *
+ * If successful, 0 is returned.
*/
long keyctl_revoke_key(key_serial_t id)
{
@@ -358,14 +365,14 @@ long keyctl_revoke_key(key_serial_t id)
key_ref_put(key_ref);
error:
return ret;
+}
-} /* end keyctl_revoke_key() */
-
-/*****************************************************************************/
/*
- * clear the specified process keyring
- * - the keyring must be writable
- * - implements keyctl(KEYCTL_CLEAR)
+ * Clear the specified keyring, creating an empty process keyring if one of the
+ * special keyring IDs is used.
+ *
+ * The keyring must grant the caller Write permission for this to work. If
+ * successful, 0 will be returned.
*/
long keyctl_keyring_clear(key_serial_t ringid)
{
@@ -383,15 +390,18 @@ long keyctl_keyring_clear(key_serial_t ringid)
key_ref_put(keyring_ref);
error:
return ret;
+}
-} /* end keyctl_keyring_clear() */
-
-/*****************************************************************************/
/*
- * link a key into a keyring
- * - the keyring must be writable
- * - the key must be linkable
- * - implements keyctl(KEYCTL_LINK)
+ * Create a link from a keyring to a key if there's no matching key in the
+ * keyring, otherwise replace the link to the matching key with a link to the
+ * new key.
+ *
+ * The key must grant the caller Link permission and the the keyring must grant
+ * the caller Write permission. Furthermore, if an additional link is created,
+ * the keyring's quota will be extended.
+ *
+ * If successful, 0 will be returned.
*/
long keyctl_keyring_link(key_serial_t id, key_serial_t ringid)
{
@@ -417,15 +427,16 @@ error2:
key_ref_put(keyring_ref);
error:
return ret;
+}
-} /* end keyctl_keyring_link() */
-
-/*****************************************************************************/
/*
- * unlink the first attachment of a key from a keyring
- * - the keyring must be writable
- * - we don't need any permissions on the key
- * - implements keyctl(KEYCTL_UNLINK)
+ * Unlink a key from a keyring.
+ *
+ * The keyring must grant the caller Write permission for this to work; the key
+ * itself need not grant the caller anything. If the last link to a key is
+ * removed then that key will be scheduled for destruction.
+ *
+ * If successful, 0 will be returned.
*/
long keyctl_keyring_unlink(key_serial_t id, key_serial_t ringid)
{
@@ -451,19 +462,20 @@ error2:
key_ref_put(keyring_ref);
error:
return ret;
+}
-} /* end keyctl_keyring_unlink() */
-
-/*****************************************************************************/
/*
- * describe a user key
- * - the key must have view permission
- * - if there's a buffer, we place up to buflen bytes of data into it
- * - unless there's an error, we return the amount of description available,
- * irrespective of how much we may have copied
- * - the description is formatted thus:
+ * Return a description of a key to userspace.
+ *
+ * The key must grant the caller View permission for this to work.
+ *
+ * If there's a buffer, we place up to buflen bytes of data into it formatted
+ * in the following way:
+ *
* type;uid;gid;perm;description<NUL>
- * - implements keyctl(KEYCTL_DESCRIBE)
+ *
+ * If successful, we return the amount of description available, irrespective
+ * of how much we may have copied into the buffer.
*/
long keyctl_describe_key(key_serial_t keyid,
char __user *buffer,
@@ -531,18 +543,17 @@ error2:
key_ref_put(key_ref);
error:
return ret;
+}
-} /* end keyctl_describe_key() */
-
-/*****************************************************************************/
/*
- * search the specified keyring for a matching key
- * - the start keyring must be searchable
- * - nested keyrings may also be searched if they are searchable
- * - only keys with search permission may be found
- * - if a key is found, it will be attached to the destination keyring if
- * there's one specified
- * - implements keyctl(KEYCTL_SEARCH)
+ * Search the specified keyring and any keyrings it links to for a matching
+ * key. Only keyrings that grant the caller Search permission will be searched
+ * (this includes the starting keyring). Only keys with Search permission can
+ * be found.
+ *
+ * If successful, the found key will be linked to the destination keyring if
+ * supplied and the key has Link permission, and the found key ID will be
+ * returned.
*/
long keyctl_keyring_search(key_serial_t ringid,
const char __user *_type,
@@ -626,18 +637,17 @@ error2:
kfree(description);
error:
return ret;
+}
-} /* end keyctl_keyring_search() */
-
-/*****************************************************************************/
/*
- * read a user key's payload
- * - the keyring must be readable or the key must be searchable from the
- * process's keyrings
- * - if there's a buffer, we place up to buflen bytes of data into it
- * - unless there's an error, we return the amount of data in the key,
- * irrespective of how much we may have copied
- * - implements keyctl(KEYCTL_READ)
+ * Read a key's payload.
+ *
+ * The key must either grant the caller Read permission, or it must grant the
+ * caller Search permission when searched for from the process keyrings.
+ *
+ * If successful, we place up to buflen bytes of data into the buffer, if one
+ * is provided, and return the amount of data that is available in the key,
+ * irrespective of how much we copied into the buffer.
*/
long keyctl_read_key(key_serial_t keyid, char __user *buffer, size_t buflen)
{
@@ -688,15 +698,22 @@ error2:
key_put(key);
error:
return ret;
+}
-} /* end keyctl_read_key() */
-
-/*****************************************************************************/
/*
- * change the ownership of a key
- * - the keyring owned by the changer
- * - if the uid or gid is -1, then that parameter is not changed
- * - implements keyctl(KEYCTL_CHOWN)
+ * Change the ownership of a key
+ *
+ * The key must grant the caller Setattr permission for this to work, though
+ * the key need not be fully instantiated yet. For the UID to be changed, or
+ * for the GID to be changed to a group the caller is not a member of, the
+ * caller must have sysadmin capability. If either uid or gid is -1 then that
+ * attribute is not changed.
+ *
+ * If the UID is to be changed, the new user must have sufficient quota to
+ * accept the key. The quota deduction will be removed from the old user to
+ * the new user should the attribute be changed.
+ *
+ * If successful, 0 will be returned.
*/
long keyctl_chown_key(key_serial_t id, uid_t uid, gid_t gid)
{
@@ -796,14 +813,14 @@ quota_overrun:
zapowner = newowner;
ret = -EDQUOT;
goto error_put;
+}
-} /* end keyctl_chown_key() */
-
-/*****************************************************************************/
/*
- * change the permission mask on a key
- * - the keyring owned by the changer
- * - implements keyctl(KEYCTL_SETPERM)
+ * Change the permission mask on a key.
+ *
+ * The key must grant the caller Setattr permission for this to work, though
+ * the key need not be fully instantiated yet. If the caller does not have
+ * sysadmin capability, it may only change the permission on keys that it owns.
*/
long keyctl_setperm_key(key_serial_t id, key_perm_t perm)
{
@@ -838,11 +855,11 @@ long keyctl_setperm_key(key_serial_t id, key_perm_t perm)
key_put(key);
error:
return ret;
-
-} /* end keyctl_setperm_key() */
+}
/*
- * get the destination keyring for instantiation
+ * Get the destination keyring for instantiation and check that the caller has
+ * Write permission on it.
*/
static long get_instantiation_keyring(key_serial_t ringid,
struct request_key_auth *rka,
@@ -879,7 +896,7 @@ static long get_instantiation_keyring(key_serial_t ringid,
}
/*
- * change the request_key authorisation key on the current process
+ * Change the request_key authorisation key on the current process.
*/
static int keyctl_change_reqkey_auth(struct key *key)
{
@@ -895,10 +912,14 @@ static int keyctl_change_reqkey_auth(struct key *key)
return commit_creds(new);
}
-/*****************************************************************************/
/*
- * instantiate the key with the specified payload, and, if one is given, link
- * the key into the keyring
+ * Instantiate a key with the specified payload and link the key into the
+ * destination keyring if one is given.
+ *
+ * The caller must have the appropriate instantiation permit set for this to
+ * work (see keyctl_assume_authority). No other permissions are required.
+ *
+ * If successful, 0 will be returned.
*/
long keyctl_instantiate_key(key_serial_t id,
const void __user *_payload,
@@ -973,13 +994,22 @@ error2:
vfree(payload);
error:
return ret;
+}
-} /* end keyctl_instantiate_key() */
-
-/*****************************************************************************/
/*
- * negatively instantiate the key with the given timeout (in seconds), and, if
- * one is given, link the key into the keyring
+ * Negatively instantiate the key with the given timeout (in seconds) and link
+ * the key into the destination keyring if one is given.
+ *
+ * The caller must have the appropriate instantiation permit set for this to
+ * work (see keyctl_assume_authority). No other permissions are required.
+ *
+ * The key and any links to the key will be automatically garbage collected
+ * after the timeout expires.
+ *
+ * Negative keys are used to rate limit repeated request_key() calls by causing
+ * them to return -ENOKEY until the negative key expires.
+ *
+ * If successful, 0 will be returned.
*/
long keyctl_negate_key(key_serial_t id, unsigned timeout, key_serial_t ringid)
{
@@ -1020,13 +1050,14 @@ long keyctl_negate_key(key_serial_t id, unsigned timeout, key_serial_t ringid)
error:
return ret;
+}
-} /* end keyctl_negate_key() */
-
-/*****************************************************************************/
/*
- * set the default keyring in which request_key() will cache keys
- * - return the old setting
+ * Read or set the default keyring in which request_key() will cache keys and
+ * return the old setting.
+ *
+ * If a process keyring is specified then this will be created if it doesn't
+ * yet exist. The old setting will be returned if successful.
*/
long keyctl_set_reqkey_keyring(int reqkey_defl)
{
@@ -1079,12 +1110,19 @@ set:
error:
abort_creds(new);
return ret;
+}
-} /* end keyctl_set_reqkey_keyring() */
-
-/*****************************************************************************/
/*
- * set or clear the timeout for a key
+ * Set or clear the timeout on a key.
+ *
+ * Either the key must grant the caller Setattr permission or else the caller
+ * must hold an instantiation authorisation token for the key.
+ *
+ * The timeout is either 0 to clear the timeout, or a number of seconds from
+ * the current time. The key and any links to the key will be automatically
+ * garbage collected after the timeout expires.
+ *
+ * If successful, 0 is returned.
*/
long keyctl_set_timeout(key_serial_t id, unsigned timeout)
{
@@ -1136,12 +1174,24 @@ okay:
ret = 0;
error:
return ret;
+}
-} /* end keyctl_set_timeout() */
-
-/*****************************************************************************/
/*
- * assume the authority to instantiate the specified key
+ * Assume (or clear) the authority to instantiate the specified key.
+ *
+ * This sets the authoritative token currently in force for key instantiation.
+ * This must be done for a key to be instantiated. It has the effect of making
+ * available all the keys from the caller of the request_key() that created a
+ * key to request_key() calls made by the caller of this function.
+ *
+ * The caller must have the instantiation key in their process keyrings with a
+ * Search permission grant available to the caller.
+ *
+ * If the ID given is 0, then the setting will be cleared and 0 returned.
+ *
+ * If the ID given has a matching an authorisation key, then that key will be
+ * set and its ID will be returned. The authorisation key can be read to get
+ * the callout information passed to request_key().
*/
long keyctl_assume_authority(key_serial_t id)
{
@@ -1178,16 +1228,17 @@ long keyctl_assume_authority(key_serial_t id)
ret = authkey->serial;
error:
return ret;
-
-} /* end keyctl_assume_authority() */
+}
/*
- * get the security label of a key
- * - the key must grant us view permission
- * - if there's a buffer, we place up to buflen bytes of data into it
- * - unless there's an error, we return the amount of information available,
- * irrespective of how much we may have copied (including the terminal NUL)
- * - implements keyctl(KEYCTL_GET_SECURITY)
+ * Get a key's the LSM security label.
+ *
+ * The key must grant the caller View permission for this to work.
+ *
+ * If there's a buffer, then up to buflen bytes of data will be placed into it.
+ *
+ * If successful, the amount of information available will be returned,
+ * irrespective of how much was copied (including the terminal NUL).
*/
long keyctl_get_security(key_serial_t keyid,
char __user *buffer,
@@ -1242,10 +1293,16 @@ long keyctl_get_security(key_serial_t keyid,
}
/*
- * attempt to install the calling process's session keyring on the process's
- * parent process
- * - the keyring must exist and must grant us LINK permission
- * - implements keyctl(KEYCTL_SESSION_TO_PARENT)
+ * Attempt to install the calling process's session keyring on the process's
+ * parent process.
+ *
+ * The keyring must exist and must grant the caller LINK permission, and the
+ * parent process must be single-threaded and must have the same effective
+ * ownership as this process and mustn't be SUID/SGID.
+ *
+ * The keyring will be emplaced on the parent when it next resumes userspace.
+ *
+ * If successful, 0 will be returned.
*/
long keyctl_session_to_parent(void)
{
@@ -1348,9 +1405,8 @@ error_keyring:
#endif /* !TIF_NOTIFY_RESUME */
}
-/*****************************************************************************/
/*
- * the key control system call
+ * The key control system call
*/
SYSCALL_DEFINE5(keyctl, int, option, unsigned long, arg2, unsigned long, arg3,
unsigned long, arg4, unsigned long, arg5)
@@ -1439,5 +1495,4 @@ SYSCALL_DEFINE5(keyctl, int, option, unsigned long, arg2, unsigned long, arg3,
default:
return -EOPNOTSUPP;
}
-
-} /* end sys_keyctl() */
+}
diff --git a/security/keys/keyring.c b/security/keys/keyring.c
index d37f713..5620f08 100644
--- a/security/keys/keyring.c
+++ b/security/keys/keyring.c
@@ -25,14 +25,16 @@
(keyring)->payload.subscriptions, \
rwsem_is_locked((struct rw_semaphore *)&(keyring)->sem)))
+#define KEY_LINK_FIXQUOTA 1UL
+
/*
- * when plumbing the depths of the key tree, this sets a hard limit set on how
- * deep we're willing to go
+ * When plumbing the depths of the key tree, this sets a hard limit
+ * set on how deep we're willing to go.
*/
#define KEYRING_SEARCH_MAX_DEPTH 6
/*
- * we keep all named keyrings in a hash to speed looking them up
+ * We keep all named keyrings in a hash to speed looking them up.
*/
#define KEYRING_NAME_HASH_SIZE (1 << 5)
@@ -50,7 +52,9 @@ static inline unsigned keyring_hash(const char *desc)
}
/*
- * the keyring type definition
+ * The keyring key type definition. Keyrings are simply keys of this type and
+ * can be treated as ordinary keys in addition to having their own special
+ * operations.
*/
static int keyring_instantiate(struct key *keyring,
const void *data, size_t datalen);
@@ -71,19 +75,17 @@ struct key_type key_type_keyring = {
.describe = keyring_describe,
.read = keyring_read,
};
-
EXPORT_SYMBOL(key_type_keyring);
/*
- * semaphore to serialise link/link calls to prevent two link calls in parallel
- * introducing a cycle
+ * Semaphore to serialise link/link calls to prevent two link calls in parallel
+ * introducing a cycle.
*/
static DECLARE_RWSEM(keyring_serialise_link_sem);
-/*****************************************************************************/
/*
- * publish the name of a keyring so that it can be found by name (if it has
- * one)
+ * Publish the name of a keyring so that it can be found by name (if it has
+ * one).
*/
static void keyring_publish_name(struct key *keyring)
{
@@ -102,13 +104,12 @@ static void keyring_publish_name(struct key *keyring)
write_unlock(&keyring_name_lock);
}
+}
-} /* end keyring_publish_name() */
-
-/*****************************************************************************/
/*
- * initialise a keyring
- * - we object if we were given any data
+ * Initialise a keyring.
+ *
+ * Returns 0 on success, -EINVAL if given any data.
*/
static int keyring_instantiate(struct key *keyring,
const void *data, size_t datalen)
@@ -123,23 +124,20 @@ static int keyring_instantiate(struct key *keyring,
}
return ret;
+}
-} /* end keyring_instantiate() */
-
-/*****************************************************************************/
/*
- * match keyrings on their name
+ * Match keyrings on their name
*/
static int keyring_match(const struct key *keyring, const void *description)
{
return keyring->description &&
strcmp(keyring->description, description) == 0;
+}
-} /* end keyring_match() */
-
-/*****************************************************************************/
/*
- * dispose of the data dangling from the corpse of a keyring
+ * Clean up a keyring when it is destroyed. Unpublish its name if it had one
+ * and dispose of its data.
*/
static void keyring_destroy(struct key *keyring)
{
@@ -164,12 +162,10 @@ static void keyring_destroy(struct key *keyring)
key_put(klist->keys[loop]);
kfree(klist);
}
+}
-} /* end keyring_destroy() */
-
-/*****************************************************************************/
/*
- * describe the keyring
+ * Describe a keyring for /proc.
*/
static void keyring_describe(const struct key *keyring, struct seq_file *m)
{
@@ -187,13 +183,12 @@ static void keyring_describe(const struct key *keyring, struct seq_file *m)
else
seq_puts(m, ": empty");
rcu_read_unlock();
+}
-} /* end keyring_describe() */
-
-/*****************************************************************************/
/*
- * read a list of key IDs from the keyring's contents
- * - the keyring's semaphore is read-locked
+ * Read a list of key IDs from the keyring's contents in binary form
+ *
+ * The keyring's semaphore is read-locked by the caller.
*/
static long keyring_read(const struct key *keyring,
char __user *buffer, size_t buflen)
@@ -241,12 +236,10 @@ static long keyring_read(const struct key *keyring,
error:
return ret;
+}
-} /* end keyring_read() */
-
-/*****************************************************************************/
/*
- * allocate a keyring and link into the destination keyring
+ * Allocate a keyring and link into the destination keyring.
*/
struct key *keyring_alloc(const char *description, uid_t uid, gid_t gid,
const struct cred *cred, unsigned long flags,
@@ -269,20 +262,42 @@ struct key *keyring_alloc(const char *description, uid_t uid, gid_t gid,
}
return keyring;
+}
-} /* end keyring_alloc() */
-
-/*****************************************************************************/
-/*
- * search the supplied keyring tree for a key that matches the criterion
- * - perform a breadth-then-depth search up to the prescribed limit
- * - we only find keys on which we have search permission
- * - we use the supplied match function to see if the description (or other
- * feature of interest) matches
- * - we rely on RCU to prevent the keyring lists from disappearing on us
- * - we return -EAGAIN if we didn't find any matching key
- * - we return -ENOKEY if we only found negative matching keys
- * - we propagate the possession attribute from the keyring ref to the key ref
+/**
+ * keyring_search_aux - Search a keyring tree for a key matching some criteria
+ * @keyring_ref: A pointer to the keyring with possession indicator.
+ * @cred: The credentials to use for permissions checks.
+ * @type: The type of key to search for.
+ * @description: Parameter for @match.
+ * @match: Function to rule on whether or not a key is the one required.
+ *
+ * Search the supplied keyring tree for a key that matches the criteria given.
+ * The root keyring and any linked keyrings must grant Search permission to the
+ * caller to be searchable and keys can only be found if they too grant Search
+ * to the caller. The possession flag on the root keyring pointer controls use
+ * of the possessor bits in permissions checking of the entire tree. In
+ * addition, the LSM gets to forbid keyring searches and key matches.
+ *
+ * The search is performed as a breadth-then-depth search up to the prescribed
+ * limit (KEYRING_SEARCH_MAX_DEPTH).
+ *
+ * Keys are matched to the type provided and are then filtered by the match
+ * function, which is given the description to use in any way it sees fit. The
+ * match function may use any attributes of a key that it wishes to to
+ * determine the match. Normally the match function from the key type would be
+ * used.
+ *
+ * RCU is used to prevent the keyring key lists from disappearing without the
+ * need to take lots of locks.
+ *
+ * Returns a pointer to the found key and increments the key usage count if
+ * successful; -EAGAIN if no matching keys were found, or if expired or revoked
+ * keys were found; -ENOKEY if only negative keys were found; -ENOTDIR if the
+ * specified keyring wasn't a keyring.
+ *
+ * In the case of a successful return, the possession attribute from
+ * @keyring_ref is propagated to the returned key reference.
*/
key_ref_t keyring_search_aux(key_ref_t keyring_ref,
const struct cred *cred,
@@ -444,17 +459,16 @@ error_2:
rcu_read_unlock();
error:
return key_ref;
+}
-} /* end keyring_search_aux() */
-
-/*****************************************************************************/
-/*
- * search the supplied keyring tree for a key that matches the criterion
- * - perform a breadth-then-depth search up to the prescribed limit
- * - we only find keys on which we have search permission
- * - we readlock the keyrings as we search down the tree
- * - we return -EAGAIN if we didn't find any matching key
- * - we return -ENOKEY if we only found negative matching keys
+/**
+ * keyring_search - Search the supplied keyring tree for a matching key
+ * @keyring: The root of the keyring tree to be searched.
+ * @type: The type of keyring we want to find.
+ * @description: The name of the keyring we want to find.
+ *
+ * As keyring_search_aux() above, but using the current task's credentials and
+ * type's default matching function.
*/
key_ref_t keyring_search(key_ref_t keyring,
struct key_type *type,
@@ -465,16 +479,23 @@ key_ref_t keyring_search(key_ref_t keyring,
return keyring_search_aux(keyring, current->cred,
type, description, type->match);
-
-} /* end keyring_search() */
-
+}
EXPORT_SYMBOL(keyring_search);
-/*****************************************************************************/
/*
- * search the given keyring only (no recursion)
- * - keyring must be locked by caller
- * - caller must guarantee that the keyring is a keyring
+ * Search the given keyring only (no recursion).
+ *
+ * The caller must guarantee that the keyring is a keyring and that the
+ * permission is granted to search the keyring as no check is made here.
+ *
+ * RCU is used to make it unnecessary to lock the keyring key list here.
+ *
+ * Returns a pointer to the found key with usage count incremented if
+ * successful and returns -ENOKEY if not found. Revoked keys and keys not
+ * providing the requested permission are skipped over.
+ *
+ * If successful, the possession indicator is propagated from the keyring ref
+ * to the returned key reference.
*/
key_ref_t __keyring_search_one(key_ref_t keyring_ref,
const struct key_type *ktype,
@@ -514,14 +535,18 @@ found:
atomic_inc(&key->usage);
rcu_read_unlock();
return make_key_ref(key, possessed);
+}
-} /* end __keyring_search_one() */
-
-/*****************************************************************************/
/*
- * find a keyring with the specified name
- * - all named keyrings are searched
- * - normally only finds keyrings with search permission for the current process
+ * Find a keyring with the specified name.
+ *
+ * All named keyrings in the current user namespace are searched, provided they
+ * grant Search permission directly to the caller (unless this check is
+ * skipped). Keyrings whose usage points have reached zero or who have been
+ * revoked are skipped.
+ *
+ * Returns a pointer to the keyring with the keyring's refcount having being
+ * incremented on success. -ENOKEY is returned if a key could not be found.
*/
struct key *find_keyring_by_name(const char *name, bool skip_perm_check)
{
@@ -569,15 +594,14 @@ struct key *find_keyring_by_name(const char *name, bool skip_perm_check)
out:
read_unlock(&keyring_name_lock);
return keyring;
+}
-} /* end find_keyring_by_name() */
-
-/*****************************************************************************/
/*
- * see if a cycle will will be created by inserting acyclic tree B in acyclic
- * tree A at the topmost level (ie: as a direct child of A)
- * - since we are adding B to A at the top level, checking for cycles should
- * just be a matter of seeing if node A is somewhere in tree B
+ * See if a cycle will will be created by inserting acyclic tree B in acyclic
+ * tree A at the topmost level (ie: as a direct child of A).
+ *
+ * Since we are adding B to A at the top level, checking for cycles should just
+ * be a matter of seeing if node A is somewhere in tree B.
*/
static int keyring_detect_cycle(struct key *A, struct key *B)
{
@@ -657,11 +681,10 @@ too_deep:
cycle_detected:
ret = -EDEADLK;
goto error;
-
-} /* end keyring_detect_cycle() */
+}
/*
- * dispose of a keyring list after the RCU grace period, freeing the unlinked
+ * Dispose of a keyring list after the RCU grace period, freeing the unlinked
* key
*/
static void keyring_unlink_rcu_disposal(struct rcu_head *rcu)
@@ -675,14 +698,14 @@ static void keyring_unlink_rcu_disposal(struct rcu_head *rcu)
}
/*
- * preallocate memory so that a key can be linked into to a keyring
+ * Preallocate memory so that a key can be linked into to a keyring.
*/
int __key_link_begin(struct key *keyring, const struct key_type *type,
- const char *description,
- struct keyring_list **_prealloc)
+ const char *description, unsigned long *_prealloc)
__acquires(&keyring->sem)
{
struct keyring_list *klist, *nklist;
+ unsigned long prealloc;
unsigned max;
size_t size;
int loop, ret;
@@ -725,6 +748,7 @@ int __key_link_begin(struct key *keyring, const struct key_type *type,
/* note replacement slot */
klist->delkey = nklist->delkey = loop;
+ prealloc = (unsigned long)nklist;
goto done;
}
}
@@ -739,6 +763,7 @@ int __key_link_begin(struct key *keyring, const struct key_type *type,
if (klist && klist->nkeys < klist->maxkeys) {
/* there's sufficient slack space to append directly */
nklist = NULL;
+ prealloc = KEY_LINK_FIXQUOTA;
} else {
/* grow the key list */
max = 4;
@@ -773,8 +798,9 @@ int __key_link_begin(struct key *keyring, const struct key_type *type,
nklist->keys[nklist->delkey] = NULL;
}
+ prealloc = (unsigned long)nklist | KEY_LINK_FIXQUOTA;
done:
- *_prealloc = nklist;
+ *_prealloc = prealloc;
kleave(" = 0");
return 0;
@@ -792,10 +818,10 @@ error_krsem:
}
/*
- * check already instantiated keys aren't going to be a problem
- * - the caller must have called __key_link_begin()
- * - don't need to call this for keys that were created since __key_link_begin()
- * was called
+ * Check already instantiated keys aren't going to be a problem.
+ *
+ * The caller must have called __key_link_begin(). Don't need to call this for
+ * keys that were created since __key_link_begin() was called.
*/
int __key_link_check_live_key(struct key *keyring, struct key *key)
{
@@ -807,17 +833,20 @@ int __key_link_check_live_key(struct key *keyring, struct key *key)
}
/*
- * link a key into to a keyring
- * - must be called with __key_link_begin() having being called
- * - discard already extant link to matching key if there is one
+ * Link a key into to a keyring.
+ *
+ * Must be called with __key_link_begin() having being called. Discards any
+ * already extant link to matching key if there is one, so that each keyring
+ * holds at most one link to any given key of a particular type+description
+ * combination.
*/
void __key_link(struct key *keyring, struct key *key,
- struct keyring_list **_prealloc)
+ unsigned long *_prealloc)
{
struct keyring_list *klist, *nklist;
- nklist = *_prealloc;
- *_prealloc = NULL;
+ nklist = (struct keyring_list *)(*_prealloc & ~KEY_LINK_FIXQUOTA);
+ *_prealloc = 0;
kenter("%d,%d,%p", keyring->serial, key->serial, nklist);
@@ -852,34 +881,54 @@ void __key_link(struct key *keyring, struct key *key,
}
/*
- * finish linking a key into to a keyring
- * - must be called with __key_link_begin() having being called
+ * Finish linking a key into to a keyring.
+ *
+ * Must be called with __key_link_begin() having being called.
*/
void __key_link_end(struct key *keyring, struct key_type *type,
- struct keyring_list *prealloc)
+ unsigned long prealloc)
__releases(&keyring->sem)
{
BUG_ON(type == NULL);
BUG_ON(type->name == NULL);
- kenter("%d,%s,%p", keyring->serial, type->name, prealloc);
+ kenter("%d,%s,%lx", keyring->serial, type->name, prealloc);
if (type == &key_type_keyring)
up_write(&keyring_serialise_link_sem);
if (prealloc) {
- kfree(prealloc);
- key_payload_reserve(keyring,
- keyring->datalen - KEYQUOTA_LINK_BYTES);
+ if (prealloc & KEY_LINK_FIXQUOTA)
+ key_payload_reserve(keyring,
+ keyring->datalen -
+ KEYQUOTA_LINK_BYTES);
+ kfree((struct keyring_list *)(prealloc & ~KEY_LINK_FIXQUOTA));
}
up_write(&keyring->sem);
}
-/*
- * link a key to a keyring
+/**
+ * key_link - Link a key to a keyring
+ * @keyring: The keyring to make the link in.
+ * @key: The key to link to.
+ *
+ * Make a link in a keyring to a key, such that the keyring holds a reference
+ * on that key and the key can potentially be found by searching that keyring.
+ *
+ * This function will write-lock the keyring's semaphore and will consume some
+ * of the user's key data quota to hold the link.
+ *
+ * Returns 0 if successful, -ENOTDIR if the keyring isn't a keyring,
+ * -EKEYREVOKED if the keyring has been revoked, -ENFILE if the keyring is
+ * full, -EDQUOT if there is insufficient key data quota remaining to add
+ * another link or -ENOMEM if there's insufficient memory.
+ *
+ * It is assumed that the caller has checked that it is permitted for a link to
+ * be made (the keyring should have Write permission and the key Link
+ * permission).
*/
int key_link(struct key *keyring, struct key *key)
{
- struct keyring_list *prealloc;
+ unsigned long prealloc;
int ret;
key_check(keyring);
@@ -895,12 +944,24 @@ int key_link(struct key *keyring, struct key *key)
return ret;
}
-
EXPORT_SYMBOL(key_link);
-/*****************************************************************************/
-/*
- * unlink the first link to a key from a keyring
+/**
+ * key_unlink - Unlink the first link to a key from a keyring.
+ * @keyring: The keyring to remove the link from.
+ * @key: The key the link is to.
+ *
+ * Remove a link from a keyring to a key.
+ *
+ * This function will write-lock the keyring's semaphore.
+ *
+ * Returns 0 if successful, -ENOTDIR if the keyring isn't a keyring, -ENOENT if
+ * the key isn't linked to by the keyring or -ENOMEM if there's insufficient
+ * memory.
+ *
+ * It is assumed that the caller has checked that it is permitted for a link to
+ * be removed (the keyring should have Write permission; no permissions are
+ * required on the key).
*/
int key_unlink(struct key *keyring, struct key *key)
{
@@ -968,15 +1029,12 @@ nomem:
ret = -ENOMEM;
up_write(&keyring->sem);
goto error;
-
-} /* end key_unlink() */
-
+}
EXPORT_SYMBOL(key_unlink);
-/*****************************************************************************/
/*
- * dispose of a keyring list after the RCU grace period, releasing the keys it
- * links to
+ * Dispose of a keyring list after the RCU grace period, releasing the keys it
+ * links to.
*/
static void keyring_clear_rcu_disposal(struct rcu_head *rcu)
{
@@ -989,13 +1047,15 @@ static void keyring_clear_rcu_disposal(struct rcu_head *rcu)
key_put(klist->keys[loop]);
kfree(klist);
+}
-} /* end keyring_clear_rcu_disposal() */
-
-/*****************************************************************************/
-/*
- * clear the specified process keyring
- * - implements keyctl(KEYCTL_CLEAR)
+/**
+ * keyring_clear - Clear a keyring
+ * @keyring: The keyring to clear.
+ *
+ * Clear the contents of the specified keyring.
+ *
+ * Returns 0 if successful or -ENOTDIR if the keyring isn't a keyring.
*/
int keyring_clear(struct key *keyring)
{
@@ -1027,15 +1087,13 @@ int keyring_clear(struct key *keyring)
}
return ret;
-
-} /* end keyring_clear() */
-
+}
EXPORT_SYMBOL(keyring_clear);
-/*****************************************************************************/
/*
- * dispose of the links from a revoked keyring
- * - called with the key sem write-locked
+ * Dispose of the links from a revoked keyring.
+ *
+ * This is called with the key sem write-locked.
*/
static void keyring_revoke(struct key *keyring)
{
@@ -1050,11 +1108,10 @@ static void keyring_revoke(struct key *keyring)
rcu_assign_pointer(keyring->payload.subscriptions, NULL);
call_rcu(&klist->rcu, keyring_clear_rcu_disposal);
}
-
-} /* end keyring_revoke() */
+}
/*
- * Determine whether a key is dead
+ * Determine whether a key is dead.
*/
static bool key_is_dead(struct key *key, time_t limit)
{
@@ -1063,7 +1120,12 @@ static bool key_is_dead(struct key *key, time_t limit)
}
/*
- * Collect garbage from the contents of a keyring
+ * Collect garbage from the contents of a keyring, replacing the old list with
+ * a new one with the pointers all shuffled down.
+ *
+ * Dead keys are classed as oned that are flagged as being dead or are revoked,
+ * expired or negative keys that were revoked or expired before the specified
+ * limit.
*/
void keyring_gc(struct key *keyring, time_t limit)
{
diff --git a/security/keys/permission.c b/security/keys/permission.c
index 2864550..c35b522 100644
--- a/security/keys/permission.c
+++ b/security/keys/permission.c
@@ -1,4 +1,4 @@
-/* permission.c: key permission determination
+/* Key permission checking
*
* Copyright (C) 2005 Red Hat, Inc. All Rights Reserved.
* Written by David Howells (dhowells@redhat.com)
@@ -13,18 +13,19 @@
#include <linux/security.h>
#include "internal.h"
-/*****************************************************************************/
/**
* key_task_permission - Check a key can be used
- * @key_ref: The key to check
- * @cred: The credentials to use
- * @perm: The permissions to check for
+ * @key_ref: The key to check.
+ * @cred: The credentials to use.
+ * @perm: The permissions to check for.
*
* Check to see whether permission is granted to use a key in the desired way,
* but permit the security modules to override.
*
- * The caller must hold either a ref on cred or must hold the RCU readlock or a
- * spinlock.
+ * The caller must hold either a ref on cred or must hold the RCU readlock.
+ *
+ * Returns 0 if successful, -EACCES if access is denied based on the
+ * permissions bits or the LSM check.
*/
int key_task_permission(const key_ref_t key_ref, const struct cred *cred,
key_perm_t perm)
@@ -79,14 +80,16 @@ use_these_perms:
/* let LSM be the final arbiter */
return security_key_permission(key_ref, cred, perm);
-
-} /* end key_task_permission() */
-
+}
EXPORT_SYMBOL(key_task_permission);
-/*****************************************************************************/
-/*
- * validate a key
+/**
+ * key_validate - Validate a key.
+ * @key: The key to be validated.
+ *
+ * Check that a key is valid, returning 0 if the key is okay, -EKEYREVOKED if
+ * the key's type has been removed or if the key has been revoked or
+ * -EKEYEXPIRED if the key has expired.
*/
int key_validate(struct key *key)
{
@@ -111,7 +114,5 @@ int key_validate(struct key *key)
error:
return ret;
-
-} /* end key_validate() */
-
+}
EXPORT_SYMBOL(key_validate);
diff --git a/security/keys/proc.c b/security/keys/proc.c
index 70373966..525cf8a 100644
--- a/security/keys/proc.c
+++ b/security/keys/proc.c
@@ -1,4 +1,4 @@
-/* proc.c: proc files for key database enumeration
+/* procfs files for key database enumeration
*
* Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
* Written by David Howells (dhowells@redhat.com)
@@ -60,9 +60,8 @@ static const struct file_operations proc_key_users_fops = {
.release = seq_release,
};
-/*****************************************************************************/
/*
- * declare the /proc files
+ * Declare the /proc files.
*/
static int __init key_proc_init(void)
{
@@ -79,14 +78,13 @@ static int __init key_proc_init(void)
panic("Cannot create /proc/key-users\n");
return 0;
-
-} /* end key_proc_init() */
+}
__initcall(key_proc_init);
-/*****************************************************************************/
/*
- * implement "/proc/keys" to provides a list of the keys on the system
+ * Implement "/proc/keys" to provide a list of the keys on the system that
+ * grant View permission to the caller.
*/
#ifdef CONFIG_KEYS_DEBUG_PROC_KEYS
@@ -293,9 +291,9 @@ static struct rb_node *key_user_first(struct rb_root *r)
return __key_user_next(n);
}
-/*****************************************************************************/
/*
- * implement "/proc/key-users" to provides a list of the key users
+ * Implement "/proc/key-users" to provides a list of the key users and their
+ * quotas.
*/
static int proc_key_users_open(struct inode *inode, struct file *file)
{
@@ -351,5 +349,4 @@ static int proc_key_users_show(struct seq_file *m, void *v)
maxbytes);
return 0;
-
}
diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c
index 504bdd2..930634e 100644
--- a/security/keys/process_keys.c
+++ b/security/keys/process_keys.c
@@ -1,4 +1,4 @@
-/* Management of a process's keyrings
+/* Manage a process's keyrings
*
* Copyright (C) 2004-2005, 2008 Red Hat, Inc. All Rights Reserved.
* Written by David Howells (dhowells@redhat.com)
@@ -21,13 +21,13 @@
#include <asm/uaccess.h>
#include "internal.h"
-/* session keyring create vs join semaphore */
+/* Session keyring create vs join semaphore */
static DEFINE_MUTEX(key_session_mutex);
-/* user keyring creation semaphore */
+/* User keyring creation semaphore */
static DEFINE_MUTEX(key_user_keyring_mutex);
-/* the root user's tracking struct */
+/* The root user's tracking struct */
struct key_user root_key_user = {
.usage = ATOMIC_INIT(3),
.cons_lock = __MUTEX_INITIALIZER(root_key_user.cons_lock),
@@ -38,9 +38,8 @@ struct key_user root_key_user = {
.user_ns = &init_user_ns,
};
-/*****************************************************************************/
/*
- * install user and user session keyrings for a particular UID
+ * Install the user and user session keyrings for the current process's UID.
*/
int install_user_keyrings(void)
{
@@ -122,7 +121,8 @@ error:
}
/*
- * install a fresh thread keyring directly to new credentials
+ * Install a fresh thread keyring directly to new credentials. This keyring is
+ * allowed to overrun the quota.
*/
int install_thread_keyring_to_cred(struct cred *new)
{
@@ -138,7 +138,7 @@ int install_thread_keyring_to_cred(struct cred *new)
}
/*
- * install a fresh thread keyring, discarding the old one
+ * Install a fresh thread keyring, discarding the old one.
*/
static int install_thread_keyring(void)
{
@@ -161,9 +161,10 @@ static int install_thread_keyring(void)
}
/*
- * install a process keyring directly to a credentials struct
- * - returns -EEXIST if there was already a process keyring, 0 if one installed,
- * and other -ve on any other error
+ * Install a process keyring directly to a credentials struct.
+ *
+ * Returns -EEXIST if there was already a process keyring, 0 if one installed,
+ * and other value on any other error
*/
int install_process_keyring_to_cred(struct cred *new)
{
@@ -192,8 +193,11 @@ int install_process_keyring_to_cred(struct cred *new)
}
/*
- * make sure a process keyring is installed
- * - we
+ * Make sure a process keyring is installed for the current process. The
+ * existing process keyring is not replaced.
+ *
+ * Returns 0 if there is a process keyring by the end of this function, some
+ * error otherwise.
*/
static int install_process_keyring(void)
{
@@ -214,7 +218,7 @@ static int install_process_keyring(void)
}
/*
- * install a session keyring directly to a credentials struct
+ * Install a session keyring directly to a credentials struct.
*/
int install_session_keyring_to_cred(struct cred *cred, struct key *keyring)
{
@@ -254,8 +258,8 @@ int install_session_keyring_to_cred(struct cred *cred, struct key *keyring)
}
/*
- * install a session keyring, discarding the old one
- * - if a keyring is not supplied, an empty one is invented
+ * Install a session keyring, discarding the old one. If a keyring is not
+ * supplied, an empty one is invented.
*/
static int install_session_keyring(struct key *keyring)
{
@@ -275,9 +279,8 @@ static int install_session_keyring(struct key *keyring)
return commit_creds(new);
}
-/*****************************************************************************/
/*
- * the filesystem user ID changed
+ * Handle the fsuid changing.
*/
void key_fsuid_changed(struct task_struct *tsk)
{
@@ -288,12 +291,10 @@ void key_fsuid_changed(struct task_struct *tsk)
tsk->cred->thread_keyring->uid = tsk->cred->fsuid;
up_write(&tsk->cred->thread_keyring->sem);
}
+}
-} /* end key_fsuid_changed() */
-
-/*****************************************************************************/
/*
- * the filesystem group ID changed
+ * Handle the fsgid changing.
*/
void key_fsgid_changed(struct task_struct *tsk)
{
@@ -304,16 +305,28 @@ void key_fsgid_changed(struct task_struct *tsk)
tsk->cred->thread_keyring->gid = tsk->cred->fsgid;
up_write(&tsk->cred->thread_keyring->sem);
}
+}
-} /* end key_fsgid_changed() */
-
-/*****************************************************************************/
/*
- * search only my process keyrings for the first matching key
- * - we use the supplied match function to see if the description (or other
- * feature of interest) matches
- * - we return -EAGAIN if we didn't find any matching key
- * - we return -ENOKEY if we found only negative matching keys
+ * Search the process keyrings attached to the supplied cred for the first
+ * matching key.
+ *
+ * The search criteria are the type and the match function. The description is
+ * given to the match function as a parameter, but doesn't otherwise influence
+ * the search. Typically the match function will compare the description
+ * parameter to the key's description.
+ *
+ * This can only search keyrings that grant Search permission to the supplied
+ * credentials. Keyrings linked to searched keyrings will also be searched if
+ * they grant Search permission too. Keys can only be found if they grant
+ * Search permission to the credentials.
+ *
+ * Returns a pointer to the key with the key usage count incremented if
+ * successful, -EAGAIN if we didn't find any matching key or -ENOKEY if we only
+ * matched negative keys.
+ *
+ * In the case of a successful return, the possession attribute is set on the
+ * returned key reference.
*/
key_ref_t search_my_process_keyrings(struct key_type *type,
const void *description,
@@ -428,13 +441,13 @@ found:
return key_ref;
}
-/*****************************************************************************/
/*
- * search the process keyrings for the first matching key
- * - we use the supplied match function to see if the description (or other
- * feature of interest) matches
- * - we return -EAGAIN if we didn't find any matching key
- * - we return -ENOKEY if we found only negative matching keys
+ * Search the process keyrings attached to the supplied cred for the first
+ * matching key in the manner of search_my_process_keyrings(), but also search
+ * the keys attached to the assumed authorisation key using its credentials if
+ * one is available.
+ *
+ * Return same as search_my_process_keyrings().
*/
key_ref_t search_process_keyrings(struct key_type *type,
const void *description,
@@ -489,24 +502,33 @@ key_ref_t search_process_keyrings(struct key_type *type,
found:
return key_ref;
+}
-} /* end search_process_keyrings() */
-
-/*****************************************************************************/
/*
- * see if the key we're looking at is the target key
+ * See if the key we're looking at is the target key.
*/
int lookup_user_key_possessed(const struct key *key, const void *target)
{
return key == target;
+}
-} /* end lookup_user_key_possessed() */
-
-/*****************************************************************************/
/*
- * lookup a key given a key ID from userspace with a given permissions mask
- * - don't create special keyrings unless so requested
- * - partially constructed keys aren't found unless requested
+ * Look up a key ID given us by userspace with a given permissions mask to get
+ * the key it refers to.
+ *
+ * Flags can be passed to request that special keyrings be created if referred
+ * to directly, to permit partially constructed keys to be found and to skip
+ * validity and permission checks on the found key.
+ *
+ * Returns a pointer to the key with an incremented usage count if successful;
+ * -EINVAL if the key ID is invalid; -ENOKEY if the key ID does not correspond
+ * to a key or the best found key was a negative key; -EKEYREVOKED or
+ * -EKEYEXPIRED if the best found key was revoked or expired; -EACCES if the
+ * found key doesn't grant the requested permit or the LSM denied access to it;
+ * or -ENOMEM if a special keyring couldn't be created.
+ *
+ * In the case of a successful return, the possession attribute is set on the
+ * returned key reference.
*/
key_ref_t lookup_user_key(key_serial_t id, unsigned long lflags,
key_perm_t perm)
@@ -711,15 +733,18 @@ invalid_key:
reget_creds:
put_cred(cred);
goto try_again;
+}
-} /* end lookup_user_key() */
-
-/*****************************************************************************/
/*
- * join the named keyring as the session keyring if possible, or attempt to
- * create a new one of that name if not
- * - if the name is NULL, an empty anonymous keyring is installed instead
- * - named session keyring joining is done with a semaphore held
+ * Join the named keyring as the session keyring if possible else attempt to
+ * create a new one of that name and join that.
+ *
+ * If the name is NULL, an empty anonymous keyring will be installed as the
+ * session keyring.
+ *
+ * Named session keyrings are joined with a semaphore held to prevent the
+ * keyrings from going away whilst the attempt is made to going them and also
+ * to prevent a race in creating compatible session keyrings.
*/
long join_session_keyring(const char *name)
{
@@ -791,8 +816,8 @@ error:
}
/*
- * Replace a process's session keyring when that process resumes userspace on
- * behalf of one of its children
+ * Replace a process's session keyring on behalf of one of its children when
+ * the target process is about to resume userspace execution.
*/
void key_replace_session_keyring(void)
{
diff --git a/security/keys/request_key.c b/security/keys/request_key.c
index 0ea52d2..a3dc0d4 100644
--- a/security/keys/request_key.c
+++ b/security/keys/request_key.c
@@ -39,8 +39,14 @@ static int key_wait_bit_intr(void *flags)
return signal_pending(current) ? -ERESTARTSYS : 0;
}
-/*
- * call to complete the construction of a key
+/**
+ * complete_request_key - Complete the construction of a key.
+ * @cons: The key construction record.
+ * @error: The success or failute of the construction.
+ *
+ * Complete the attempt to construct a key. The key will be negated
+ * if an error is indicated. The authorisation key will be revoked
+ * unconditionally.
*/
void complete_request_key(struct key_construction *cons, int error)
{
@@ -58,23 +64,33 @@ void complete_request_key(struct key_construction *cons, int error)
}
EXPORT_SYMBOL(complete_request_key);
+/*
+ * Initialise a usermode helper that is going to have a specific session
+ * keyring.
+ *
+ * This is called in context of freshly forked kthread before kernel_execve(),
+ * so we can simply install the desired session_keyring at this point.
+ */
static int umh_keys_init(struct subprocess_info *info)
{
struct cred *cred = (struct cred*)current_cred();
struct key *keyring = info->data;
- /*
- * This is called in context of freshly forked kthread before
- * kernel_execve(), we can just change our ->session_keyring.
- */
+
return install_session_keyring_to_cred(cred, keyring);
}
+/*
+ * Clean up a usermode helper with session keyring.
+ */
static void umh_keys_cleanup(struct subprocess_info *info)
{
struct key *keyring = info->data;
key_put(keyring);
}
+/*
+ * Call a usermode helper with a specific session keyring.
+ */
static int call_usermodehelper_keys(char *path, char **argv, char **envp,
struct key *session_keyring, enum umh_wait wait)
{
@@ -91,7 +107,7 @@ static int call_usermodehelper_keys(char *path, char **argv, char **envp,
}
/*
- * request userspace finish the construction of a key
+ * Request userspace finish the construction of a key
* - execute "/sbin/request-key <op> <key> <uid> <gid> <keyring> <keyring> <keyring>"
*/
static int call_sbin_request_key(struct key_construction *cons,
@@ -198,8 +214,9 @@ error_alloc:
}
/*
- * call out to userspace for key construction
- * - we ignore program failure and go on key status instead
+ * Call out to userspace for key construction.
+ *
+ * Program failure is ignored in favour of key status.
*/
static int construct_key(struct key *key, const void *callout_info,
size_t callout_len, void *aux,
@@ -246,9 +263,10 @@ static int construct_key(struct key *key, const void *callout_info,
}
/*
- * get the appropriate destination keyring for the request
- * - we return whatever keyring we select with an extra reference upon it which
- * the caller must release
+ * Get the appropriate destination keyring for the request.
+ *
+ * The keyring selected is returned with an extra reference upon it which the
+ * caller must release.
*/
static void construct_get_dest_keyring(struct key **_dest_keyring)
{
@@ -321,9 +339,11 @@ static void construct_get_dest_keyring(struct key **_dest_keyring)
}
/*
- * allocate a new key in under-construction state and attempt to link it in to
- * the requested place
- * - may return a key that's already under construction instead
+ * Allocate a new key in under-construction state and attempt to link it in to
+ * the requested keyring.
+ *
+ * May return a key that's already under construction instead if there was a
+ * race between two thread calling request_key().
*/
static int construct_alloc_key(struct key_type *type,
const char *description,
@@ -332,8 +352,8 @@ static int construct_alloc_key(struct key_type *type,
struct key_user *user,
struct key **_key)
{
- struct keyring_list *prealloc;
const struct cred *cred = current_cred();
+ unsigned long prealloc;
struct key *key;
key_ref_t key_ref;
int ret;
@@ -414,7 +434,7 @@ alloc_failed:
}
/*
- * commence key construction
+ * Commence key construction.
*/
static struct key *construct_key_and_link(struct key_type *type,
const char *description,
@@ -465,12 +485,32 @@ construction_failed:
return ERR_PTR(ret);
}
-/*
- * request a key
- * - search the process's keyrings
- * - check the list of keys being created or updated
- * - call out to userspace for a key if supplementary info was provided
- * - cache the key in an appropriate keyring
+/**
+ * request_key_and_link - Request a key and cache it in a keyring.
+ * @type: The type of key we want.
+ * @description: The searchable description of the key.
+ * @callout_info: The data to pass to the instantiation upcall (or NULL).
+ * @callout_len: The length of callout_info.
+ * @aux: Auxiliary data for the upcall.
+ * @dest_keyring: Where to cache the key.
+ * @flags: Flags to key_alloc().
+ *
+ * A key matching the specified criteria is searched for in the process's
+ * keyrings and returned with its usage count incremented if found. Otherwise,
+ * if callout_info is not NULL, a key will be allocated and some service
+ * (probably in userspace) will be asked to instantiate it.
+ *
+ * If successfully found or created, the key will be linked to the destination
+ * keyring if one is provided.
+ *
+ * Returns a pointer to the key if successful; -EACCES, -ENOKEY, -EKEYREVOKED
+ * or -EKEYEXPIRED if an inaccessible, negative, revoked or expired key was
+ * found; -ENOKEY if no key was found and no @callout_info was given; -EDQUOT
+ * if insufficient key quota was available to create a new key; or -ENOMEM if
+ * insufficient memory was available.
+ *
+ * If the returned key was created, then it may still be under construction,
+ * and wait_for_key_construction() should be used to wait for that to complete.
*/
struct key *request_key_and_link(struct key_type *type,
const char *description,
@@ -524,8 +564,16 @@ error:
return key;
}
-/*
- * wait for construction of a key to complete
+/**
+ * wait_for_key_construction - Wait for construction of a key to complete
+ * @key: The key being waited for.
+ * @intr: Whether to wait interruptibly.
+ *
+ * Wait for a key to finish being constructed.
+ *
+ * Returns 0 if successful; -ERESTARTSYS if the wait was interrupted; -ENOKEY
+ * if the key was negated; or -EKEYREVOKED or -EKEYEXPIRED if the key was
+ * revoked or expired.
*/
int wait_for_key_construction(struct key *key, bool intr)
{
@@ -542,12 +590,19 @@ int wait_for_key_construction(struct key *key, bool intr)
}
EXPORT_SYMBOL(wait_for_key_construction);
-/*
- * request a key
- * - search the process's keyrings
- * - check the list of keys being created or updated
- * - call out to userspace for a key if supplementary info was provided
- * - waits uninterruptible for creation to complete
+/**
+ * request_key - Request a key and wait for construction
+ * @type: Type of key.
+ * @description: The searchable description of the key.
+ * @callout_info: The data to pass to the instantiation upcall (or NULL).
+ *
+ * As for request_key_and_link() except that it does not add the returned key
+ * to a keyring if found, new keys are always allocated in the user's quota,
+ * the callout_info must be a NUL-terminated string and no auxiliary data can
+ * be passed.
+ *
+ * Furthermore, it then works as wait_for_key_construction() to wait for the
+ * completion of keys undergoing construction with a non-interruptible wait.
*/
struct key *request_key(struct key_type *type,
const char *description,
@@ -572,12 +627,19 @@ struct key *request_key(struct key_type *type,
}
EXPORT_SYMBOL(request_key);
-/*
- * request a key with auxiliary data for the upcaller
- * - search the process's keyrings
- * - check the list of keys being created or updated
- * - call out to userspace for a key if supplementary info was provided
- * - waits uninterruptible for creation to complete
+/**
+ * request_key_with_auxdata - Request a key with auxiliary data for the upcaller
+ * @type: The type of key we want.
+ * @description: The searchable description of the key.
+ * @callout_info: The data to pass to the instantiation upcall (or NULL).
+ * @callout_len: The length of callout_info.
+ * @aux: Auxiliary data for the upcall.
+ *
+ * As for request_key_and_link() except that it does not add the returned key
+ * to a keyring if found and new keys are always allocated in the user's quota.
+ *
+ * Furthermore, it then works as wait_for_key_construction() to wait for the
+ * completion of keys undergoing construction with a non-interruptible wait.
*/
struct key *request_key_with_auxdata(struct key_type *type,
const char *description,
@@ -602,10 +664,18 @@ struct key *request_key_with_auxdata(struct key_type *type,
EXPORT_SYMBOL(request_key_with_auxdata);
/*
- * request a key (allow async construction)
- * - search the process's keyrings
- * - check the list of keys being created or updated
- * - call out to userspace for a key if supplementary info was provided
+ * request_key_async - Request a key (allow async construction)
+ * @type: Type of key.
+ * @description: The searchable description of the key.
+ * @callout_info: The data to pass to the instantiation upcall (or NULL).
+ * @callout_len: The length of callout_info.
+ *
+ * As for request_key_and_link() except that it does not add the returned key
+ * to a keyring if found, new keys are always allocated in the user's quota and
+ * no auxiliary data can be passed.
+ *
+ * The caller should call wait_for_key_construction() to wait for the
+ * completion of the returned key if it is still undergoing construction.
*/
struct key *request_key_async(struct key_type *type,
const char *description,
@@ -620,9 +690,17 @@ EXPORT_SYMBOL(request_key_async);
/*
* request a key with auxiliary data for the upcaller (allow async construction)
- * - search the process's keyrings
- * - check the list of keys being created or updated
- * - call out to userspace for a key if supplementary info was provided
+ * @type: Type of key.
+ * @description: The searchable description of the key.
+ * @callout_info: The data to pass to the instantiation upcall (or NULL).
+ * @callout_len: The length of callout_info.
+ * @aux: Auxiliary data for the upcall.
+ *
+ * As for request_key_and_link() except that it does not add the returned key
+ * to a keyring if found and new keys are always allocated in the user's quota.
+ *
+ * The caller should call wait_for_key_construction() to wait for the
+ * completion of the returned key if it is still undergoing construction.
*/
struct key *request_key_async_with_auxdata(struct key_type *type,
const char *description,
diff --git a/security/keys/request_key_auth.c b/security/keys/request_key_auth.c
index 8674715..6816403 100644
--- a/security/keys/request_key_auth.c
+++ b/security/keys/request_key_auth.c
@@ -1,4 +1,4 @@
-/* request_key_auth.c: request key authorisation controlling key def
+/* Request key authorisation token key definition.
*
* Copyright (C) 2005 Red Hat, Inc. All Rights Reserved.
* Written by David Howells (dhowells@redhat.com)
@@ -26,7 +26,7 @@ static void request_key_auth_destroy(struct key *);
static long request_key_auth_read(const struct key *, char __user *, size_t);
/*
- * the request-key authorisation key type definition
+ * The request-key authorisation key type definition.
*/
struct key_type key_type_request_key_auth = {
.name = ".request_key_auth",
@@ -38,9 +38,8 @@ struct key_type key_type_request_key_auth = {
.read = request_key_auth_read,
};
-/*****************************************************************************/
/*
- * instantiate a request-key authorisation key
+ * Instantiate a request-key authorisation key.
*/
static int request_key_auth_instantiate(struct key *key,
const void *data,
@@ -48,12 +47,10 @@ static int request_key_auth_instantiate(struct key *key,
{
key->payload.data = (struct request_key_auth *) data;
return 0;
+}
-} /* end request_key_auth_instantiate() */
-
-/*****************************************************************************/
/*
- * reading a request-key authorisation key retrieves the callout information
+ * Describe an authorisation token.
*/
static void request_key_auth_describe(const struct key *key,
struct seq_file *m)
@@ -63,12 +60,10 @@ static void request_key_auth_describe(const struct key *key,
seq_puts(m, "key:");
seq_puts(m, key->description);
seq_printf(m, " pid:%d ci:%zu", rka->pid, rka->callout_len);
+}
-} /* end request_key_auth_describe() */
-
-/*****************************************************************************/
/*
- * read the callout_info data
+ * Read the callout_info data (retrieves the callout information).
* - the key's semaphore is read-locked
*/
static long request_key_auth_read(const struct key *key,
@@ -91,13 +86,12 @@ static long request_key_auth_read(const struct key *key,
}
return ret;
+}
-} /* end request_key_auth_read() */
-
-/*****************************************************************************/
/*
- * handle revocation of an authorisation token key
- * - called with the key sem write-locked
+ * Handle revocation of an authorisation token key.
+ *
+ * Called with the key sem write-locked.
*/
static void request_key_auth_revoke(struct key *key)
{
@@ -109,12 +103,10 @@ static void request_key_auth_revoke(struct key *key)
put_cred(rka->cred);
rka->cred = NULL;
}
+}
-} /* end request_key_auth_revoke() */
-
-/*****************************************************************************/
/*
- * destroy an instantiation authorisation token key
+ * Destroy an instantiation authorisation token key.
*/
static void request_key_auth_destroy(struct key *key)
{
@@ -131,13 +123,11 @@ static void request_key_auth_destroy(struct key *key)
key_put(rka->dest_keyring);
kfree(rka->callout_info);
kfree(rka);
+}
-} /* end request_key_auth_destroy() */
-
-/*****************************************************************************/
/*
- * create an authorisation token for /sbin/request-key or whoever to gain
- * access to the caller's security data
+ * Create an authorisation token for /sbin/request-key or whoever to gain
+ * access to the caller's security data.
*/
struct key *request_key_auth_new(struct key *target, const void *callout_info,
size_t callout_len, struct key *dest_keyring)
@@ -228,12 +218,10 @@ error_alloc:
kfree(rka);
kleave("= %d", ret);
return ERR_PTR(ret);
+}
-} /* end request_key_auth_new() */
-
-/*****************************************************************************/
/*
- * see if an authorisation key is associated with a particular key
+ * See if an authorisation key is associated with a particular key.
*/
static int key_get_instantiation_authkey_match(const struct key *key,
const void *_id)
@@ -242,16 +230,11 @@ static int key_get_instantiation_authkey_match(const struct key *key,
key_serial_t id = (key_serial_t)(unsigned long) _id;
return rka->target_key->serial == id;
+}
-} /* end key_get_instantiation_authkey_match() */
-
-/*****************************************************************************/
/*
- * get the authorisation key for instantiation of a specific key if attached to
- * the current process's keyrings
- * - this key is inserted into a keyring and that is set as /sbin/request-key's
- * session keyring
- * - a target_id of zero specifies any valid token
+ * Search the current process's keyrings for the authorisation key for
+ * instantiation of a key.
*/
struct key *key_get_instantiation_authkey(key_serial_t target_id)
{
@@ -278,5 +261,4 @@ struct key *key_get_instantiation_authkey(key_serial_t target_id)
error:
return authkey;
-
-} /* end key_get_instantiation_authkey() */
+}
diff --git a/security/keys/trusted_defined.c b/security/keys/trusted.c
index 975e9f2..83fc92e 100644
--- a/security/keys/trusted_defined.c
+++ b/security/keys/trusted.c
@@ -29,7 +29,7 @@
#include <linux/tpm.h>
#include <linux/tpm_command.h>
-#include "trusted_defined.h"
+#include "trusted.h"
static const char hmac_alg[] = "hmac(sha1)";
static const char hash_alg[] = "sha1";
@@ -101,11 +101,13 @@ static int TSS_rawhmac(unsigned char *digest, const unsigned char *key,
if (dlen == 0)
break;
data = va_arg(argp, unsigned char *);
- if (data == NULL)
- return -EINVAL;
+ if (data == NULL) {
+ ret = -EINVAL;
+ break;
+ }
ret = crypto_shash_update(&sdesc->shash, data, dlen);
if (ret < 0)
- goto out;
+ break;
}
va_end(argp);
if (!ret)
@@ -146,14 +148,17 @@ static int TSS_authhmac(unsigned char *digest, const unsigned char *key,
if (dlen == 0)
break;
data = va_arg(argp, unsigned char *);
- ret = crypto_shash_update(&sdesc->shash, data, dlen);
- if (ret < 0) {
- va_end(argp);
- goto out;
+ if (!data) {
+ ret = -EINVAL;
+ break;
}
+ ret = crypto_shash_update(&sdesc->shash, data, dlen);
+ if (ret < 0)
+ break;
}
va_end(argp);
- ret = crypto_shash_final(&sdesc->shash, paramdigest);
+ if (!ret)
+ ret = crypto_shash_final(&sdesc->shash, paramdigest);
if (!ret)
ret = TSS_rawhmac(digest, key, keylen, SHA1_DIGEST_SIZE,
paramdigest, TPM_NONCE_SIZE, h1,
@@ -222,13 +227,12 @@ static int TSS_checkhmac1(unsigned char *buffer,
break;
dpos = va_arg(argp, unsigned int);
ret = crypto_shash_update(&sdesc->shash, buffer + dpos, dlen);
- if (ret < 0) {
- va_end(argp);
- goto out;
- }
+ if (ret < 0)
+ break;
}
va_end(argp);
- ret = crypto_shash_final(&sdesc->shash, paramdigest);
+ if (!ret)
+ ret = crypto_shash_final(&sdesc->shash, paramdigest);
if (ret < 0)
goto out;
@@ -316,13 +320,12 @@ static int TSS_checkhmac2(unsigned char *buffer,
break;
dpos = va_arg(argp, unsigned int);
ret = crypto_shash_update(&sdesc->shash, buffer + dpos, dlen);
- if (ret < 0) {
- va_end(argp);
- goto out;
- }
+ if (ret < 0)
+ break;
}
va_end(argp);
- ret = crypto_shash_final(&sdesc->shash, paramdigest);
+ if (!ret)
+ ret = crypto_shash_final(&sdesc->shash, paramdigest);
if (ret < 0)
goto out;
@@ -511,7 +514,7 @@ static int tpm_seal(struct tpm_buf *tb, uint16_t keytype,
/* get session for sealing key */
ret = osap(tb, &sess, keyauth, keytype, keyhandle);
if (ret < 0)
- return ret;
+ goto out;
dump_sess(&sess);
/* calculate encrypted authorization value */
@@ -519,11 +522,11 @@ static int tpm_seal(struct tpm_buf *tb, uint16_t keytype,
memcpy(td->xorwork + SHA1_DIGEST_SIZE, sess.enonce, SHA1_DIGEST_SIZE);
ret = TSS_sha1(td->xorwork, SHA1_DIGEST_SIZE * 2, td->xorhash);
if (ret < 0)
- return ret;
+ goto out;
ret = tpm_get_random(tb, td->nonceodd, TPM_NONCE_SIZE);
if (ret < 0)
- return ret;
+ goto out;
ordinal = htonl(TPM_ORD_SEAL);
datsize = htonl(datalen);
pcrsize = htonl(pcrinfosize);
@@ -552,7 +555,7 @@ static int tpm_seal(struct tpm_buf *tb, uint16_t keytype,
&datsize, datalen, data, 0, 0);
}
if (ret < 0)
- return ret;
+ goto out;
/* build and send the TPM request packet */
INIT_BUF(tb);
@@ -572,7 +575,7 @@ static int tpm_seal(struct tpm_buf *tb, uint16_t keytype,
ret = trusted_tpm_send(TPM_ANY_NUM, tb->data, MAX_BUF_SIZE);
if (ret < 0)
- return ret;
+ goto out;
/* calculate the size of the returned Blob */
sealinfosize = LOAD32(tb->data, TPM_DATA_OFFSET + sizeof(uint32_t));
@@ -591,6 +594,8 @@ static int tpm_seal(struct tpm_buf *tb, uint16_t keytype,
memcpy(blob, tb->data + TPM_DATA_OFFSET, storedsize);
*bloblen = storedsize;
}
+out:
+ kfree(td);
return ret;
}
@@ -1027,6 +1032,7 @@ static int trusted_update(struct key *key, const void *data, size_t datalen)
ret = datablob_parse(datablob, new_p, new_o);
if (ret != Opt_update) {
ret = -EINVAL;
+ kfree(new_p);
goto out;
}
/* copy old key values, and reseal with new pcrs */
diff --git a/security/keys/trusted_defined.h b/security/keys/trusted.h
index 3249fbd..3249fbd 100644
--- a/security/keys/trusted_defined.h
+++ b/security/keys/trusted.h
diff --git a/security/keys/user_defined.c b/security/keys/user_defined.c
index e9aa079..02807fb 100644
--- a/security/keys/user_defined.c
+++ b/security/keys/user_defined.c
@@ -35,7 +35,6 @@ struct key_type key_type_user = {
EXPORT_SYMBOL_GPL(key_type_user);
-/*****************************************************************************/
/*
* instantiate a user defined key
*/
@@ -65,12 +64,10 @@ int user_instantiate(struct key *key, const void *data, size_t datalen)
error:
return ret;
-
-} /* end user_instantiate() */
+}
EXPORT_SYMBOL_GPL(user_instantiate);
-/*****************************************************************************/
/*
* dispose of the old data from an updated user defined key
*/
@@ -81,10 +78,8 @@ static void user_update_rcu_disposal(struct rcu_head *rcu)
upayload = container_of(rcu, struct user_key_payload, rcu);
kfree(upayload);
+}
-} /* end user_update_rcu_disposal() */
-
-/*****************************************************************************/
/*
* update a user defined key
* - the key's semaphore is write-locked
@@ -123,24 +118,20 @@ int user_update(struct key *key, const void *data, size_t datalen)
error:
return ret;
-
-} /* end user_update() */
+}
EXPORT_SYMBOL_GPL(user_update);
-/*****************************************************************************/
/*
* match users on their name
*/
int user_match(const struct key *key, const void *description)
{
return strcmp(key->description, description) == 0;
-
-} /* end user_match() */
+}
EXPORT_SYMBOL_GPL(user_match);
-/*****************************************************************************/
/*
* dispose of the links from a revoked keyring
* - called with the key sem write-locked
@@ -156,12 +147,10 @@ void user_revoke(struct key *key)
rcu_assign_pointer(key->payload.data, NULL);
call_rcu(&upayload->rcu, user_update_rcu_disposal);
}
-
-} /* end user_revoke() */
+}
EXPORT_SYMBOL(user_revoke);
-/*****************************************************************************/
/*
* dispose of the data dangling from the corpse of a user key
*/
@@ -170,12 +159,10 @@ void user_destroy(struct key *key)
struct user_key_payload *upayload = key->payload.data;
kfree(upayload);
-
-} /* end user_destroy() */
+}
EXPORT_SYMBOL_GPL(user_destroy);
-/*****************************************************************************/
/*
* describe the user key
*/
@@ -184,12 +171,10 @@ void user_describe(const struct key *key, struct seq_file *m)
seq_puts(m, key->description);
seq_printf(m, ": %u", key->datalen);
-
-} /* end user_describe() */
+}
EXPORT_SYMBOL_GPL(user_describe);
-/*****************************************************************************/
/*
* read the key data
* - the key's semaphore is read-locked
@@ -213,7 +198,6 @@ long user_read(const struct key *key, char __user *buffer, size_t buflen)
}
return ret;
-
-} /* end user_read() */
+}
EXPORT_SYMBOL_GPL(user_read);
diff --git a/security/selinux/ss/conditional.c b/security/selinux/ss/conditional.c
index c3f845c..a533732 100644
--- a/security/selinux/ss/conditional.c
+++ b/security/selinux/ss/conditional.c
@@ -178,7 +178,7 @@ int cond_init_bool_indexes(struct policydb *p)
p->bool_val_to_struct = (struct cond_bool_datum **)
kmalloc(p->p_bools.nprim * sizeof(struct cond_bool_datum *), GFP_KERNEL);
if (!p->bool_val_to_struct)
- return -1;
+ return -ENOMEM;
return 0;
}
diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c
index be9de38..5736356 100644
--- a/security/selinux/ss/policydb.c
+++ b/security/selinux/ss/policydb.c
@@ -501,8 +501,8 @@ static int policydb_index(struct policydb *p)
if (rc)
goto out;
- rc = -ENOMEM;
- if (cond_init_bool_indexes(p))
+ rc = cond_init_bool_indexes(p);
+ if (rc)
goto out;
for (i = 0; i < SYM_NUM; i++) {
diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c
index 0fc614c..cb62d17 100644
--- a/sound/pci/ac97/ac97_codec.c
+++ b/sound/pci/ac97/ac97_codec.c
@@ -1961,7 +1961,7 @@ static int snd_ac97_dev_disconnect(struct snd_device *device)
}
/* build_ops to do nothing */
-static struct snd_ac97_build_ops null_build_ops;
+static const struct snd_ac97_build_ops null_build_ops;
#ifdef CONFIG_SND_AC97_POWER_SAVE
static void do_update_power(struct work_struct *work)
diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c
index e68c98e..bf47574 100644
--- a/sound/pci/ac97/ac97_patch.c
+++ b/sound/pci/ac97/ac97_patch.c
@@ -371,7 +371,7 @@ static int patch_yamaha_ymf743_build_spdif(struct snd_ac97 *ac97)
return 0;
}
-static struct snd_ac97_build_ops patch_yamaha_ymf743_ops = {
+static const struct snd_ac97_build_ops patch_yamaha_ymf743_ops = {
.build_spdif = patch_yamaha_ymf743_build_spdif,
.build_3d = patch_yamaha_ymf7x3_3d,
};
@@ -455,7 +455,7 @@ static int patch_yamaha_ymf753_post_spdif(struct snd_ac97 * ac97)
return 0;
}
-static struct snd_ac97_build_ops patch_yamaha_ymf753_ops = {
+static const struct snd_ac97_build_ops patch_yamaha_ymf753_ops = {
.build_3d = patch_yamaha_ymf7x3_3d,
.build_post_spdif = patch_yamaha_ymf753_post_spdif
};
@@ -502,7 +502,7 @@ static int patch_wolfson_wm9703_specific(struct snd_ac97 * ac97)
return 0;
}
-static struct snd_ac97_build_ops patch_wolfson_wm9703_ops = {
+static const struct snd_ac97_build_ops patch_wolfson_wm9703_ops = {
.build_specific = patch_wolfson_wm9703_specific,
};
@@ -533,7 +533,7 @@ static int patch_wolfson_wm9704_specific(struct snd_ac97 * ac97)
return 0;
}
-static struct snd_ac97_build_ops patch_wolfson_wm9704_ops = {
+static const struct snd_ac97_build_ops patch_wolfson_wm9704_ops = {
.build_specific = patch_wolfson_wm9704_specific,
};
@@ -677,7 +677,7 @@ static int patch_wolfson_wm9711_specific(struct snd_ac97 * ac97)
return 0;
}
-static struct snd_ac97_build_ops patch_wolfson_wm9711_ops = {
+static const struct snd_ac97_build_ops patch_wolfson_wm9711_ops = {
.build_specific = patch_wolfson_wm9711_specific,
};
@@ -871,7 +871,7 @@ static void patch_wolfson_wm9713_resume (struct snd_ac97 * ac97)
}
#endif
-static struct snd_ac97_build_ops patch_wolfson_wm9713_ops = {
+static const struct snd_ac97_build_ops patch_wolfson_wm9713_ops = {
.build_specific = patch_wolfson_wm9713_specific,
.build_3d = patch_wolfson_wm9713_3d,
#ifdef CONFIG_PM
@@ -976,7 +976,7 @@ static int patch_sigmatel_stac97xx_specific(struct snd_ac97 * ac97)
return 0;
}
-static struct snd_ac97_build_ops patch_sigmatel_stac9700_ops = {
+static const struct snd_ac97_build_ops patch_sigmatel_stac9700_ops = {
.build_3d = patch_sigmatel_stac9700_3d,
.build_specific = patch_sigmatel_stac97xx_specific
};
@@ -1023,7 +1023,7 @@ static int patch_sigmatel_stac9708_specific(struct snd_ac97 *ac97)
return patch_sigmatel_stac97xx_specific(ac97);
}
-static struct snd_ac97_build_ops patch_sigmatel_stac9708_ops = {
+static const struct snd_ac97_build_ops patch_sigmatel_stac9708_ops = {
.build_3d = patch_sigmatel_stac9708_3d,
.build_specific = patch_sigmatel_stac9708_specific
};
@@ -1252,7 +1252,7 @@ static int patch_sigmatel_stac9758_specific(struct snd_ac97 *ac97)
return 0;
}
-static struct snd_ac97_build_ops patch_sigmatel_stac9758_ops = {
+static const struct snd_ac97_build_ops patch_sigmatel_stac9758_ops = {
.build_3d = patch_sigmatel_stac9700_3d,
.build_specific = patch_sigmatel_stac9758_specific
};
@@ -1327,7 +1327,7 @@ static int patch_cirrus_build_spdif(struct snd_ac97 * ac97)
return 0;
}
-static struct snd_ac97_build_ops patch_cirrus_ops = {
+static const struct snd_ac97_build_ops patch_cirrus_ops = {
.build_spdif = patch_cirrus_build_spdif
};
@@ -1384,7 +1384,7 @@ static int patch_conexant_build_spdif(struct snd_ac97 * ac97)
return 0;
}
-static struct snd_ac97_build_ops patch_conexant_ops = {
+static const struct snd_ac97_build_ops patch_conexant_ops = {
.build_spdif = patch_conexant_build_spdif
};
@@ -1560,7 +1560,7 @@ static void patch_ad1881_chained(struct snd_ac97 * ac97, int unchained_idx, int
}
}
-static struct snd_ac97_build_ops patch_ad1881_build_ops = {
+static const struct snd_ac97_build_ops patch_ad1881_build_ops = {
#ifdef CONFIG_PM
.resume = ad18xx_resume
#endif
@@ -1647,7 +1647,7 @@ static int patch_ad1885_specific(struct snd_ac97 * ac97)
return 0;
}
-static struct snd_ac97_build_ops patch_ad1885_build_ops = {
+static const struct snd_ac97_build_ops patch_ad1885_build_ops = {
.build_specific = &patch_ad1885_specific,
#ifdef CONFIG_PM
.resume = ad18xx_resume
@@ -1674,7 +1674,7 @@ static int patch_ad1886_specific(struct snd_ac97 * ac97)
return 0;
}
-static struct snd_ac97_build_ops patch_ad1886_build_ops = {
+static const struct snd_ac97_build_ops patch_ad1886_build_ops = {
.build_specific = &patch_ad1886_specific,
#ifdef CONFIG_PM
.resume = ad18xx_resume
@@ -1881,7 +1881,7 @@ static int patch_ad1981a_specific(struct snd_ac97 * ac97)
ARRAY_SIZE(snd_ac97_ad1981x_jack_sense));
}
-static struct snd_ac97_build_ops patch_ad1981a_build_ops = {
+static const struct snd_ac97_build_ops patch_ad1981a_build_ops = {
.build_post_spdif = patch_ad198x_post_spdif,
.build_specific = patch_ad1981a_specific,
#ifdef CONFIG_PM
@@ -1936,7 +1936,7 @@ static int patch_ad1981b_specific(struct snd_ac97 *ac97)
ARRAY_SIZE(snd_ac97_ad1981x_jack_sense));
}
-static struct snd_ac97_build_ops patch_ad1981b_build_ops = {
+static const struct snd_ac97_build_ops patch_ad1981b_build_ops = {
.build_post_spdif = patch_ad198x_post_spdif,
.build_specific = patch_ad1981b_specific,
#ifdef CONFIG_PM
@@ -2075,7 +2075,7 @@ static int patch_ad1888_specific(struct snd_ac97 *ac97)
return patch_build_controls(ac97, snd_ac97_ad1888_controls, ARRAY_SIZE(snd_ac97_ad1888_controls));
}
-static struct snd_ac97_build_ops patch_ad1888_build_ops = {
+static const struct snd_ac97_build_ops patch_ad1888_build_ops = {
.build_post_spdif = patch_ad198x_post_spdif,
.build_specific = patch_ad1888_specific,
#ifdef CONFIG_PM
@@ -2124,7 +2124,7 @@ static int patch_ad1980_specific(struct snd_ac97 *ac97)
return patch_build_controls(ac97, &snd_ac97_ad198x_2cmic, 1);
}
-static struct snd_ac97_build_ops patch_ad1980_build_ops = {
+static const struct snd_ac97_build_ops patch_ad1980_build_ops = {
.build_post_spdif = patch_ad198x_post_spdif,
.build_specific = patch_ad1980_specific,
#ifdef CONFIG_PM
@@ -2239,7 +2239,7 @@ static int patch_ad1985_specific(struct snd_ac97 *ac97)
ARRAY_SIZE(snd_ac97_ad1985_controls));
}
-static struct snd_ac97_build_ops patch_ad1985_build_ops = {
+static const struct snd_ac97_build_ops patch_ad1985_build_ops = {
.build_post_spdif = patch_ad198x_post_spdif,
.build_specific = patch_ad1985_specific,
#ifdef CONFIG_PM
@@ -2531,7 +2531,7 @@ static int patch_ad1986_specific(struct snd_ac97 *ac97)
ARRAY_SIZE(snd_ac97_ad1985_controls));
}
-static struct snd_ac97_build_ops patch_ad1986_build_ops = {
+static const struct snd_ac97_build_ops patch_ad1986_build_ops = {
.build_post_spdif = patch_ad198x_post_spdif,
.build_specific = patch_ad1986_specific,
#ifdef CONFIG_PM
@@ -2636,7 +2636,7 @@ static int patch_alc650_specific(struct snd_ac97 * ac97)
return 0;
}
-static struct snd_ac97_build_ops patch_alc650_ops = {
+static const struct snd_ac97_build_ops patch_alc650_ops = {
.build_specific = patch_alc650_specific,
.update_jacks = alc650_update_jacks
};
@@ -2788,7 +2788,7 @@ static int patch_alc655_specific(struct snd_ac97 * ac97)
return 0;
}
-static struct snd_ac97_build_ops patch_alc655_ops = {
+static const struct snd_ac97_build_ops patch_alc655_ops = {
.build_specific = patch_alc655_specific,
.update_jacks = alc655_update_jacks
};
@@ -2900,7 +2900,7 @@ static int patch_alc850_specific(struct snd_ac97 *ac97)
return 0;
}
-static struct snd_ac97_build_ops patch_alc850_ops = {
+static const struct snd_ac97_build_ops patch_alc850_ops = {
.build_specific = patch_alc850_specific,
.update_jacks = alc850_update_jacks
};
@@ -2962,7 +2962,7 @@ static int patch_cm9738_specific(struct snd_ac97 * ac97)
return patch_build_controls(ac97, snd_ac97_cm9738_controls, ARRAY_SIZE(snd_ac97_cm9738_controls));
}
-static struct snd_ac97_build_ops patch_cm9738_ops = {
+static const struct snd_ac97_build_ops patch_cm9738_ops = {
.build_specific = patch_cm9738_specific,
.update_jacks = cm9738_update_jacks
};
@@ -3053,7 +3053,7 @@ static int patch_cm9739_post_spdif(struct snd_ac97 * ac97)
return patch_build_controls(ac97, snd_ac97_cm9739_controls_spdif, ARRAY_SIZE(snd_ac97_cm9739_controls_spdif));
}
-static struct snd_ac97_build_ops patch_cm9739_ops = {
+static const struct snd_ac97_build_ops patch_cm9739_ops = {
.build_specific = patch_cm9739_specific,
.build_post_spdif = patch_cm9739_post_spdif,
.update_jacks = cm9739_update_jacks
@@ -3227,7 +3227,7 @@ static int patch_cm9761_specific(struct snd_ac97 * ac97)
return patch_build_controls(ac97, snd_ac97_cm9761_controls, ARRAY_SIZE(snd_ac97_cm9761_controls));
}
-static struct snd_ac97_build_ops patch_cm9761_ops = {
+static const struct snd_ac97_build_ops patch_cm9761_ops = {
.build_specific = patch_cm9761_specific,
.build_post_spdif = patch_cm9761_post_spdif,
.update_jacks = cm9761_update_jacks
@@ -3323,7 +3323,7 @@ static int patch_cm9780_specific(struct snd_ac97 *ac97)
return patch_build_controls(ac97, cm9780_controls, ARRAY_SIZE(cm9780_controls));
}
-static struct snd_ac97_build_ops patch_cm9780_ops = {
+static const struct snd_ac97_build_ops patch_cm9780_ops = {
.build_specific = patch_cm9780_specific,
.build_post_spdif = patch_cm9761_post_spdif /* identical with CM9761 */
};
@@ -3443,7 +3443,7 @@ static int patch_vt1616_specific(struct snd_ac97 * ac97)
return 0;
}
-static struct snd_ac97_build_ops patch_vt1616_ops = {
+static const struct snd_ac97_build_ops patch_vt1616_ops = {
.build_specific = patch_vt1616_specific
};
@@ -3797,7 +3797,7 @@ static int patch_it2646_specific(struct snd_ac97 * ac97)
return 0;
}
-static struct snd_ac97_build_ops patch_it2646_ops = {
+static const struct snd_ac97_build_ops patch_it2646_ops = {
.build_specific = patch_it2646_specific,
.update_jacks = it2646_update_jacks
};
@@ -3831,7 +3831,7 @@ static int patch_si3036_specific(struct snd_ac97 * ac97)
return 0;
}
-static struct snd_ac97_build_ops patch_si3036_ops = {
+static const struct snd_ac97_build_ops patch_si3036_ops = {
.build_specific = patch_si3036_specific,
};
@@ -3898,7 +3898,7 @@ static int patch_ucb1400_specific(struct snd_ac97 * ac97)
return 0;
}
-static struct snd_ac97_build_ops patch_ucb1400_ops = {
+static const struct snd_ac97_build_ops patch_ucb1400_ops = {
.build_specific = patch_ucb1400_specific,
};
diff --git a/sound/pci/au88x0/au88x0_pcm.c b/sound/pci/au88x0/au88x0_pcm.c
index b9d2f20..5439d66 100644
--- a/sound/pci/au88x0/au88x0_pcm.c
+++ b/sound/pci/au88x0/au88x0_pcm.c
@@ -42,11 +42,7 @@ static struct snd_pcm_hardware snd_vortex_playback_hw_adb = {
.rate_min = 5000,
.rate_max = 48000,
.channels_min = 1,
-#ifdef CHIP_AU8830
- .channels_max = 4,
-#else
.channels_max = 2,
-#endif
.buffer_bytes_max = 0x10000,
.period_bytes_min = 0x1,
.period_bytes_max = 0x1000,
@@ -115,6 +111,17 @@ static struct snd_pcm_hardware snd_vortex_playback_hw_wt = {
.periods_max = 64,
};
#endif
+#ifdef CHIP_AU8830
+static unsigned int au8830_channels[3] = {
+ 1, 2, 4,
+};
+
+static struct snd_pcm_hw_constraint_list hw_constraints_au8830_channels = {
+ .count = ARRAY_SIZE(au8830_channels),
+ .list = au8830_channels,
+ .mask = 0,
+};
+#endif
/* open callback */
static int snd_vortex_pcm_open(struct snd_pcm_substream *substream)
{
@@ -156,6 +163,15 @@ static int snd_vortex_pcm_open(struct snd_pcm_substream *substream)
if (VORTEX_PCM_TYPE(substream->pcm) == VORTEX_PCM_ADB
|| VORTEX_PCM_TYPE(substream->pcm) == VORTEX_PCM_I2S)
runtime->hw = snd_vortex_playback_hw_adb;
+#ifdef CHIP_AU8830
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
+ VORTEX_PCM_TYPE(substream->pcm) == VORTEX_PCM_ADB) {
+ runtime->hw.channels_max = 4;
+ snd_pcm_hw_constraint_list(runtime, 0,
+ SNDRV_PCM_HW_PARAM_CHANNELS,
+ &hw_constraints_au8830_channels);
+ }
+#endif
substream->runtime->private_data = NULL;
}
#ifndef CHIP_AU8810
diff --git a/sound/pci/cs5535audio/cs5535audio_pm.c b/sound/pci/cs5535audio/cs5535audio_pm.c
index a3301cc..185b000 100644
--- a/sound/pci/cs5535audio/cs5535audio_pm.c
+++ b/sound/pci/cs5535audio/cs5535audio_pm.c
@@ -90,12 +90,7 @@ int snd_cs5535audio_resume(struct pci_dev *pci)
int i;
pci_set_power_state(pci, PCI_D0);
- if (pci_restore_state(pci) < 0) {
- printk(KERN_ERR "cs5535audio: pci_restore_state failed, "
- "disabling device\n");
- snd_card_disconnect(card);
- return -EIO;
- }
+ pci_restore_state(pci);
if (pci_enable_device(pci) < 0) {
printk(KERN_ERR "cs5535audio: pci_enable_device failed, "
"disabling device\n");
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index 05e5ec8..ae5c5d5e 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -2134,10 +2134,10 @@ int snd_hda_codec_reset(struct hda_codec *codec)
* This function returns zero if successful or a negative error code.
*/
int snd_hda_add_vmaster(struct hda_codec *codec, char *name,
- unsigned int *tlv, const char **slaves)
+ unsigned int *tlv, const char * const *slaves)
{
struct snd_kcontrol *kctl;
- const char **s;
+ const char * const *s;
int err;
for (s = slaves; *s && !snd_hda_find_mixer_ctl(codec, *s); s++)
@@ -3689,7 +3689,7 @@ EXPORT_SYMBOL_HDA(snd_hda_build_pcms);
* If no entries are matching, the function returns a negative value.
*/
int snd_hda_check_board_config(struct hda_codec *codec,
- int num_configs, const char **models,
+ int num_configs, const char * const *models,
const struct snd_pci_quirk *tbl)
{
if (codec->modelname && models) {
@@ -3753,7 +3753,7 @@ EXPORT_SYMBOL_HDA(snd_hda_check_board_config);
* If no entries are matching, the function returns a negative value.
*/
int snd_hda_check_board_codec_sid_config(struct hda_codec *codec,
- int num_configs, const char **models,
+ int num_configs, const char * const *models,
const struct snd_pci_quirk *tbl)
{
const struct snd_pci_quirk *q;
@@ -4690,7 +4690,7 @@ const char *hda_get_input_pin_label(struct hda_codec *codec, hda_nid_t pin,
int check_location)
{
unsigned int def_conf;
- static const char *mic_names[] = {
+ static const char * const mic_names[] = {
"Internal Mic", "Dock Mic", "Mic", "Front Mic", "Rear Mic",
};
int attr;
diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c
index fb0582f8..a63c54d 100644
--- a/sound/pci/hda/hda_generic.c
+++ b/sound/pci/hda/hda_generic.c
@@ -762,7 +762,8 @@ static int check_existing_control(struct hda_codec *codec, const char *type, con
/*
* build output mixer controls
*/
-static int create_output_mixers(struct hda_codec *codec, const char **names)
+static int create_output_mixers(struct hda_codec *codec,
+ const char * const *names)
{
struct hda_gspec *spec = codec->spec;
int i, err;
@@ -780,8 +781,8 @@ static int create_output_mixers(struct hda_codec *codec, const char **names)
static int build_output_controls(struct hda_codec *codec)
{
struct hda_gspec *spec = codec->spec;
- static const char *types_speaker[] = { "Speaker", "Headphone" };
- static const char *types_line[] = { "Front", "Headphone" };
+ static const char * const types_speaker[] = { "Speaker", "Headphone" };
+ static const char * const types_line[] = { "Front", "Headphone" };
switch (spec->pcm_vol_nodes) {
case 1:
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index d3d18be..2e91a99 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -2809,6 +2809,8 @@ static DEFINE_PCI_DEVICE_TABLE(azx_ids) = {
#endif
/* Vortex86MX */
{ PCI_DEVICE(0x17f3, 0x3010), .driver_data = AZX_DRIVER_GENERIC },
+ /* VMware HDAudio */
+ { PCI_DEVICE(0x15ad, 0x1977), .driver_data = AZX_DRIVER_GENERIC },
/* AMD/ATI Generic, PCI class code and Vendor ID for HD Audio */
{ PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_ANY_ID),
.class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8,
diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h
index 46bbefe..3ab5e7a 100644
--- a/sound/pci/hda/hda_local.h
+++ b/sound/pci/hda/hda_local.h
@@ -140,7 +140,7 @@ void snd_hda_set_vmaster_tlv(struct hda_codec *codec, hda_nid_t nid, int dir,
struct snd_kcontrol *snd_hda_find_mixer_ctl(struct hda_codec *codec,
const char *name);
int snd_hda_add_vmaster(struct hda_codec *codec, char *name,
- unsigned int *tlv, const char **slaves);
+ unsigned int *tlv, const char * const *slaves);
int snd_hda_codec_reset(struct hda_codec *codec);
/* amp value bits */
@@ -341,10 +341,10 @@ void snd_print_pcm_bits(int pcm, char *buf, int buflen);
* Misc
*/
int snd_hda_check_board_config(struct hda_codec *codec, int num_configs,
- const char **modelnames,
+ const char * const *modelnames,
const struct snd_pci_quirk *pci_list);
int snd_hda_check_board_codec_sid_config(struct hda_codec *codec,
- int num_configs, const char **models,
+ int num_configs, const char * const *models,
const struct snd_pci_quirk *tbl);
int snd_hda_add_new_ctls(struct hda_codec *codec,
struct snd_kcontrol_new *knew);
diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c
index f025200..bfe74c2 100644
--- a/sound/pci/hda/hda_proc.c
+++ b/sound/pci/hda/hda_proc.c
@@ -418,7 +418,7 @@ static void print_digital_conv(struct snd_info_buffer *buffer,
static const char *get_pwr_state(u32 state)
{
- static const char *buf[4] = {
+ static const char * const buf[4] = {
"D0", "D1", "D2", "D3"
};
if (state < 4)
diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c
index 4678067..8dabab7 100644
--- a/sound/pci/hda/patch_analog.c
+++ b/sound/pci/hda/patch_analog.c
@@ -46,6 +46,9 @@ struct ad198x_spec {
unsigned int cur_eapd;
unsigned int need_dac_fix;
+ hda_nid_t *alt_dac_nid;
+ struct hda_pcm_stream *stream_analog_alt_playback;
+
/* capture */
unsigned int num_adc_nids;
hda_nid_t *adc_nids;
@@ -81,8 +84,8 @@ struct ad198x_spec {
#endif
/* for virtual master */
hda_nid_t vmaster_nid;
- const char **slave_vols;
- const char **slave_sws;
+ const char * const *slave_vols;
+ const char * const *slave_sws;
};
/*
@@ -130,7 +133,7 @@ static int ad198x_init(struct hda_codec *codec)
return 0;
}
-static const char *ad_slave_vols[] = {
+static const char * const ad_slave_vols[] = {
"Front Playback Volume",
"Surround Playback Volume",
"Center Playback Volume",
@@ -143,7 +146,7 @@ static const char *ad_slave_vols[] = {
NULL
};
-static const char *ad_slave_sws[] = {
+static const char * const ad_slave_sws[] = {
"Front Playback Switch",
"Surround Playback Switch",
"Center Playback Switch",
@@ -156,6 +159,25 @@ static const char *ad_slave_sws[] = {
NULL
};
+static const char * const ad1988_6stack_fp_slave_vols[] = {
+ "Front Playback Volume",
+ "Surround Playback Volume",
+ "Center Playback Volume",
+ "LFE Playback Volume",
+ "Side Playback Volume",
+ "IEC958 Playback Volume",
+ NULL
+};
+
+static const char * const ad1988_6stack_fp_slave_sws[] = {
+ "Front Playback Switch",
+ "Surround Playback Switch",
+ "Center Playback Switch",
+ "LFE Playback Switch",
+ "Side Playback Switch",
+ "IEC958 Playback Switch",
+ NULL
+};
static void ad198x_free_kctls(struct hda_codec *codec);
#ifdef CONFIG_SND_HDA_INPUT_BEEP
@@ -309,6 +331,38 @@ static int ad198x_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
}
+static int ad198x_alt_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
+ struct hda_codec *codec,
+ unsigned int stream_tag,
+ unsigned int format,
+ struct snd_pcm_substream *substream)
+{
+ struct ad198x_spec *spec = codec->spec;
+ snd_hda_codec_setup_stream(codec, spec->alt_dac_nid[0], stream_tag,
+ 0, format);
+ return 0;
+}
+
+static int ad198x_alt_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
+ struct hda_codec *codec,
+ struct snd_pcm_substream *substream)
+{
+ struct ad198x_spec *spec = codec->spec;
+ snd_hda_codec_cleanup_stream(codec, spec->alt_dac_nid[0]);
+ return 0;
+}
+
+static struct hda_pcm_stream ad198x_pcm_analog_alt_playback = {
+ .substreams = 1,
+ .channels_min = 2,
+ .channels_max = 2,
+ /* NID is set in ad198x_build_pcms */
+ .ops = {
+ .prepare = ad198x_alt_playback_pcm_prepare,
+ .cleanup = ad198x_alt_playback_pcm_cleanup
+ },
+};
+
/*
* Digital out
*/
@@ -446,6 +500,17 @@ static int ad198x_build_pcms(struct hda_codec *codec)
}
}
+ if (spec->alt_dac_nid && spec->stream_analog_alt_playback) {
+ codec->num_pcms++;
+ info = spec->pcm_rec + 2;
+ info->name = "AD198x Headphone";
+ info->pcm_type = HDA_PCM_TYPE_AUDIO;
+ info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
+ *spec->stream_analog_alt_playback;
+ info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid =
+ spec->alt_dac_nid[0];
+ }
+
return 0;
}
@@ -1069,7 +1134,7 @@ enum {
AD1986A_MODELS
};
-static const char *ad1986a_models[AD1986A_MODELS] = {
+static const char * const ad1986a_models[AD1986A_MODELS] = {
[AD1986A_6STACK] = "6stack",
[AD1986A_3STACK] = "3stack",
[AD1986A_LAPTOP] = "laptop",
@@ -1813,7 +1878,7 @@ enum {
AD1981_MODELS
};
-static const char *ad1981_models[AD1981_MODELS] = {
+static const char * const ad1981_models[AD1981_MODELS] = {
[AD1981_HP] = "hp",
[AD1981_THINKPAD] = "thinkpad",
[AD1981_BASIC] = "basic",
@@ -2015,6 +2080,7 @@ static int patch_ad1981(struct hda_codec *codec)
enum {
AD1988_6STACK,
AD1988_6STACK_DIG,
+ AD1988_6STACK_DIG_FP,
AD1988_3STACK,
AD1988_3STACK_DIG,
AD1988_LAPTOP,
@@ -2047,6 +2113,10 @@ static hda_nid_t ad1988_6stack_dac_nids_rev2[4] = {
0x04, 0x05, 0x0a, 0x06
};
+static hda_nid_t ad1988_alt_dac_nid[1] = {
+ 0x03
+};
+
static hda_nid_t ad1988_3stack_dac_nids_rev2[3] = {
0x04, 0x0a, 0x06
};
@@ -2166,6 +2236,35 @@ static struct snd_kcontrol_new ad1988_6stack_mixers2[] = {
{ } /* end */
};
+static struct snd_kcontrol_new ad1988_6stack_fp_mixers[] = {
+ HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
+
+ HDA_BIND_MUTE("Front Playback Switch", 0x29, 2, HDA_INPUT),
+ HDA_BIND_MUTE("Surround Playback Switch", 0x2a, 2, HDA_INPUT),
+ HDA_BIND_MUTE_MONO("Center Playback Switch", 0x27, 1, 2, HDA_INPUT),
+ HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x27, 2, 2, HDA_INPUT),
+ HDA_BIND_MUTE("Side Playback Switch", 0x28, 2, HDA_INPUT),
+ HDA_BIND_MUTE("Headphone Playback Switch", 0x22, 2, HDA_INPUT),
+ HDA_BIND_MUTE("Mono Playback Switch", 0x1e, 2, HDA_INPUT),
+
+ HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x6, HDA_INPUT),
+ HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x6, HDA_INPUT),
+ HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x0, HDA_INPUT),
+ HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x1, HDA_INPUT),
+ HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x1, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x4, HDA_INPUT),
+ HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x4, HDA_INPUT),
+
+ HDA_CODEC_VOLUME("Analog Mix Playback Volume", 0x21, 0x0, HDA_OUTPUT),
+ HDA_CODEC_MUTE("Analog Mix Playback Switch", 0x21, 0x0, HDA_OUTPUT),
+
+ HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x39, 0x0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME("Mic Boost Volume", 0x3c, 0x0, HDA_OUTPUT),
+
+ { } /* end */
+};
+
/* 3-stack mode */
static struct snd_kcontrol_new ad1988_3stack_mixers1[] = {
HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT),
@@ -2445,6 +2544,68 @@ static struct hda_verb ad1988_6stack_init_verbs[] = {
{ }
};
+static struct hda_verb ad1988_6stack_fp_init_verbs[] = {
+ /* Front, Surround, CLFE, side DAC; unmute as default */
+ {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ /* Headphone; unmute as default */
+ {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ /* Port-A front headphon path */
+ {0x37, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC0:03h */
+ {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+ {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+ {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+ /* Port-D line-out path */
+ {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+ {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+ {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+ /* Port-F surround path */
+ {0x2a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+ {0x2a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+ {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+ /* Port-G CLFE path */
+ {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+ {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+ {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+ /* Port-H side path */
+ {0x28, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+ {0x28, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+ {0x25, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ {0x25, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+ /* Mono out path */
+ {0x36, AC_VERB_SET_CONNECT_SEL, 0x1}, /* DAC1:04h */
+ {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+ {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+ {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+ {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb01f}, /* unmute, 0dB */
+ /* Port-B front mic-in path */
+ {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+ {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+ {0x39, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+ /* Port-C line-in path */
+ {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+ {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+ {0x3a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+ {0x33, AC_VERB_SET_CONNECT_SEL, 0x0},
+ /* Port-E mic-in path */
+ {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+ {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+ {0x3c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+ {0x34, AC_VERB_SET_CONNECT_SEL, 0x0},
+ /* Analog CD Input */
+ {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+ /* Analog Mix output amp */
+ {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */
+
+ { }
+};
+
static struct hda_verb ad1988_capture_init_verbs[] = {
/* mute analog mix */
{0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
@@ -2792,7 +2953,9 @@ static int ad1988_auto_create_multi_out_ctls(struct ad198x_spec *spec,
const struct auto_pin_cfg *cfg)
{
char name[32];
- static const char *chname[4] = { "Front", "Surround", NULL /*CLFE*/, "Side" };
+ static const char * const chname[4] = {
+ "Front", "Surround", NULL /*CLFE*/, "Side"
+ };
hda_nid_t nid;
int i, err;
@@ -3074,13 +3237,13 @@ static int ad1988_auto_init(struct hda_codec *codec)
return 0;
}
-
/*
*/
-static const char *ad1988_models[AD1988_MODEL_LAST] = {
+static const char * const ad1988_models[AD1988_MODEL_LAST] = {
[AD1988_6STACK] = "6stack",
[AD1988_6STACK_DIG] = "6stack-dig",
+ [AD1988_6STACK_DIG_FP] = "6stack-dig-fp",
[AD1988_3STACK] = "3stack",
[AD1988_3STACK_DIG] = "3stack-dig",
[AD1988_LAPTOP] = "laptop",
@@ -3140,6 +3303,7 @@ static int patch_ad1988(struct hda_codec *codec)
switch (board_config) {
case AD1988_6STACK:
case AD1988_6STACK_DIG:
+ case AD1988_6STACK_DIG_FP:
spec->multiout.max_channels = 8;
spec->multiout.num_dacs = 4;
if (is_rev2(codec))
@@ -3152,10 +3316,22 @@ static int patch_ad1988(struct hda_codec *codec)
spec->mixers[0] = ad1988_6stack_mixers1_rev2;
else
spec->mixers[0] = ad1988_6stack_mixers1;
- spec->mixers[1] = ad1988_6stack_mixers2;
+ if (board_config == AD1988_6STACK_DIG_FP) {
+ spec->mixers[1] = ad1988_6stack_fp_mixers;
+ spec->slave_vols = ad1988_6stack_fp_slave_vols;
+ spec->slave_sws = ad1988_6stack_fp_slave_sws;
+ spec->alt_dac_nid = ad1988_alt_dac_nid;
+ spec->stream_analog_alt_playback =
+ &ad198x_pcm_analog_alt_playback;
+ } else
+ spec->mixers[1] = ad1988_6stack_mixers2;
spec->num_init_verbs = 1;
- spec->init_verbs[0] = ad1988_6stack_init_verbs;
- if (board_config == AD1988_6STACK_DIG) {
+ if (board_config == AD1988_6STACK_DIG_FP)
+ spec->init_verbs[0] = ad1988_6stack_fp_init_verbs;
+ else
+ spec->init_verbs[0] = ad1988_6stack_init_verbs;
+ if ((board_config == AD1988_6STACK_DIG) ||
+ (board_config == AD1988_6STACK_DIG_FP)) {
spec->multiout.dig_out_nid = AD1988_SPDIF_OUT;
spec->dig_in_nid = AD1988_SPDIF_IN;
}
@@ -3399,7 +3575,7 @@ static struct hda_amp_list ad1884_loopbacks[] = {
};
#endif
-static const char *ad1884_slave_vols[] = {
+static const char * const ad1884_slave_vols[] = {
"PCM Playback Volume",
"Mic Playback Volume",
"Mono Playback Volume",
@@ -3637,7 +3813,7 @@ enum {
AD1984_MODELS
};
-static const char *ad1984_models[AD1984_MODELS] = {
+static const char * const ad1984_models[AD1984_MODELS] = {
[AD1984_BASIC] = "basic",
[AD1984_THINKPAD] = "thinkpad",
[AD1984_DELL_DESKTOP] = "dell_desktop",
@@ -4308,7 +4484,7 @@ enum {
AD1884A_MODELS
};
-static const char *ad1884a_models[AD1884A_MODELS] = {
+static const char * const ad1884a_models[AD1884A_MODELS] = {
[AD1884A_DESKTOP] = "desktop",
[AD1884A_LAPTOP] = "laptop",
[AD1884A_MOBILE] = "mobile",
@@ -4696,7 +4872,7 @@ enum {
AD1882_MODELS
};
-static const char *ad1882_models[AD1986A_MODELS] = {
+static const char * const ad1882_models[AD1986A_MODELS] = {
[AD1882_3STACK] = "3stack",
[AD1882_6STACK] = "6stack",
};
diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c
index 18af38e..a07b031 100644
--- a/sound/pci/hda/patch_cirrus.c
+++ b/sound/pci/hda/patch_cirrus.c
@@ -490,7 +490,7 @@ static int parse_digital_input(struct hda_codec *codec)
* create mixer controls
*/
-static const char *dir_sfx[2] = { "Playback", "Capture" };
+static const char * const dir_sfx[2] = { "Playback", "Capture" };
static int add_mute(struct hda_codec *codec, const char *name, int index,
unsigned int pval, int dir, struct snd_kcontrol **kctlp)
@@ -1156,7 +1156,7 @@ static int cs_parse_auto_config(struct hda_codec *codec)
return 0;
}
-static const char *cs420x_models[CS420X_MODELS] = {
+static const char * const cs420x_models[CS420X_MODELS] = {
[CS420X_MBP53] = "mbp53",
[CS420X_MBP55] = "mbp55",
[CS420X_IMAC27] = "imac27",
diff --git a/sound/pci/hda/patch_cmedia.c b/sound/pci/hda/patch_cmedia.c
index ff60908..1f8bbcd 100644
--- a/sound/pci/hda/patch_cmedia.c
+++ b/sound/pci/hda/patch_cmedia.c
@@ -608,7 +608,7 @@ static void cmi9880_free(struct hda_codec *codec)
/*
*/
-static const char *cmi9880_models[CMI_MODELS] = {
+static const char * const cmi9880_models[CMI_MODELS] = {
[CMI_MINIMAL] = "minimal",
[CMI_MIN_FP] = "min_fp",
[CMI_FULL] = "full",
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c
index e96581f..9bb030a 100644
--- a/sound/pci/hda/patch_conexant.c
+++ b/sound/pci/hda/patch_conexant.c
@@ -537,13 +537,13 @@ static struct snd_kcontrol_new cxt_beep_mixer[] = {
};
#endif
-static const char *slave_vols[] = {
+static const char * const slave_vols[] = {
"Headphone Playback Volume",
"Speaker Playback Volume",
NULL
};
-static const char *slave_sws[] = {
+static const char * const slave_sws[] = {
"Headphone Playback Switch",
"Speaker Playback Switch",
NULL
@@ -1134,7 +1134,7 @@ enum {
CXT5045_MODELS
};
-static const char *cxt5045_models[CXT5045_MODELS] = {
+static const char * const cxt5045_models[CXT5045_MODELS] = {
[CXT5045_LAPTOP_HPSENSE] = "laptop-hpsense",
[CXT5045_LAPTOP_MICSENSE] = "laptop-micsense",
[CXT5045_LAPTOP_HPMICSENSE] = "laptop-hpmicsense",
@@ -1579,7 +1579,7 @@ enum {
CXT5047_MODELS
};
-static const char *cxt5047_models[CXT5047_MODELS] = {
+static const char * const cxt5047_models[CXT5047_MODELS] = {
[CXT5047_LAPTOP] = "laptop",
[CXT5047_LAPTOP_HP] = "laptop-hp",
[CXT5047_LAPTOP_EAPD] = "laptop-eapd",
@@ -1995,7 +1995,7 @@ enum {
CXT5051_MODELS
};
-static const char *cxt5051_models[CXT5051_MODELS] = {
+static const char *const cxt5051_models[CXT5051_MODELS] = {
[CXT5051_LAPTOP] = "laptop",
[CXT5051_HP] = "hp",
[CXT5051_HP_DV6736] = "hp-dv6736",
@@ -3084,7 +3084,7 @@ enum {
CXT5066_MODELS
};
-static const char *cxt5066_models[CXT5066_MODELS] = {
+static const char * const cxt5066_models[CXT5066_MODELS] = {
[CXT5066_LAPTOP] = "laptop",
[CXT5066_DELL_LAPTOP] = "dell-laptop",
[CXT5066_OLPC_XO_1_5] = "olpc-xo-1_5",
@@ -3746,7 +3746,7 @@ static int cx_auto_build_output_controls(struct hda_codec *codec)
struct conexant_spec *spec = codec->spec;
int i, err;
int num_line = 0, num_hp = 0, num_spk = 0;
- static const char *texts[3] = { "Front", "Surround", "CLFE" };
+ static const char * const texts[3] = { "Front", "Surround", "CLFE" };
if (spec->dac_info_filled == 1)
return cx_auto_add_pb_volume(codec, spec->dac_info[0].dac,
diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c
index f29b97b..2d5b83f 100644
--- a/sound/pci/hda/patch_hdmi.c
+++ b/sound/pci/hda/patch_hdmi.c
@@ -817,6 +817,7 @@ static int hdmi_pcm_open(struct hda_pcm_stream *hinfo,
struct hdmi_spec *spec = codec->spec;
struct hdmi_eld *eld;
struct hda_pcm_stream *codec_pars;
+ struct snd_pcm_runtime *runtime = substream->runtime;
unsigned int idx;
for (idx = 0; idx < spec->num_cvts; idx++)
@@ -844,6 +845,14 @@ static int hdmi_pcm_open(struct hda_pcm_stream *hinfo,
hinfo->formats = codec_pars->formats;
hinfo->maxbps = codec_pars->maxbps;
}
+ /* store the updated parameters */
+ runtime->hw.channels_min = hinfo->channels_min;
+ runtime->hw.channels_max = hinfo->channels_max;
+ runtime->hw.formats = hinfo->formats;
+ runtime->hw.rates = hinfo->rates;
+
+ snd_pcm_hw_constraint_step(substream->runtime, 0,
+ SNDRV_PCM_HW_PARAM_CHANNELS, 2);
return 0;
}
@@ -1238,6 +1247,9 @@ static int simple_playback_pcm_open(struct hda_pcm_stream *hinfo,
snd_pcm_hw_constraint_list(substream->runtime, 0,
SNDRV_PCM_HW_PARAM_CHANNELS,
hw_constraints_channels);
+ } else {
+ snd_pcm_hw_constraint_step(substream->runtime, 0,
+ SNDRV_PCM_HW_PARAM_CHANNELS, 2);
}
return snd_hda_multi_out_dig_open(codec, &spec->multiout);
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index 51c08ed..be4df4c 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -303,6 +303,8 @@ struct alc_customize_define {
unsigned int fixup:1; /* Means that this sku is set by driver, not read from hw */
};
+struct alc_fixup;
+
struct alc_spec {
/* codec parameterization */
struct snd_kcontrol_new *mixers[5]; /* mixer arrays */
@@ -404,6 +406,11 @@ struct alc_spec {
/* for PLL fix */
hda_nid_t pll_nid;
unsigned int pll_coef_idx, pll_coef_bit;
+
+ /* fix-up list */
+ int fixup_id;
+ const struct alc_fixup *fixup_list;
+ const char *fixup_name;
};
/*
@@ -1683,88 +1690,133 @@ struct alc_model_fixup {
};
struct alc_fixup {
- unsigned int sku;
- const struct alc_pincfg *pins;
- const struct hda_verb *verbs;
- void (*func)(struct hda_codec *codec, const struct alc_fixup *fix,
- int pre_init);
+ int type;
+ bool chained;
+ int chain_id;
+ union {
+ unsigned int sku;
+ const struct alc_pincfg *pins;
+ const struct hda_verb *verbs;
+ void (*func)(struct hda_codec *codec,
+ const struct alc_fixup *fix,
+ int action);
+ } v;
};
-static void __alc_pick_fixup(struct hda_codec *codec,
- const struct alc_fixup *fix,
- const char *modelname,
- int pre_init)
-{
- const struct alc_pincfg *cfg;
- struct alc_spec *spec;
+enum {
+ ALC_FIXUP_INVALID,
+ ALC_FIXUP_SKU,
+ ALC_FIXUP_PINS,
+ ALC_FIXUP_VERBS,
+ ALC_FIXUP_FUNC,
+};
- cfg = fix->pins;
- if (pre_init && fix->sku) {
-#ifdef CONFIG_SND_DEBUG_VERBOSE
- snd_printdd(KERN_INFO "hda_codec: %s: Apply sku override for %s\n",
- codec->chip_name, modelname);
-#endif
- spec = codec->spec;
- spec->cdefine.sku_cfg = fix->sku;
- spec->cdefine.fixup = 1;
- }
- if (pre_init && cfg) {
-#ifdef CONFIG_SND_DEBUG_VERBOSE
- snd_printdd(KERN_INFO "hda_codec: %s: Apply pincfg for %s\n",
- codec->chip_name, modelname);
-#endif
- for (; cfg->nid; cfg++)
- snd_hda_codec_set_pincfg(codec, cfg->nid, cfg->val);
- }
- if (!pre_init && fix->verbs) {
-#ifdef CONFIG_SND_DEBUG_VERBOSE
- snd_printdd(KERN_INFO "hda_codec: %s: Apply fix-verbs for %s\n",
- codec->chip_name, modelname);
-#endif
- add_verb(codec->spec, fix->verbs);
- }
- if (fix->func) {
-#ifdef CONFIG_SND_DEBUG_VERBOSE
- snd_printdd(KERN_INFO "hda_codec: %s: Apply fix-func for %s\n",
- codec->chip_name, modelname);
-#endif
- fix->func(codec, fix, pre_init);
- }
-}
+enum {
+ ALC_FIXUP_ACT_PRE_PROBE,
+ ALC_FIXUP_ACT_PROBE,
+ ALC_FIXUP_ACT_INIT,
+};
-static void alc_pick_fixup(struct hda_codec *codec,
- const struct snd_pci_quirk *quirk,
- const struct alc_fixup *fix,
- int pre_init)
+static void alc_apply_fixup(struct hda_codec *codec, int action)
{
- quirk = snd_pci_quirk_lookup(codec->bus->pci, quirk);
- if (quirk) {
- fix += quirk->value;
+ struct alc_spec *spec = codec->spec;
+ int id = spec->fixup_id;
#ifdef CONFIG_SND_DEBUG_VERBOSE
- __alc_pick_fixup(codec, fix, quirk->name, pre_init);
-#else
- __alc_pick_fixup(codec, fix, NULL, pre_init);
+ const char *modelname = spec->fixup_name;
#endif
+ int depth = 0;
+
+ if (!spec->fixup_list)
+ return;
+
+ while (id >= 0) {
+ const struct alc_fixup *fix = spec->fixup_list + id;
+ const struct alc_pincfg *cfg;
+
+ switch (fix->type) {
+ case ALC_FIXUP_SKU:
+ if (action != ALC_FIXUP_ACT_PRE_PROBE || !fix->v.sku)
+ break;;
+ snd_printdd(KERN_INFO "hda_codec: %s: "
+ "Apply sku override for %s\n",
+ codec->chip_name, modelname);
+ spec->cdefine.sku_cfg = fix->v.sku;
+ spec->cdefine.fixup = 1;
+ break;
+ case ALC_FIXUP_PINS:
+ cfg = fix->v.pins;
+ if (action != ALC_FIXUP_ACT_PRE_PROBE || !cfg)
+ break;
+ snd_printdd(KERN_INFO "hda_codec: %s: "
+ "Apply pincfg for %s\n",
+ codec->chip_name, modelname);
+ for (; cfg->nid; cfg++)
+ snd_hda_codec_set_pincfg(codec, cfg->nid,
+ cfg->val);
+ break;
+ case ALC_FIXUP_VERBS:
+ if (action != ALC_FIXUP_ACT_PROBE || !fix->v.verbs)
+ break;
+ snd_printdd(KERN_INFO "hda_codec: %s: "
+ "Apply fix-verbs for %s\n",
+ codec->chip_name, modelname);
+ add_verb(codec->spec, fix->v.verbs);
+ break;
+ case ALC_FIXUP_FUNC:
+ if (!fix->v.func)
+ break;
+ snd_printdd(KERN_INFO "hda_codec: %s: "
+ "Apply fix-func for %s\n",
+ codec->chip_name, modelname);
+ fix->v.func(codec, fix, action);
+ break;
+ default:
+ snd_printk(KERN_ERR "hda_codec: %s: "
+ "Invalid fixup type %d\n",
+ codec->chip_name, fix->type);
+ break;
+ }
+ if (!fix[id].chained)
+ break;
+ if (++depth > 10)
+ break;
+ id = fix[id].chain_id;
}
}
-static void alc_pick_fixup_model(struct hda_codec *codec,
- const struct alc_model_fixup *models,
- const struct snd_pci_quirk *quirk,
- const struct alc_fixup *fix,
- int pre_init)
+static void alc_pick_fixup(struct hda_codec *codec,
+ const struct alc_model_fixup *models,
+ const struct snd_pci_quirk *quirk,
+ const struct alc_fixup *fixlist)
{
+ struct alc_spec *spec = codec->spec;
+ int id = -1;
+ const char *name = NULL;
+
if (codec->modelname && models) {
while (models->name) {
if (!strcmp(codec->modelname, models->name)) {
- fix += models->id;
+ id = models->id;
+ name = models->name;
break;
}
models++;
}
- __alc_pick_fixup(codec, fix, codec->modelname, pre_init);
- } else {
- alc_pick_fixup(codec, quirk, fix, pre_init);
+ }
+ if (id < 0) {
+ quirk = snd_pci_quirk_lookup(codec->bus->pci, quirk);
+ if (quirk) {
+ id = quirk->value;
+#ifdef CONFIG_SND_DEBUG_VERBOSE
+ name = quirk->name;
+#endif
+ }
+ }
+
+ spec->fixup_id = id;
+ if (id >= 0) {
+ spec->fixup_list = fixlist;
+ spec->fixup_name = name;
}
}
@@ -2866,7 +2918,7 @@ static struct snd_kcontrol_new alc880_uniwill_p53_mixer[] = {
/*
* slave controls for virtual master
*/
-static const char *alc_slave_vols[] = {
+static const char * const alc_slave_vols[] = {
"Front Playback Volume",
"Surround Playback Volume",
"Center Playback Volume",
@@ -2880,7 +2932,7 @@ static const char *alc_slave_vols[] = {
NULL,
};
-static const char *alc_slave_sws[] = {
+static const char * const alc_slave_sws[] = {
"Front Playback Switch",
"Surround Playback Switch",
"Center Playback Switch",
@@ -3861,6 +3913,8 @@ static int alc_init(struct hda_codec *codec)
if (spec->init_hook)
spec->init_hook(codec);
+ alc_apply_fixup(codec, ALC_FIXUP_ACT_INIT);
+
hda_call_check_power_status(codec, 0x01);
return 0;
}
@@ -4559,7 +4613,7 @@ static struct hda_verb alc880_test_init_verbs[] = {
/*
*/
-static const char *alc880_models[ALC880_MODEL_LAST] = {
+static const char * const alc880_models[ALC880_MODEL_LAST] = {
[ALC880_3ST] = "3stack",
[ALC880_TCL_S700] = "tcl",
[ALC880_3ST_DIG] = "3stack-digout",
@@ -5092,7 +5146,7 @@ static const char *alc_get_line_out_pfx(const struct auto_pin_cfg *cfg,
static int alc880_auto_create_multi_out_ctls(struct alc_spec *spec,
const struct auto_pin_cfg *cfg)
{
- static const char *chname[4] = {
+ static const char * const chname[4] = {
"Front", "Surround", NULL /*CLFE*/, "Side"
};
const char *pfx = alc_get_line_out_pfx(cfg, false);
@@ -7090,7 +7144,8 @@ enum {
static const struct alc_fixup alc260_fixups[] = {
[PINFIX_HP_DC5750] = {
- .pins = (const struct alc_pincfg[]) {
+ .type = ALC_FIXUP_PINS,
+ .v.pins = (const struct alc_pincfg[]) {
{ 0x11, 0x90130110 }, /* speaker */
{ }
}
@@ -7105,7 +7160,7 @@ static struct snd_pci_quirk alc260_fixup_tbl[] = {
/*
* ALC260 configurations
*/
-static const char *alc260_models[ALC260_MODEL_LAST] = {
+static const char * const alc260_models[ALC260_MODEL_LAST] = {
[ALC260_BASIC] = "basic",
[ALC260_HP] = "hp",
[ALC260_HP_3013] = "hp-3013",
@@ -7301,8 +7356,10 @@ static int patch_alc260(struct hda_codec *codec)
board_config = ALC260_AUTO;
}
- if (board_config == ALC260_AUTO)
- alc_pick_fixup(codec, alc260_fixup_tbl, alc260_fixups, 1);
+ if (board_config == ALC260_AUTO) {
+ alc_pick_fixup(codec, NULL, alc260_fixup_tbl, alc260_fixups);
+ alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
+ }
if (board_config == ALC260_AUTO) {
/* automatic parse from the BIOS config */
@@ -7350,8 +7407,7 @@ static int patch_alc260(struct hda_codec *codec)
set_capture_mixer(codec);
set_beep_amp(spec, 0x07, 0x05, HDA_INPUT);
- if (board_config == ALC260_AUTO)
- alc_pick_fixup(codec, alc260_fixup_tbl, alc260_fixups, 0);
+ alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
spec->vmaster_nid = 0x08;
@@ -9727,7 +9783,7 @@ static hda_nid_t alc1200_slave_dig_outs[] = {
/*
* configuration and preset
*/
-static const char *alc882_models[ALC882_MODEL_LAST] = {
+static const char * const alc882_models[ALC882_MODEL_LAST] = {
[ALC882_3ST_DIG] = "3stack-dig",
[ALC882_6ST_DIG] = "6stack-dig",
[ALC882_ARIMA] = "arima",
@@ -10678,7 +10734,8 @@ enum {
static const struct alc_fixup alc882_fixups[] = {
[PINFIX_ABIT_AW9D_MAX] = {
- .pins = (const struct alc_pincfg[]) {
+ .type = ALC_FIXUP_PINS,
+ .v.pins = (const struct alc_pincfg[]) {
{ 0x15, 0x01080104 }, /* side */
{ 0x16, 0x01011012 }, /* rear */
{ 0x17, 0x01016011 }, /* clfe */
@@ -10686,13 +10743,15 @@ static const struct alc_fixup alc882_fixups[] = {
}
},
[PINFIX_PB_M5210] = {
- .verbs = (const struct hda_verb[]) {
+ .type = ALC_FIXUP_VERBS,
+ .v.verbs = (const struct hda_verb[]) {
{ 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50 },
{}
}
},
[PINFIX_ACER_ASPIRE_7736] = {
- .sku = ALC_FIXUP_SKU_IGNORE,
+ .type = ALC_FIXUP_SKU,
+ .v.sku = ALC_FIXUP_SKU_IGNORE,
},
};
@@ -10873,9 +10932,6 @@ static int alc_auto_add_mic_boost(struct hda_codec *codec)
return 0;
}
-static int alc861vd_auto_create_multi_out_ctls(struct alc_spec *spec,
- const struct auto_pin_cfg *cfg);
-
/* almost identical with ALC880 parser... */
static int alc882_parse_auto_config(struct hda_codec *codec)
{
@@ -10893,10 +10949,7 @@ static int alc882_parse_auto_config(struct hda_codec *codec)
err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
if (err < 0)
return err;
- if (codec->vendor_id == 0x10ec0887)
- err = alc861vd_auto_create_multi_out_ctls(spec, &spec->autocfg);
- else
- err = alc880_auto_create_multi_out_ctls(spec, &spec->autocfg);
+ err = alc880_auto_create_multi_out_ctls(spec, &spec->autocfg);
if (err < 0)
return err;
err = alc880_auto_create_extra_out(spec, spec->autocfg.hp_pins[0],
@@ -10984,8 +11037,10 @@ static int patch_alc882(struct hda_codec *codec)
board_config = ALC882_AUTO;
}
- if (board_config == ALC882_AUTO)
- alc_pick_fixup(codec, alc882_fixup_tbl, alc882_fixups, 1);
+ if (board_config == ALC882_AUTO) {
+ alc_pick_fixup(codec, NULL, alc882_fixup_tbl, alc882_fixups);
+ alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
+ }
alc_auto_parse_customize_define(codec);
@@ -11061,8 +11116,7 @@ static int patch_alc882(struct hda_codec *codec)
if (has_cdefine_beep(codec))
set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
- if (board_config == ALC882_AUTO)
- alc_pick_fixup(codec, alc882_fixup_tbl, alc882_fixups, 0);
+ alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
spec->vmaster_nid = 0x0c;
@@ -12452,19 +12506,14 @@ enum {
static const struct alc_fixup alc262_fixups[] = {
[PINFIX_FSC_H270] = {
- .pins = (const struct alc_pincfg[]) {
+ .type = ALC_FIXUP_PINS,
+ .v.pins = (const struct alc_pincfg[]) {
{ 0x14, 0x99130110 }, /* speaker */
{ 0x15, 0x0221142f }, /* front HP */
{ 0x1b, 0x0121141f }, /* rear HP */
{ }
}
},
- [PINFIX_PB_M5210] = {
- .verbs = (const struct hda_verb[]) {
- { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50 },
- {}
- }
- },
};
static struct snd_pci_quirk alc262_fixup_tbl[] = {
@@ -12554,7 +12603,7 @@ static void alc262_auto_init(struct hda_codec *codec)
/*
* configuration and preset
*/
-static const char *alc262_models[ALC262_MODEL_LAST] = {
+static const char * const alc262_models[ALC262_MODEL_LAST] = {
[ALC262_BASIC] = "basic",
[ALC262_HIPPO] = "hippo",
[ALC262_HIPPO_1] = "hippo_1",
@@ -12582,6 +12631,8 @@ static struct snd_pci_quirk alc262_cfg_tbl[] = {
ALC262_HP_BPC),
SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1300, "HP xw series",
ALC262_HP_BPC),
+ SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1500, "HP z series",
+ ALC262_HP_BPC),
SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1700, "HP xw series",
ALC262_HP_BPC),
SND_PCI_QUIRK(0x103c, 0x2800, "HP D7000", ALC262_HP_BPC_D7000_WL),
@@ -12895,8 +12946,10 @@ static int patch_alc262(struct hda_codec *codec)
board_config = ALC262_AUTO;
}
- if (board_config == ALC262_AUTO)
- alc_pick_fixup(codec, alc262_fixup_tbl, alc262_fixups, 1);
+ if (board_config == ALC262_AUTO) {
+ alc_pick_fixup(codec, NULL, alc262_fixup_tbl, alc262_fixups);
+ alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
+ }
if (board_config == ALC262_AUTO) {
/* automatic parse from the BIOS config */
@@ -12966,8 +13019,7 @@ static int patch_alc262(struct hda_codec *codec)
if (!spec->no_analog && has_cdefine_beep(codec))
set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
- if (board_config == ALC262_AUTO)
- alc_pick_fixup(codec, alc262_fixup_tbl, alc262_fixups, 0);
+ alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
spec->vmaster_nid = 0x0c;
@@ -13741,7 +13793,7 @@ static void alc268_auto_init(struct hda_codec *codec)
/*
* configuration and preset
*/
-static const char *alc268_models[ALC268_MODEL_LAST] = {
+static const char * const alc268_models[ALC268_MODEL_LAST] = {
[ALC267_QUANTA_IL1] = "quanta-il1",
[ALC268_3ST] = "3stack",
[ALC268_TOSHIBA] = "toshiba",
@@ -14822,17 +14874,19 @@ static int alc269_resume(struct hda_codec *codec)
#endif /* SND_HDA_NEEDS_RESUME */
static void alc269_fixup_hweq(struct hda_codec *codec,
- const struct alc_fixup *fix, int pre_init)
+ const struct alc_fixup *fix, int action)
{
int coef;
+ if (action != ALC_FIXUP_ACT_INIT)
+ return;
coef = alc_read_coef_idx(codec, 0x1e);
alc_write_coef_idx(codec, 0x1e, coef | 0x80);
}
enum {
ALC269_FIXUP_SONY_VAIO,
- ALC275_FIX_SONY_VAIO_GPIO2,
+ ALC275_FIXUP_SONY_VAIO_GPIO2,
ALC269_FIXUP_DELL_M101Z,
ALC269_FIXUP_SKU_IGNORE,
ALC269_FIXUP_ASUS_G73JW,
@@ -14842,22 +14896,26 @@ enum {
static const struct alc_fixup alc269_fixups[] = {
[ALC269_FIXUP_SONY_VAIO] = {
- .verbs = (const struct hda_verb[]) {
+ .type = ALC_FIXUP_VERBS,
+ .v.verbs = (const struct hda_verb[]) {
{0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREFGRD},
{}
}
},
- [ALC275_FIX_SONY_VAIO_GPIO2] = {
- .verbs = (const struct hda_verb[]) {
+ [ALC275_FIXUP_SONY_VAIO_GPIO2] = {
+ .type = ALC_FIXUP_VERBS,
+ .v.verbs = (const struct hda_verb[]) {
{0x01, AC_VERB_SET_GPIO_MASK, 0x04},
{0x01, AC_VERB_SET_GPIO_DIRECTION, 0x04},
{0x01, AC_VERB_SET_GPIO_DATA, 0x00},
- {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREFGRD},
{ }
- }
+ },
+ .chained = true,
+ .chain_id = ALC269_FIXUP_SONY_VAIO
},
[ALC269_FIXUP_DELL_M101Z] = {
- .verbs = (const struct hda_verb[]) {
+ .type = ALC_FIXUP_VERBS,
+ .v.verbs = (const struct hda_verb[]) {
/* Enables internal speaker */
{0x20, AC_VERB_SET_COEF_INDEX, 13},
{0x20, AC_VERB_SET_PROC_COEF, 0x4040},
@@ -14865,39 +14923,39 @@ static const struct alc_fixup alc269_fixups[] = {
}
},
[ALC269_FIXUP_SKU_IGNORE] = {
- .sku = ALC_FIXUP_SKU_IGNORE,
+ .type = ALC_FIXUP_SKU,
+ .v.sku = ALC_FIXUP_SKU_IGNORE,
},
[ALC269_FIXUP_ASUS_G73JW] = {
- .pins = (const struct alc_pincfg[]) {
+ .type = ALC_FIXUP_PINS,
+ .v.pins = (const struct alc_pincfg[]) {
{ 0x17, 0x99130111 }, /* subwoofer */
{ }
}
},
[ALC269_FIXUP_LENOVO_EAPD] = {
- .verbs = (const struct hda_verb[]) {
+ .type = ALC_FIXUP_VERBS,
+ .v.verbs = (const struct hda_verb[]) {
{0x14, AC_VERB_SET_EAPD_BTLENABLE, 0},
{}
}
},
[ALC275_FIXUP_SONY_HWEQ] = {
- .func = alc269_fixup_hweq,
- .verbs = (const struct hda_verb[]) {
- {0x01, AC_VERB_SET_GPIO_MASK, 0x04},
- {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x04},
- {0x01, AC_VERB_SET_GPIO_DATA, 0x00},
- {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREFGRD},
- { }
- }
+ .type = ALC_FIXUP_FUNC,
+ .v.func = alc269_fixup_hweq,
+ .chained = true,
+ .chain_id = ALC275_FIXUP_SONY_VAIO_GPIO2
}
};
static struct snd_pci_quirk alc269_fixup_tbl[] = {
- SND_PCI_QUIRK(0x104d, 0x9073, "Sony VAIO", ALC275_FIX_SONY_VAIO_GPIO2),
+ SND_PCI_QUIRK(0x104d, 0x9073, "Sony VAIO", ALC275_FIXUP_SONY_VAIO_GPIO2),
SND_PCI_QUIRK(0x104d, 0x907b, "Sony VAIO", ALC275_FIXUP_SONY_HWEQ),
SND_PCI_QUIRK(0x104d, 0x9084, "Sony VAIO", ALC275_FIXUP_SONY_HWEQ),
SND_PCI_QUIRK_VENDOR(0x104d, "Sony VAIO", ALC269_FIXUP_SONY_VAIO),
SND_PCI_QUIRK(0x1028, 0x0470, "Dell M101z", ALC269_FIXUP_DELL_M101Z),
SND_PCI_QUIRK(0x17aa, 0x21b8, "Thinkpad Edge 14", ALC269_FIXUP_SKU_IGNORE),
+ SND_PCI_QUIRK(0x17aa, 0x21e9, "Thinkpad Edge 14", ALC269_FIXUP_SKU_IGNORE),
SND_PCI_QUIRK(0x17aa, 0x20f2, "Thinkpad SL410/510", ALC269_FIXUP_SKU_IGNORE),
SND_PCI_QUIRK(0x1043, 0x1a13, "Asus G73Jw", ALC269_FIXUP_ASUS_G73JW),
SND_PCI_QUIRK(0x17aa, 0x9e54, "LENOVO NB", ALC269_FIXUP_LENOVO_EAPD),
@@ -14908,7 +14966,7 @@ static struct snd_pci_quirk alc269_fixup_tbl[] = {
/*
* configuration and preset
*/
-static const char *alc269_models[ALC269_MODEL_LAST] = {
+static const char * const alc269_models[ALC269_MODEL_LAST] = {
[ALC269_BASIC] = "basic",
[ALC269_QUANTA_FL1] = "quanta",
[ALC269_AMIC] = "laptop-amic",
@@ -15184,8 +15242,10 @@ static int patch_alc269(struct hda_codec *codec)
board_config = ALC269_AUTO;
}
- if (board_config == ALC269_AUTO)
- alc_pick_fixup(codec, alc269_fixup_tbl, alc269_fixups, 1);
+ if (board_config == ALC269_AUTO) {
+ alc_pick_fixup(codec, NULL, alc269_fixup_tbl, alc269_fixups);
+ alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
+ }
if (board_config == ALC269_AUTO) {
/* automatic parse from the BIOS config */
@@ -15246,8 +15306,7 @@ static int patch_alc269(struct hda_codec *codec)
if (has_cdefine_beep(codec))
set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT);
- if (board_config == ALC269_AUTO)
- alc_pick_fixup(codec, alc269_fixup_tbl, alc269_fixups, 0);
+ alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
spec->vmaster_nid = 0x02;
@@ -15950,7 +16009,7 @@ static int alc861_auto_create_multi_out_ctls(struct hda_codec *codec,
const struct auto_pin_cfg *cfg)
{
struct alc_spec *spec = codec->spec;
- static const char *chname[4] = {
+ static const char * const chname[4] = {
"Front", "Surround", NULL /*CLFE*/, "Side"
};
const char *pfx = alc_get_line_out_pfx(cfg, true);
@@ -16156,7 +16215,7 @@ static struct hda_amp_list alc861_loopbacks[] = {
/*
* configuration and preset
*/
-static const char *alc861_models[ALC861_MODEL_LAST] = {
+static const char * const alc861_models[ALC861_MODEL_LAST] = {
[ALC861_3ST] = "3stack",
[ALC660_3ST] = "3stack-660",
[ALC861_3ST_DIG] = "3stack-dig",
@@ -16306,7 +16365,8 @@ enum {
static const struct alc_fixup alc861_fixups[] = {
[PINFIX_FSC_AMILO_PI1505] = {
- .pins = (const struct alc_pincfg[]) {
+ .type = ALC_FIXUP_PINS,
+ .v.pins = (const struct alc_pincfg[]) {
{ 0x0b, 0x0221101f }, /* HP */
{ 0x0f, 0x90170310 }, /* speaker */
{ }
@@ -16341,8 +16401,10 @@ static int patch_alc861(struct hda_codec *codec)
board_config = ALC861_AUTO;
}
- if (board_config == ALC861_AUTO)
- alc_pick_fixup(codec, alc861_fixup_tbl, alc861_fixups, 1);
+ if (board_config == ALC861_AUTO) {
+ alc_pick_fixup(codec, NULL, alc861_fixup_tbl, alc861_fixups);
+ alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
+ }
if (board_config == ALC861_AUTO) {
/* automatic parse from the BIOS config */
@@ -16379,8 +16441,7 @@ static int patch_alc861(struct hda_codec *codec)
spec->vmaster_nid = 0x03;
- if (board_config == ALC861_AUTO)
- alc_pick_fixup(codec, alc861_fixup_tbl, alc861_fixups, 0);
+ alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
codec->patch_ops = alc_patch_ops;
if (board_config == ALC861_AUTO) {
@@ -16857,7 +16918,7 @@ static void alc861vd_dallas_setup(struct hda_codec *codec)
/*
* configuration and preset
*/
-static const char *alc861vd_models[ALC861VD_MODEL_LAST] = {
+static const char * const alc861vd_models[ALC861VD_MODEL_LAST] = {
[ALC660VD_3ST] = "3stack-660",
[ALC660VD_3ST_DIG] = "3stack-660-digout",
[ALC660VD_ASUS_V1S] = "asus-v1s",
@@ -17072,12 +17133,14 @@ static void alc861vd_auto_init_analog_input(struct hda_codec *codec)
#define alc861vd_idx_to_mixer_switch(nid) ((nid) + 0x0c)
/* add playback controls from the parsed DAC table */
-/* Based on ALC880 version. But ALC861VD and ALC887 have separate,
+/* Based on ALC880 version. But ALC861VD has separate,
* different NIDs for mute/unmute switch and volume control */
static int alc861vd_auto_create_multi_out_ctls(struct alc_spec *spec,
const struct auto_pin_cfg *cfg)
{
- static const char *chname[4] = {"Front", "Surround", "CLFE", "Side"};
+ static const char * const chname[4] = {
+ "Front", "Surround", "CLFE", "Side"
+ };
const char *pfx = alc_get_line_out_pfx(cfg, true);
hda_nid_t nid_v, nid_s;
int i, err;
@@ -17262,7 +17325,8 @@ enum {
/* reset GPIO1 */
static const struct alc_fixup alc861vd_fixups[] = {
[ALC660VD_FIX_ASUS_GPIO1] = {
- .verbs = (const struct hda_verb[]) {
+ .type = ALC_FIXUP_VERBS,
+ .v.verbs = (const struct hda_verb[]) {
{0x01, AC_VERB_SET_GPIO_MASK, 0x03},
{0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
{0x01, AC_VERB_SET_GPIO_DATA, 0x01},
@@ -17297,8 +17361,10 @@ static int patch_alc861vd(struct hda_codec *codec)
board_config = ALC861VD_AUTO;
}
- if (board_config == ALC861VD_AUTO)
- alc_pick_fixup(codec, alc861vd_fixup_tbl, alc861vd_fixups, 1);
+ if (board_config == ALC861VD_AUTO) {
+ alc_pick_fixup(codec, NULL, alc861vd_fixup_tbl, alc861vd_fixups);
+ alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
+ }
if (board_config == ALC861VD_AUTO) {
/* automatic parse from the BIOS config */
@@ -17346,8 +17412,7 @@ static int patch_alc861vd(struct hda_codec *codec)
spec->vmaster_nid = 0x02;
- if (board_config == ALC861VD_AUTO)
- alc_pick_fixup(codec, alc861vd_fixup_tbl, alc861vd_fixups, 0);
+ alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
codec->patch_ops = alc_patch_ops;
@@ -18630,7 +18695,7 @@ static struct snd_kcontrol_new alc272_nc10_mixer[] = {
/*
* configuration and preset
*/
-static const char *alc662_models[ALC662_MODEL_LAST] = {
+static const char * const alc662_models[ALC662_MODEL_LAST] = {
[ALC662_3ST_2ch_DIG] = "3stack-dig",
[ALC662_3ST_6ch_DIG] = "3stack-6ch-dig",
[ALC662_3ST_6ch] = "3stack-6ch",
@@ -19145,7 +19210,7 @@ static int alc662_auto_create_multi_out_ctls(struct hda_codec *codec,
const struct auto_pin_cfg *cfg)
{
struct alc_spec *spec = codec->spec;
- static const char *chname[4] = {
+ static const char * const chname[4] = {
"Front", "Surround", NULL /*CLFE*/, "Side"
};
const char *pfx = alc_get_line_out_pfx(cfg, true);
@@ -19378,7 +19443,10 @@ static void alc662_auto_init(struct hda_codec *codec)
}
static void alc272_fixup_mario(struct hda_codec *codec,
- const struct alc_fixup *fix, int pre_init) {
+ const struct alc_fixup *fix, int action)
+{
+ if (action != ALC_FIXUP_ACT_PROBE)
+ return;
if (snd_hda_override_amp_caps(codec, 0x2, HDA_OUTPUT,
(0x3b << AC_AMPCAP_OFFSET_SHIFT) |
(0x3b << AC_AMPCAP_NUM_STEPS_SHIFT) |
@@ -19392,24 +19460,35 @@ enum {
ALC662_FIXUP_ASPIRE,
ALC662_FIXUP_IDEAPAD,
ALC272_FIXUP_MARIO,
+ ALC662_FIXUP_CZC_P10T,
};
static const struct alc_fixup alc662_fixups[] = {
[ALC662_FIXUP_ASPIRE] = {
- .pins = (const struct alc_pincfg[]) {
+ .type = ALC_FIXUP_PINS,
+ .v.pins = (const struct alc_pincfg[]) {
{ 0x15, 0x99130112 }, /* subwoofer */
{ }
}
},
[ALC662_FIXUP_IDEAPAD] = {
- .pins = (const struct alc_pincfg[]) {
+ .type = ALC_FIXUP_PINS,
+ .v.pins = (const struct alc_pincfg[]) {
{ 0x17, 0x99130112 }, /* subwoofer */
{ }
}
},
[ALC272_FIXUP_MARIO] = {
- .func = alc272_fixup_mario,
- }
+ .type = ALC_FIXUP_FUNC,
+ .v.func = alc272_fixup_mario,
+ },
+ [ALC662_FIXUP_CZC_P10T] = {
+ .type = ALC_FIXUP_VERBS,
+ .v.verbs = (const struct hda_verb[]) {
+ {0x14, AC_VERB_SET_EAPD_BTLENABLE, 0},
+ {}
+ }
+ },
};
static struct snd_pci_quirk alc662_fixup_tbl[] = {
@@ -19417,6 +19496,7 @@ static struct snd_pci_quirk alc662_fixup_tbl[] = {
SND_PCI_QUIRK(0x144d, 0xc051, "Samsung R720", ALC662_FIXUP_IDEAPAD),
SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo Ideapad Y550P", ALC662_FIXUP_IDEAPAD),
SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo Ideapad Y550", ALC662_FIXUP_IDEAPAD),
+ SND_PCI_QUIRK(0x1b35, 0x2206, "CZC P10T", ALC662_FIXUP_CZC_P10T),
{}
};
@@ -19462,7 +19542,9 @@ static int patch_alc662(struct hda_codec *codec)
}
if (board_config == ALC662_AUTO) {
- alc_pick_fixup(codec, alc662_fixup_tbl, alc662_fixups, 1);
+ alc_pick_fixup(codec, alc662_fixup_models,
+ alc662_fixup_tbl, alc662_fixups);
+ alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
/* automatic parse from the BIOS config */
err = alc662_parse_auto_config(codec);
if (err < 0) {
@@ -19520,12 +19602,11 @@ static int patch_alc662(struct hda_codec *codec)
}
spec->vmaster_nid = 0x02;
+ alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
+
codec->patch_ops = alc_patch_ops;
- if (board_config == ALC662_AUTO) {
+ if (board_config == ALC662_AUTO)
spec->init_hook = alc662_auto_init;
- alc_pick_fixup_model(codec, alc662_fixup_models,
- alc662_fixup_tbl, alc662_fixups, 0);
- }
alc_init_jacks(codec);
@@ -19913,7 +19994,7 @@ static void alc680_auto_init(struct hda_codec *codec)
/*
* configuration and preset
*/
-static const char *alc680_models[ALC680_MODEL_LAST] = {
+static const char * const alc680_models[ALC680_MODEL_LAST] = {
[ALC680_BASE] = "base",
[ALC680_AUTO] = "auto",
};
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c
index 4ab019d..9ea48b4 100644
--- a/sound/pci/hda/patch_sigmatel.c
+++ b/sound/pci/hda/patch_sigmatel.c
@@ -266,7 +266,7 @@ struct sigmatel_spec {
struct sigmatel_mic_route int_mic;
struct sigmatel_mic_route dock_mic;
- const char **spdif_labels;
+ const char * const *spdif_labels;
hda_nid_t dig_in_nid;
hda_nid_t mono_nid;
@@ -524,7 +524,7 @@ static unsigned long stac927x_capsws[] = {
HDA_COMPOSE_AMP_VAL(0x1d, 3, 0, HDA_OUTPUT),
};
-static const char *stac927x_spdif_labels[5] = {
+static const char * const stac927x_spdif_labels[5] = {
"Digital Playback", "ADAT", "Analog Mux 1",
"Analog Mux 2", "Analog Mux 3"
};
@@ -1062,7 +1062,7 @@ static struct snd_kcontrol_new stac_smux_mixer = {
.put = stac92xx_smux_enum_put,
};
-static const char *slave_vols[] = {
+static const char * const slave_vols[] = {
"Front Playback Volume",
"Surround Playback Volume",
"Center Playback Volume",
@@ -1073,7 +1073,7 @@ static const char *slave_vols[] = {
NULL
};
-static const char *slave_sws[] = {
+static const char * const slave_sws[] = {
"Front Playback Switch",
"Surround Playback Switch",
"Center Playback Switch",
@@ -1354,7 +1354,7 @@ static unsigned int *stac9200_brd_tbl[STAC_9200_MODELS] = {
[STAC_9200_PANASONIC] = ref9200_pin_configs,
};
-static const char *stac9200_models[STAC_9200_MODELS] = {
+static const char * const stac9200_models[STAC_9200_MODELS] = {
[STAC_AUTO] = "auto",
[STAC_REF] = "ref",
[STAC_9200_OQO] = "oqo",
@@ -1500,7 +1500,7 @@ static unsigned int *stac925x_brd_tbl[STAC_925x_MODELS] = {
[STAC_M6] = stac925xM6_pin_configs,
};
-static const char *stac925x_models[STAC_925x_MODELS] = {
+static const char * const stac925x_models[STAC_925x_MODELS] = {
[STAC_925x_AUTO] = "auto",
[STAC_REF] = "ref",
[STAC_M1] = "m1",
@@ -1574,7 +1574,7 @@ static unsigned int *stac92hd73xx_brd_tbl[STAC_92HD73XX_MODELS] = {
[STAC_92HD73XX_INTEL] = intel_dg45id_pin_configs,
};
-static const char *stac92hd73xx_models[STAC_92HD73XX_MODELS] = {
+static const char * const stac92hd73xx_models[STAC_92HD73XX_MODELS] = {
[STAC_92HD73XX_AUTO] = "auto",
[STAC_92HD73XX_NO_JD] = "no-jd",
[STAC_92HD73XX_REF] = "ref",
@@ -1660,7 +1660,7 @@ static unsigned int *stac92hd83xxx_brd_tbl[STAC_92HD83XXX_MODELS] = {
[STAC_HP_DV7_4000] = hp_dv7_4000_pin_configs,
};
-static const char *stac92hd83xxx_models[STAC_92HD83XXX_MODELS] = {
+static const char * const stac92hd83xxx_models[STAC_92HD83XXX_MODELS] = {
[STAC_92HD83XXX_AUTO] = "auto",
[STAC_92HD83XXX_REF] = "ref",
[STAC_92HD83XXX_PWR_REF] = "mic-ref",
@@ -1722,7 +1722,7 @@ static unsigned int *stac92hd71bxx_brd_tbl[STAC_92HD71BXX_MODELS] = {
[STAC_HP_DV4_1222NR] = NULL,
};
-static const char *stac92hd71bxx_models[STAC_92HD71BXX_MODELS] = {
+static const char * const stac92hd71bxx_models[STAC_92HD71BXX_MODELS] = {
[STAC_92HD71BXX_AUTO] = "auto",
[STAC_92HD71BXX_REF] = "ref",
[STAC_DELL_M4_1] = "dell-m4-1",
@@ -1915,7 +1915,7 @@ static unsigned int *stac922x_brd_tbl[STAC_922X_MODELS] = {
[STAC_922X_DELL_M82] = dell_922x_m82_pin_configs,
};
-static const char *stac922x_models[STAC_922X_MODELS] = {
+static const char * const stac922x_models[STAC_922X_MODELS] = {
[STAC_922X_AUTO] = "auto",
[STAC_D945_REF] = "ref",
[STAC_D945GTP5] = "5stack",
@@ -2077,7 +2077,7 @@ static unsigned int *stac927x_brd_tbl[STAC_927X_MODELS] = {
[STAC_927X_VOLKNOB] = NULL,
};
-static const char *stac927x_models[STAC_927X_MODELS] = {
+static const char * const stac927x_models[STAC_927X_MODELS] = {
[STAC_927X_AUTO] = "auto",
[STAC_D965_REF_NO_JD] = "ref-no-jd",
[STAC_D965_REF] = "ref",
@@ -2180,7 +2180,7 @@ static unsigned int *stac9205_brd_tbl[STAC_9205_MODELS] = {
[STAC_9205_EAPD] = NULL,
};
-static const char *stac9205_models[STAC_9205_MODELS] = {
+static const char * const stac9205_models[STAC_9205_MODELS] = {
[STAC_9205_AUTO] = "auto",
[STAC_9205_REF] = "ref",
[STAC_9205_DELL_M42] = "dell-m42",
@@ -3123,7 +3123,7 @@ static int create_multi_out_ctls(struct hda_codec *codec, int num_outs,
int type)
{
struct sigmatel_spec *spec = codec->spec;
- static const char *chname[4] = {
+ static const char * const chname[4] = {
"Front", "Surround", NULL /*CLFE*/, "Side"
};
hda_nid_t nid;
@@ -3256,7 +3256,7 @@ static int stac92xx_auto_create_hp_ctls(struct hda_codec *codec,
}
/* labels for mono mux outputs */
-static const char *stac92xx_mono_labels[4] = {
+static const char * const stac92xx_mono_labels[4] = {
"DAC0", "DAC1", "Mixer", "DAC2"
};
@@ -3380,7 +3380,7 @@ static int stac92xx_auto_create_mux_input_ctls(struct hda_codec *codec)
return 0;
};
-static const char *stac92xx_spdif_labels[3] = {
+static const char * const stac92xx_spdif_labels[3] = {
"Digital Playback", "Analog Mux 1", "Analog Mux 2",
};
@@ -3388,7 +3388,7 @@ static int stac92xx_auto_create_spdif_mux_ctls(struct hda_codec *codec)
{
struct sigmatel_spec *spec = codec->spec;
struct hda_input_mux *spdif_mux = &spec->private_smux;
- const char **labels = spec->spdif_labels;
+ const char * const *labels = spec->spdif_labels;
int i, num_cons;
hda_nid_t con_lst[HDA_MAX_NUM_INPUTS];
@@ -3409,7 +3409,7 @@ static int stac92xx_auto_create_spdif_mux_ctls(struct hda_codec *codec)
}
/* labels for dmic mux inputs */
-static const char *stac92xx_dmic_labels[5] = {
+static const char * const stac92xx_dmic_labels[5] = {
"Analog Inputs", "Digital Mic 1", "Digital Mic 2",
"Digital Mic 3", "Digital Mic 4"
};
@@ -5333,7 +5333,7 @@ again:
return 0;
}
-static int stac92hd83xxx_set_system_btl_amp(struct hda_codec *codec)
+static int hp_bnb2011_with_dock(struct hda_codec *codec)
{
if (codec->vendor_id != 0x111d7605 &&
codec->vendor_id != 0x111d76d1)
@@ -5348,10 +5348,6 @@ static int stac92hd83xxx_set_system_btl_amp(struct hda_codec *codec)
case 0x103c161d:
case 0x103c161e:
case 0x103c161f:
- case 0x103c1620:
- case 0x103c1621:
- case 0x103c1622:
- case 0x103c1623:
case 0x103c162a:
case 0x103c162b:
@@ -5360,41 +5356,9 @@ static int stac92hd83xxx_set_system_btl_amp(struct hda_codec *codec)
case 0x103c1631:
case 0x103c1633:
-
+ case 0x103c1634:
case 0x103c1635:
- case 0x103c164f:
-
- case 0x103c1676:
- case 0x103c1677:
- case 0x103c1678:
- case 0x103c1679:
- case 0x103c167a:
- case 0x103c167b:
- case 0x103c167c:
- case 0x103c167d:
- case 0x103c167e:
- case 0x103c167f:
- case 0x103c1680:
- case 0x103c1681:
- case 0x103c1682:
- case 0x103c1683:
- case 0x103c1684:
- case 0x103c1685:
- case 0x103c1686:
- case 0x103c1687:
- case 0x103c1688:
- case 0x103c1689:
- case 0x103c168a:
- case 0x103c168b:
- case 0x103c168c:
- case 0x103c168d:
- case 0x103c168e:
- case 0x103c168f:
- case 0x103c1690:
- case 0x103c1691:
- case 0x103c1692:
-
case 0x103c3587:
case 0x103c3588:
case 0x103c3589:
@@ -5402,9 +5366,9 @@ static int stac92hd83xxx_set_system_btl_amp(struct hda_codec *codec)
case 0x103c3667:
case 0x103c3668:
- /* set BTL amp level to 13.43dB for louder speaker output */
- return snd_hda_codec_write_cache(codec, codec->afg, 0,
- 0x7F4, 0x14);
+ case 0x103c3669:
+
+ return 1;
}
return 0;
}
@@ -5420,6 +5384,11 @@ static int patch_stac92hd83xxx(struct hda_codec *codec)
if (spec == NULL)
return -ENOMEM;
+ if (hp_bnb2011_with_dock(codec)) {
+ snd_hda_codec_set_pincfg(codec, 0xa, 0x2101201f);
+ snd_hda_codec_set_pincfg(codec, 0xf, 0x2181205e);
+ }
+
/* reset pin power-down; Windows may leave these bits after reboot */
snd_hda_codec_write_cache(codec, codec->afg, 0, 0x7EC, 0);
snd_hda_codec_write_cache(codec, codec->afg, 0, 0x7ED, 0);
@@ -5546,8 +5515,6 @@ again:
AC_VERB_SET_CONNECT_SEL, num_dacs);
}
- stac92hd83xxx_set_system_btl_amp(codec);
-
codec->proc_widget_hook = stac92hd_proc_hook;
return 0;
@@ -6270,7 +6237,7 @@ static unsigned int stac9872_vaio_pin_configs[9] = {
0x90a7013e
};
-static const char *stac9872_models[STAC_9872_MODELS] = {
+static const char * const stac9872_models[STAC_9872_MODELS] = {
[STAC_9872_AUTO] = "auto",
[STAC_9872_VAIO] = "vaio",
};
diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c
index 7f4852a..a76c326 100644
--- a/sound/pci/hda/patch_via.c
+++ b/sound/pci/hda/patch_via.c
@@ -2281,7 +2281,9 @@ static int vt1708_auto_create_multi_out_ctls(struct via_spec *spec,
const struct auto_pin_cfg *cfg)
{
char name[32];
- static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" };
+ static const char * const chname[4] = {
+ "Front", "Surround", "C/LFE", "Side"
+ };
hda_nid_t nid, nid_vol, nid_vols[] = {0x17, 0x19, 0x1a, 0x1b};
int i, err;
@@ -2370,7 +2372,7 @@ static void create_hp_imux(struct via_spec *spec)
{
int i;
struct hda_input_mux *imux = &spec->private_imux[1];
- static const char *texts[] = { "OFF", "ON", NULL};
+ static const char * const texts[] = { "OFF", "ON", NULL};
/* for hp mode select */
for (i = 0; texts[i]; i++)
@@ -2890,7 +2892,9 @@ static int vt1709_auto_create_multi_out_ctls(struct via_spec *spec,
const struct auto_pin_cfg *cfg)
{
char name[32];
- static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" };
+ static const char * const chname[4] = {
+ "Front", "Surround", "C/LFE", "Side"
+ };
hda_nid_t nid, nid_vol, nid_vols[] = {0x18, 0x1a, 0x1b, 0x29};
int i, err;
@@ -3433,7 +3437,9 @@ static int vt1708B_auto_create_multi_out_ctls(struct via_spec *spec,
const struct auto_pin_cfg *cfg)
{
char name[32];
- static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" };
+ static const char * const chname[4] = {
+ "Front", "Surround", "C/LFE", "Side"
+ };
hda_nid_t nid_vols[] = {0x16, 0x18, 0x26, 0x27};
hda_nid_t nid, nid_vol = 0;
int i, err;
@@ -3861,7 +3867,9 @@ static int vt1708S_auto_create_multi_out_ctls(struct via_spec *spec,
const struct auto_pin_cfg *cfg)
{
char name[32];
- static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" };
+ static const char * const chname[4] = {
+ "Front", "Surround", "C/LFE", "Side"
+ };
hda_nid_t nid_vols[] = {0x10, 0x11, 0x24, 0x25};
hda_nid_t nid_mutes[] = {0x1C, 0x18, 0x26, 0x27};
hda_nid_t nid, nid_vol, nid_mute;
@@ -4304,7 +4312,7 @@ static int vt1702_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
{
int err, i;
struct hda_input_mux *imux;
- static const char *texts[] = { "ON", "OFF", NULL};
+ static const char * const texts[] = { "ON", "OFF", NULL};
if (!pin)
return 0;
spec->multiout.hp_nid = 0x1D;
@@ -4615,7 +4623,9 @@ static int vt1718S_auto_create_multi_out_ctls(struct via_spec *spec,
const struct auto_pin_cfg *cfg)
{
char name[32];
- static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" };
+ static const char * const chname[4] = {
+ "Front", "Surround", "C/LFE", "Side"
+ };
hda_nid_t nid_vols[] = {0x8, 0x9, 0xa, 0xb};
hda_nid_t nid_mutes[] = {0x24, 0x25, 0x26, 0x27};
hda_nid_t nid, nid_vol, nid_mute = 0;
@@ -5064,7 +5074,9 @@ static int vt1716S_auto_create_multi_out_ctls(struct via_spec *spec,
const struct auto_pin_cfg *cfg)
{
char name[32];
- static const char *chname[3] = { "Front", "Surround", "C/LFE" };
+ static const char * const chname[3] = {
+ "Front", "Surround", "C/LFE"
+ };
hda_nid_t nid_vols[] = {0x10, 0x11, 0x25};
hda_nid_t nid_mutes[] = {0x1C, 0x18, 0x27};
hda_nid_t nid, nid_vol, nid_mute;
diff --git a/sound/pci/ice1712/delta.c b/sound/pci/ice1712/delta.c
index 7b62de0..20c6b07 100644
--- a/sound/pci/ice1712/delta.c
+++ b/sound/pci/ice1712/delta.c
@@ -580,6 +580,7 @@ static int __devinit snd_ice1712_delta_init(struct snd_ice1712 *ice)
{
int err;
struct snd_akm4xxx *ak;
+ unsigned char tmp;
if (ice->eeprom.subvendor == ICE1712_SUBDEVICE_DELTA1010 &&
ice->eeprom.gpiodir == 0x7b)
@@ -622,6 +623,12 @@ static int __devinit snd_ice1712_delta_init(struct snd_ice1712 *ice)
break;
}
+ /* initialize the SPI clock to high */
+ tmp = snd_ice1712_read(ice, ICE1712_IREG_GPIO_DATA);
+ tmp |= ICE1712_DELTA_AP_CCLK;
+ snd_ice1712_write(ice, ICE1712_IREG_GPIO_DATA, tmp);
+ udelay(5);
+
/* initialize spdif */
switch (ice->eeprom.subvendor) {
case ICE1712_SUBDEVICE_AUDIOPHILE:
diff --git a/sound/pci/oxygen/xonar_dg.c b/sound/pci/oxygen/xonar_dg.c
index e4de0b8..e1fa602 100644
--- a/sound/pci/oxygen/xonar_dg.c
+++ b/sound/pci/oxygen/xonar_dg.c
@@ -75,7 +75,7 @@ static void cs4245_write(struct oxygen *chip, unsigned int reg, u8 value)
OXYGEN_SPI_CEN_LATCH_CLOCK_HI,
CS4245_SPI_ADDRESS |
CS4245_SPI_WRITE |
- (value << 8) | reg);
+ (reg << 8) | value);
data->cs4245_regs[reg] = value;
}
diff --git a/sound/soc/blackfin/Kconfig b/sound/soc/blackfin/Kconfig
index 3abeedd..ae40359 100644
--- a/sound/soc/blackfin/Kconfig
+++ b/sound/soc/blackfin/Kconfig
@@ -1,6 +1,7 @@
config SND_BF5XX_I2S
tristate "SoC I2S Audio for the ADI BF5xx chip"
depends on BLACKFIN
+ select SND_BF5XX_SOC_SPORT
help
Say Y or M if you want to add support for codecs attached to
the Blackfin SPORT (synchronous serial ports) interface in I2S
@@ -35,6 +36,7 @@ config SND_BFIN_AD73311_SE
config SND_BF5XX_TDM
tristate "SoC I2S(TDM mode) Audio for the ADI BF5xx chip"
depends on (BLACKFIN && SND_SOC)
+ select SND_BF5XX_SOC_SPORT
help
Say Y or M if you want to add support for codecs attached to
the Blackfin SPORT (synchronous serial ports) interface in TDM
@@ -61,6 +63,10 @@ config SND_BF5XX_SOC_AD193X
config SND_BF5XX_AC97
tristate "SoC AC97 Audio for the ADI BF5xx chip"
depends on BLACKFIN
+ select AC97_BUS
+ select SND_SOC_AC97_BUS
+ select SND_BF5XX_SOC_SPORT
+ select SND_BF5XX_SOC_AC97
help
Say Y or M if you want to add support for codecs attached to
the Blackfin SPORT (synchronous serial ports) interface in slot 16
@@ -122,17 +128,12 @@ config SND_BF5XX_SOC_SPORT
config SND_BF5XX_SOC_I2S
tristate
- select SND_BF5XX_SOC_SPORT
config SND_BF5XX_SOC_TDM
tristate
- select SND_BF5XX_SOC_SPORT
config SND_BF5XX_SOC_AC97
tristate
- select AC97_BUS
- select SND_SOC_AC97_BUS
- select SND_BF5XX_SOC_SPORT
config SND_BF5XX_SPORT_NUM
int "Set a SPORT for Sound chip"
diff --git a/sound/soc/blackfin/bf5xx-ac97.c b/sound/soc/blackfin/bf5xx-ac97.c
index c5f856ec..ffbac26 100644
--- a/sound/soc/blackfin/bf5xx-ac97.c
+++ b/sound/soc/blackfin/bf5xx-ac97.c
@@ -260,9 +260,9 @@ static int bf5xx_ac97_suspend(struct snd_soc_dai *dai)
pr_debug("%s : sport %d\n", __func__, dai->id);
if (!dai->active)
return 0;
- if (dai->capture.active)
+ if (dai->capture_active)
sport_rx_stop(sport);
- if (dai->playback.active)
+ if (dai->playback_active)
sport_tx_stop(sport);
return 0;
}
diff --git a/sound/soc/blackfin/bf5xx-tdm.c b/sound/soc/blackfin/bf5xx-tdm.c
index 1251239..5515ac9 100644
--- a/sound/soc/blackfin/bf5xx-tdm.c
+++ b/sound/soc/blackfin/bf5xx-tdm.c
@@ -210,7 +210,7 @@ static int bf5xx_tdm_set_channel_map(struct snd_soc_dai *dai,
#ifdef CONFIG_PM
static int bf5xx_tdm_suspend(struct snd_soc_dai *dai)
{
- struct sport_device *sport = dai->private_data;
+ struct sport_device *sport = snd_soc_dai_get_drvdata(dai);
if (!dai->active)
return 0;
@@ -235,13 +235,13 @@ static int bf5xx_tdm_resume(struct snd_soc_dai *dai)
ret = -EBUSY;
}
- ret = sport_config_rx(sport, IRFS, 0x1F, 0, 0);
+ ret = sport_config_rx(sport, 0, 0x1F, 0, 0);
if (ret) {
pr_err("SPORT is busy!\n");
ret = -EBUSY;
}
- ret = sport_config_tx(sport, ITFS, 0x1F, 0, 0);
+ ret = sport_config_tx(sport, 0, 0x1F, 0, 0);
if (ret) {
pr_err("SPORT is busy!\n");
ret = -EBUSY;
@@ -303,14 +303,14 @@ static int __devinit bfin_tdm_probe(struct platform_device *pdev)
goto sport_config_err;
}
- ret = sport_config_rx(sport_handle, IRFS, 0x1F, 0, 0);
+ ret = sport_config_rx(sport_handle, 0, 0x1F, 0, 0);
if (ret) {
pr_err("SPORT is busy!\n");
ret = -EBUSY;
goto sport_config_err;
}
- ret = sport_config_tx(sport_handle, ITFS, 0x1F, 0, 0);
+ ret = sport_config_tx(sport_handle, 0, 0x1F, 0, 0);
if (ret) {
pr_err("SPORT is busy!\n");
ret = -EBUSY;
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 883a312..c48b23c 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -44,7 +44,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_TWL6040 if TWL4030_CORE
select SND_SOC_UDA134X
select SND_SOC_UDA1380 if I2C
- select SND_SOC_WL1273 if WL1273_CORE
+ select SND_SOC_WL1273 if RADIO_WL1273
select SND_SOC_WM2000 if I2C
select SND_SOC_WM8350 if MFD_WM8350
select SND_SOC_WM8400 if MFD_WM8400
diff --git a/sound/soc/codecs/wl1273.c b/sound/soc/codecs/wl1273.c
index d3ffa2f..861b28f 100644
--- a/sound/soc/codecs/wl1273.c
+++ b/sound/soc/codecs/wl1273.c
@@ -42,7 +42,7 @@ struct wl1273_priv {
static int snd_wl1273_fm_set_i2s_mode(struct wl1273_core *core,
int rate, int width)
{
- struct device *dev = &core->i2c_dev->dev;
+ struct device *dev = &core->client->dev;
int r = 0;
u16 mode;
@@ -123,13 +123,13 @@ static int snd_wl1273_fm_set_i2s_mode(struct wl1273_core *core,
dev_dbg(dev, "mode: 0x%04x\n", mode);
if (core->i2s_mode != mode) {
- r = wl1273_fm_write_cmd(core, WL1273_I2S_MODE_CONFIG_SET, mode);
+ r = core->write(core, WL1273_I2S_MODE_CONFIG_SET, mode);
if (r)
goto out;
core->i2s_mode = mode;
- r = wl1273_fm_write_cmd(core, WL1273_AUDIO_ENABLE,
- WL1273_AUDIO_ENABLE_I2S);
+ r = core->write(core, WL1273_AUDIO_ENABLE,
+ WL1273_AUDIO_ENABLE_I2S);
if (r)
goto out;
}
@@ -142,8 +142,7 @@ out:
static int snd_wl1273_fm_set_channel_number(struct wl1273_core *core,
int channel_number)
{
- struct i2c_client *client = core->i2c_dev;
- struct device *dev = &client->dev;
+ struct device *dev = &core->client->dev;
int r = 0;
dev_dbg(dev, "%s\n", __func__);
@@ -154,17 +153,13 @@ static int snd_wl1273_fm_set_channel_number(struct wl1273_core *core,
goto out;
if (channel_number == 1 && core->mode == WL1273_MODE_RX)
- r = wl1273_fm_write_cmd(core, WL1273_MOST_MODE_SET,
- WL1273_RX_MONO);
+ r = core->write(core, WL1273_MOST_MODE_SET, WL1273_RX_MONO);
else if (channel_number == 1 && core->mode == WL1273_MODE_TX)
- r = wl1273_fm_write_cmd(core, WL1273_MONO_SET,
- WL1273_TX_MONO);
+ r = core->write(core, WL1273_MONO_SET, WL1273_TX_MONO);
else if (channel_number == 2 && core->mode == WL1273_MODE_RX)
- r = wl1273_fm_write_cmd(core, WL1273_MOST_MODE_SET,
- WL1273_RX_STEREO);
+ r = core->write(core, WL1273_MOST_MODE_SET, WL1273_RX_STEREO);
else if (channel_number == 2 && core->mode == WL1273_MODE_TX)
- r = wl1273_fm_write_cmd(core, WL1273_MONO_SET,
- WL1273_TX_STEREO);
+ r = core->write(core, WL1273_MONO_SET, WL1273_TX_STEREO);
else
r = -EINVAL;
out:
@@ -237,7 +232,7 @@ static int snd_wl1273_fm_audio_put(struct snd_kcontrol *kcontrol,
if (wl1273->core->audio_mode == val)
return 0;
- r = wl1273_fm_set_audio(wl1273->core, val);
+ r = wl1273->core->set_audio(wl1273->core, val);
if (r < 0)
return r;
@@ -272,8 +267,8 @@ static int snd_wl1273_fm_volume_put(struct snd_kcontrol *kcontrol,
dev_dbg(codec->dev, "%s: enter.\n", __func__);
- r = wl1273_fm_set_volume(wl1273->core,
- ucontrol->value.integer.value[0]);
+ r = wl1273->core->set_volume(wl1273->core,
+ ucontrol->value.integer.value[0]);
if (r)
return r;
diff --git a/sound/soc/codecs/wl1273.h b/sound/soc/codecs/wl1273.h
index 14ed027..43ec7e6 100644
--- a/sound/soc/codecs/wl1273.h
+++ b/sound/soc/codecs/wl1273.h
@@ -25,77 +25,6 @@
#ifndef __WL1273_CODEC_H__
#define __WL1273_CODEC_H__
-/* I2S protocol, left channel first, data width 16 bits */
-#define WL1273_PCM_DEF_MODE 0x00
-
-/* Rx */
-#define WL1273_AUDIO_ENABLE_I2S (1 << 0)
-#define WL1273_AUDIO_ENABLE_ANALOG (1 << 1)
-
-/* Tx */
-#define WL1273_AUDIO_IO_SET_ANALOG 0
-#define WL1273_AUDIO_IO_SET_I2S 1
-
-#define WL1273_POWER_SET_OFF 0
-#define WL1273_POWER_SET_FM (1 << 0)
-#define WL1273_POWER_SET_RDS (1 << 1)
-#define WL1273_POWER_SET_RETENTION (1 << 4)
-
-#define WL1273_PUPD_SET_OFF 0x00
-#define WL1273_PUPD_SET_ON 0x01
-#define WL1273_PUPD_SET_RETENTION 0x10
-
-/* I2S mode */
-#define WL1273_IS2_WIDTH_32 0x0
-#define WL1273_IS2_WIDTH_40 0x1
-#define WL1273_IS2_WIDTH_22_23 0x2
-#define WL1273_IS2_WIDTH_23_22 0x3
-#define WL1273_IS2_WIDTH_48 0x4
-#define WL1273_IS2_WIDTH_50 0x5
-#define WL1273_IS2_WIDTH_60 0x6
-#define WL1273_IS2_WIDTH_64 0x7
-#define WL1273_IS2_WIDTH_80 0x8
-#define WL1273_IS2_WIDTH_96 0x9
-#define WL1273_IS2_WIDTH_128 0xa
-#define WL1273_IS2_WIDTH 0xf
-
-#define WL1273_IS2_FORMAT_STD (0x0 << 4)
-#define WL1273_IS2_FORMAT_LEFT (0x1 << 4)
-#define WL1273_IS2_FORMAT_RIGHT (0x2 << 4)
-#define WL1273_IS2_FORMAT_USER (0x3 << 4)
-
-#define WL1273_IS2_MASTER (0x0 << 6)
-#define WL1273_IS2_SLAVEW (0x1 << 6)
-
-#define WL1273_IS2_TRI_AFTER_SENDING (0x0 << 7)
-#define WL1273_IS2_TRI_ALWAYS_ACTIVE (0x1 << 7)
-
-#define WL1273_IS2_SDOWS_RR (0x0 << 8)
-#define WL1273_IS2_SDOWS_RF (0x1 << 8)
-#define WL1273_IS2_SDOWS_FR (0x2 << 8)
-#define WL1273_IS2_SDOWS_FF (0x3 << 8)
-
-#define WL1273_IS2_TRI_OPT (0x0 << 10)
-#define WL1273_IS2_TRI_ALWAYS (0x1 << 10)
-
-#define WL1273_IS2_RATE_48K (0x0 << 12)
-#define WL1273_IS2_RATE_44_1K (0x1 << 12)
-#define WL1273_IS2_RATE_32K (0x2 << 12)
-#define WL1273_IS2_RATE_22_05K (0x4 << 12)
-#define WL1273_IS2_RATE_16K (0x5 << 12)
-#define WL1273_IS2_RATE_12K (0x8 << 12)
-#define WL1273_IS2_RATE_11_025 (0x9 << 12)
-#define WL1273_IS2_RATE_8K (0xa << 12)
-#define WL1273_IS2_RATE (0xf << 12)
-
-#define WL1273_I2S_DEF_MODE (WL1273_IS2_WIDTH_32 | \
- WL1273_IS2_FORMAT_STD | \
- WL1273_IS2_MASTER | \
- WL1273_IS2_TRI_AFTER_SENDING | \
- WL1273_IS2_SDOWS_RR | \
- WL1273_IS2_TRI_OPT | \
- WL1273_IS2_RATE_48K)
-
int wl1273_get_format(struct snd_soc_codec *codec, unsigned int *fmt);
#endif /* End of __WL1273_CODEC_H__ */
diff --git a/sound/soc/codecs/wm8990.c b/sound/soc/codecs/wm8990.c
index 5c87a63..100aeee 100644
--- a/sound/soc/codecs/wm8990.c
+++ b/sound/soc/codecs/wm8990.c
@@ -1183,7 +1183,7 @@ static int wm8990_set_bias_level(struct snd_soc_codec *codec,
WM8990_VMIDTOG);
/* Delay to allow output caps to discharge */
- msleep(msecs_to_jiffies(300));
+ msleep(300);
/* Disable VMIDTOG */
snd_soc_write(codec, WM8990_ANTIPOP2, WM8990_SOFTST |
@@ -1195,17 +1195,17 @@ static int wm8990_set_bias_level(struct snd_soc_codec *codec,
/* Enable outputs */
snd_soc_write(codec, WM8990_POWER_MANAGEMENT_1, 0x1b00);
- msleep(msecs_to_jiffies(50));
+ msleep(50);
/* Enable VMID at 2x50k */
snd_soc_write(codec, WM8990_POWER_MANAGEMENT_1, 0x1f02);
- msleep(msecs_to_jiffies(100));
+ msleep(100);
/* Enable VREF */
snd_soc_write(codec, WM8990_POWER_MANAGEMENT_1, 0x1f03);
- msleep(msecs_to_jiffies(600));
+ msleep(600);
/* Enable BUFIOEN */
snd_soc_write(codec, WM8990_ANTIPOP2, WM8990_SOFTST |
@@ -1250,7 +1250,7 @@ static int wm8990_set_bias_level(struct snd_soc_codec *codec,
/* Disable VMID */
snd_soc_write(codec, WM8990_POWER_MANAGEMENT_1, 0x1f01);
- msleep(msecs_to_jiffies(300));
+ msleep(300);
/* Enable all output discharge bits */
snd_soc_write(codec, WM8990_ANTIPOP1, WM8990_DIS_LLINE |
diff --git a/sound/soc/ep93xx/ep93xx-i2s.c b/sound/soc/ep93xx/ep93xx-i2s.c
index 9ac93f6..fff579a 100644
--- a/sound/soc/ep93xx/ep93xx-i2s.c
+++ b/sound/soc/ep93xx/ep93xx-i2s.c
@@ -267,14 +267,16 @@ static int ep93xx_i2s_hw_params(struct snd_pcm_substream *substream,
ep93xx_i2s_write_reg(info, EP93XX_I2S_RXWRDLEN, word_len);
/*
- * Calculate the sdiv (bit clock) and lrdiv (left/right clock) values.
- * If the lrclk is pulse length is larger than the word size, then the
- * bit clock will be gated for the unused bits.
+ * EP93xx I2S module can be setup so SCLK / LRCLK value can be
+ * 32, 64, 128. MCLK / SCLK value can be 2 and 4.
+ * We set LRCLK equal to `rate' and minimum SCLK / LRCLK
+ * value is 64, because our sample size is 32 bit * 2 channels.
+ * I2S standard permits us to transmit more bits than
+ * the codec uses.
*/
- div = (clk_get_rate(info->mclk) / params_rate(params)) *
- params_channels(params);
+ div = clk_get_rate(info->mclk) / params_rate(params);
for (sdiv = 2; sdiv <= 4; sdiv += 2)
- for (lrdiv = 32; lrdiv <= 128; lrdiv <<= 1)
+ for (lrdiv = 64; lrdiv <= 128; lrdiv <<= 1)
if (sdiv * lrdiv == div) {
found = 1;
goto out;
@@ -341,9 +343,7 @@ static struct snd_soc_dai_ops ep93xx_i2s_dai_ops = {
.set_fmt = ep93xx_i2s_set_dai_fmt,
};
-#define EP93XX_I2S_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
- SNDRV_PCM_FMTBIT_S24_LE | \
- SNDRV_PCM_FMTBIT_S32_LE)
+#define EP93XX_I2S_FORMATS (SNDRV_PCM_FMTBIT_S32_LE)
static struct snd_soc_dai_driver ep93xx_i2s_dai = {
.symmetric_rates= 1,
diff --git a/sound/soc/pxa/z2.c b/sound/soc/pxa/z2.c
index 2d4f896..3ceaef6 100644
--- a/sound/soc/pxa/z2.c
+++ b/sound/soc/pxa/z2.c
@@ -104,6 +104,7 @@ static struct snd_soc_jack_gpio hs_jack_gpios[] = {
.name = "hsdet-gpio",
.report = SND_JACK_HEADSET,
.debounce_time = 200,
+ .invert = 1,
},
};
@@ -192,7 +193,7 @@ static struct snd_soc_dai_link z2_dai = {
.cpu_dai_name = "pxa2xx-i2s",
.codec_dai_name = "wm8750-hifi",
.platform_name = "pxa-pcm-audio",
- .codec_name = "wm8750-codec.0-001a",
+ .codec_name = "wm8750-codec.0-001b",
.init = z2_wm8750_init,
.ops = &z2_ops,
};
diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt
index 52462ae..e032716 100644
--- a/tools/perf/Documentation/perf-record.txt
+++ b/tools/perf/Documentation/perf-record.txt
@@ -61,6 +61,9 @@ OPTIONS
-r::
--realtime=::
Collect data with this RT SCHED_FIFO priority.
+-D::
+--no-delay::
+ Collect data without buffering.
-A::
--append::
Append to the output file to do incremental profiling.
diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index 2b5387d..7141c42 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -204,13 +204,11 @@ EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wshadow
EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Winit-self
EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wpacked
EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wredundant-decls
-EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wstack-protector
EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wstrict-aliasing=3
EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wswitch-default
EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wswitch-enum
EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wno-system-headers
EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wundef
-EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wvolatile-register-var
EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wwrite-strings
EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wbad-function-cast
EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wmissing-declarations
@@ -294,6 +292,13 @@ ifeq ($(call try-cc,$(SOURCE_HELLO),-Werror -fstack-protector-all),y)
CFLAGS := $(CFLAGS) -fstack-protector-all
endif
+ifeq ($(call try-cc,$(SOURCE_HELLO),-Werror -Wstack-protector),y)
+ CFLAGS := $(CFLAGS) -Wstack-protector
+endif
+
+ifeq ($(call try-cc,$(SOURCE_HELLO),-Werror -Wvolatile-register-var),y)
+ CFLAGS := $(CFLAGS) -Wvolatile-register-var
+endif
### --- END CONFIGURATION SECTION ---
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c
index c056cdc..8879463 100644
--- a/tools/perf/builtin-annotate.c
+++ b/tools/perf/builtin-annotate.c
@@ -212,7 +212,7 @@ get_source_line(struct hist_entry *he, int len, const char *filename)
continue;
offset = start + i;
- sprintf(cmd, "addr2line -e %s %016llx", filename, offset);
+ sprintf(cmd, "addr2line -e %s %016" PRIx64, filename, offset);
fp = popen(cmd, "r");
if (!fp)
continue;
@@ -270,9 +270,9 @@ static void hist_entry__print_hits(struct hist_entry *self)
for (offset = 0; offset < len; ++offset)
if (h->ip[offset] != 0)
- printf("%*Lx: %Lu\n", BITS_PER_LONG / 2,
+ printf("%*" PRIx64 ": %" PRIu64 "\n", BITS_PER_LONG / 2,
sym->start + offset, h->ip[offset]);
- printf("%*s: %Lu\n", BITS_PER_LONG / 2, "h->sum", h->sum);
+ printf("%*s: %" PRIu64 "\n", BITS_PER_LONG / 2, "h->sum", h->sum);
}
static int hist_entry__tty_annotate(struct hist_entry *he)
diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c
index def7ddc..d97256d 100644
--- a/tools/perf/builtin-kmem.c
+++ b/tools/perf/builtin-kmem.c
@@ -371,10 +371,10 @@ static void __print_result(struct rb_root *root, struct perf_session *session,
addr = data->ptr;
if (sym != NULL)
- snprintf(buf, sizeof(buf), "%s+%Lx", sym->name,
+ snprintf(buf, sizeof(buf), "%s+%" PRIx64 "", sym->name,
addr - map->unmap_ip(map, sym->start));
else
- snprintf(buf, sizeof(buf), "%#Lx", addr);
+ snprintf(buf, sizeof(buf), "%#" PRIx64 "", addr);
printf(" %-34s |", buf);
printf(" %9llu/%-5lu | %9llu/%-5lu | %8lu | %8lu | %6.3f%%\n",
diff --git a/tools/perf/builtin-lock.c b/tools/perf/builtin-lock.c
index b9c6e54..2b36def 100644
--- a/tools/perf/builtin-lock.c
+++ b/tools/perf/builtin-lock.c
@@ -782,9 +782,9 @@ static void print_result(void)
pr_info("%10u ", st->nr_acquired);
pr_info("%10u ", st->nr_contended);
- pr_info("%15llu ", st->wait_time_total);
- pr_info("%15llu ", st->wait_time_max);
- pr_info("%15llu ", st->wait_time_min == ULLONG_MAX ?
+ pr_info("%15" PRIu64 " ", st->wait_time_total);
+ pr_info("%15" PRIu64 " ", st->wait_time_max);
+ pr_info("%15" PRIu64 " ", st->wait_time_min == ULLONG_MAX ?
0 : st->wait_time_min);
pr_info("\n");
}
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 7069bd3..b2f729f 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -49,6 +49,7 @@ static int pipe_output = 0;
static const char *output_name = "perf.data";
static int group = 0;
static int realtime_prio = 0;
+static bool nodelay = false;
static bool raw_samples = false;
static bool sample_id_all_avail = true;
static bool system_wide = false;
@@ -307,6 +308,11 @@ static void create_counter(struct perf_evsel *evsel, int cpu)
attr->sample_type |= PERF_SAMPLE_CPU;
}
+ if (nodelay) {
+ attr->watermark = 0;
+ attr->wakeup_events = 1;
+ }
+
attr->mmap = track;
attr->comm = track;
attr->inherit = !no_inherit;
@@ -331,9 +337,6 @@ try_again:
else if (err == ENODEV && cpu_list) {
die("No such device - did you specify"
" an out-of-range profile CPU?\n");
- } else if (err == ENOENT) {
- die("%s event is not supported. ",
- event_name(evsel));
} else if (err == EINVAL && sample_id_all_avail) {
/*
* Old kernel, no attr->sample_id_type_all field
@@ -480,6 +483,7 @@ static void atexit_header(void)
process_buildids();
perf_header__write(&session->header, output, true);
perf_session__delete(session);
+ perf_evsel_list__delete();
symbol__exit();
}
}
@@ -813,7 +817,7 @@ static int __cmd_record(int argc, const char **argv)
* Approximate RIP event size: 24 bytes.
*/
fprintf(stderr,
- "[ perf record: Captured and wrote %.3f MB %s (~%lld samples) ]\n",
+ "[ perf record: Captured and wrote %.3f MB %s (~%" PRIu64 " samples) ]\n",
(double)bytes_written / 1024.0 / 1024.0,
output_name,
bytes_written / 24);
@@ -845,6 +849,8 @@ const struct option record_options[] = {
"record events on existing thread id"),
OPT_INTEGER('r', "realtime", &realtime_prio,
"collect data with this RT SCHED_FIFO priority"),
+ OPT_BOOLEAN('D', "no-delay", &nodelay,
+ "collect data without buffering"),
OPT_BOOLEAN('R', "raw-samples", &raw_samples,
"collect raw sample records from all opened counters"),
OPT_BOOLEAN('a', "all-cpus", &system_wide,
@@ -930,6 +936,8 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
list_for_each_entry(pos, &evsel_list, node) {
if (perf_evsel__alloc_fd(pos, cpus->nr, threads->nr) < 0)
goto out_free_fd;
+ if (perf_header__push_event(pos->attr.config, event_name(pos)))
+ goto out_free_fd;
}
event_array = malloc((sizeof(struct pollfd) * MAX_NR_CPUS *
MAX_COUNTERS * threads->nr));
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 75183a4..c27e31f 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -197,7 +197,7 @@ static int process_read_event(event_t *event, struct sample_data *sample __used,
event->read.value);
}
- dump_printf(": %d %d %s %Lu\n", event->read.pid, event->read.tid,
+ dump_printf(": %d %d %s %" PRIu64 "\n", event->read.pid, event->read.tid,
attr ? __event_name(attr->type, attr->config) : "FAIL",
event->read.value);
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c
index abd4b84..29acb894 100644
--- a/tools/perf/builtin-sched.c
+++ b/tools/perf/builtin-sched.c
@@ -193,7 +193,7 @@ static void calibrate_run_measurement_overhead(void)
}
run_measurement_overhead = min_delta;
- printf("run measurement overhead: %Ld nsecs\n", min_delta);
+ printf("run measurement overhead: %" PRIu64 " nsecs\n", min_delta);
}
static void calibrate_sleep_measurement_overhead(void)
@@ -211,7 +211,7 @@ static void calibrate_sleep_measurement_overhead(void)
min_delta -= 10000;
sleep_measurement_overhead = min_delta;
- printf("sleep measurement overhead: %Ld nsecs\n", min_delta);
+ printf("sleep measurement overhead: %" PRIu64 " nsecs\n", min_delta);
}
static struct sched_atom *
@@ -617,13 +617,13 @@ static void test_calibrations(void)
burn_nsecs(1e6);
T1 = get_nsecs();
- printf("the run test took %Ld nsecs\n", T1-T0);
+ printf("the run test took %" PRIu64 " nsecs\n", T1 - T0);
T0 = get_nsecs();
sleep_nsecs(1e6);
T1 = get_nsecs();
- printf("the sleep test took %Ld nsecs\n", T1-T0);
+ printf("the sleep test took %" PRIu64 " nsecs\n", T1 - T0);
}
#define FILL_FIELD(ptr, field, event, data) \
@@ -816,10 +816,10 @@ replay_switch_event(struct trace_switch_event *switch_event,
delta = 0;
if (delta < 0)
- die("hm, delta: %Ld < 0 ?\n", delta);
+ die("hm, delta: %" PRIu64 " < 0 ?\n", delta);
if (verbose) {
- printf(" ... switch from %s/%d to %s/%d [ran %Ld nsecs]\n",
+ printf(" ... switch from %s/%d to %s/%d [ran %" PRIu64 " nsecs]\n",
switch_event->prev_comm, switch_event->prev_pid,
switch_event->next_comm, switch_event->next_pid,
delta);
@@ -1048,7 +1048,7 @@ latency_switch_event(struct trace_switch_event *switch_event,
delta = 0;
if (delta < 0)
- die("hm, delta: %Ld < 0 ?\n", delta);
+ die("hm, delta: %" PRIu64 " < 0 ?\n", delta);
sched_out = perf_session__findnew(session, switch_event->prev_pid);
@@ -1221,7 +1221,7 @@ static void output_lat_thread(struct work_atoms *work_list)
avg = work_list->total_lat / work_list->nb_atoms;
- printf("|%11.3f ms |%9llu | avg:%9.3f ms | max:%9.3f ms | max at: %9.6f s\n",
+ printf("|%11.3f ms |%9" PRIu64 " | avg:%9.3f ms | max:%9.3f ms | max at: %9.6f s\n",
(double)work_list->total_runtime / 1e6,
work_list->nb_atoms, (double)avg / 1e6,
(double)work_list->max_lat / 1e6,
@@ -1423,7 +1423,7 @@ map_switch_event(struct trace_switch_event *switch_event,
delta = 0;
if (delta < 0)
- die("hm, delta: %Ld < 0 ?\n", delta);
+ die("hm, delta: %" PRIu64 " < 0 ?\n", delta);
sched_out = perf_session__findnew(session, switch_event->prev_pid);
@@ -1713,7 +1713,7 @@ static void __cmd_lat(void)
}
printf(" -----------------------------------------------------------------------------------------\n");
- printf(" TOTAL: |%11.3f ms |%9Ld |\n",
+ printf(" TOTAL: |%11.3f ms |%9" PRIu64 " |\n",
(double)all_runtime/1e6, all_count);
printf(" ---------------------------------------------------\n");
@@ -1843,15 +1843,15 @@ static const char *record_args[] = {
"-f",
"-m", "1024",
"-c", "1",
- "-e", "sched:sched_switch:r",
- "-e", "sched:sched_stat_wait:r",
- "-e", "sched:sched_stat_sleep:r",
- "-e", "sched:sched_stat_iowait:r",
- "-e", "sched:sched_stat_runtime:r",
- "-e", "sched:sched_process_exit:r",
- "-e", "sched:sched_process_fork:r",
- "-e", "sched:sched_wakeup:r",
- "-e", "sched:sched_migrate_task:r",
+ "-e", "sched:sched_switch",
+ "-e", "sched:sched_stat_wait",
+ "-e", "sched:sched_stat_sleep",
+ "-e", "sched:sched_stat_iowait",
+ "-e", "sched:sched_stat_runtime",
+ "-e", "sched:sched_process_exit",
+ "-e", "sched:sched_process_fork",
+ "-e", "sched:sched_wakeup",
+ "-e", "sched:sched_migrate_task",
};
static int __cmd_record(int argc, const char **argv)
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
index 150a606..b766c2a 100644
--- a/tools/perf/builtin-script.c
+++ b/tools/perf/builtin-script.c
@@ -77,8 +77,8 @@ static int process_sample_event(event_t *event, struct sample_data *sample,
if (session->sample_type & PERF_SAMPLE_RAW) {
if (debug_mode) {
if (sample->time < last_timestamp) {
- pr_err("Samples misordered, previous: %llu "
- "this: %llu\n", last_timestamp,
+ pr_err("Samples misordered, previous: %" PRIu64
+ " this: %" PRIu64 "\n", last_timestamp,
sample->time);
nr_unordered++;
}
@@ -126,7 +126,7 @@ static int __cmd_script(struct perf_session *session)
ret = perf_session__process_events(session, &event_ops);
if (debug_mode)
- pr_err("Misordered timestamps: %llu\n", nr_unordered);
+ pr_err("Misordered timestamps: %" PRIu64 "\n", nr_unordered);
return ret;
}
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index c385a63..a482a19 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -206,8 +206,8 @@ static int read_counter_aggr(struct perf_evsel *counter)
update_stats(&ps->res_stats[i], count[i]);
if (verbose) {
- fprintf(stderr, "%s: %Ld %Ld %Ld\n", event_name(counter),
- count[0], count[1], count[2]);
+ fprintf(stderr, "%s: %" PRIu64 " %" PRIu64 " %" PRIu64 "\n",
+ event_name(counter), count[0], count[1], count[2]);
}
/*
@@ -743,6 +743,7 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used)
out_free_fd:
list_for_each_entry(pos, &evsel_list, node)
perf_evsel__free_stat_priv(pos);
+ perf_evsel_list__delete();
out:
thread_map__delete(threads);
threads = NULL;
diff --git a/tools/perf/builtin-test.c b/tools/perf/builtin-test.c
index ed56961..5dcdba6 100644
--- a/tools/perf/builtin-test.c
+++ b/tools/perf/builtin-test.c
@@ -146,7 +146,7 @@ next_pair:
if (llabs(skew) < page_size)
continue;
- pr_debug("%#Lx: diff end addr for %s v: %#Lx k: %#Lx\n",
+ pr_debug("%#" PRIx64 ": diff end addr for %s v: %#" PRIx64 " k: %#" PRIx64 "\n",
sym->start, sym->name, sym->end, pair->end);
} else {
struct rb_node *nnd;
@@ -168,11 +168,11 @@ detour:
goto detour;
}
- pr_debug("%#Lx: diff name v: %s k: %s\n",
+ pr_debug("%#" PRIx64 ": diff name v: %s k: %s\n",
sym->start, sym->name, pair->name);
}
} else
- pr_debug("%#Lx: %s not on kallsyms\n", sym->start, sym->name);
+ pr_debug("%#" PRIx64 ": %s not on kallsyms\n", sym->start, sym->name);
err = -1;
}
@@ -211,10 +211,10 @@ detour:
if (pair->start == pos->start) {
pair->priv = 1;
- pr_info(" %Lx-%Lx %Lx %s in kallsyms as",
+ pr_info(" %" PRIx64 "-%" PRIx64 " %" PRIx64 " %s in kallsyms as",
pos->start, pos->end, pos->pgoff, pos->dso->name);
if (pos->pgoff != pair->pgoff || pos->end != pair->end)
- pr_info(": \n*%Lx-%Lx %Lx",
+ pr_info(": \n*%" PRIx64 "-%" PRIx64 " %" PRIx64 "",
pair->start, pair->end, pair->pgoff);
pr_info(" %s\n", pair->dso->name);
pair->priv = 1;
@@ -307,7 +307,7 @@ static int test__open_syscall_event(void)
}
if (evsel->counts->cpu[0].val != nr_open_calls) {
- pr_debug("perf_evsel__read_on_cpu: expected to intercept %d calls, got %Ld\n",
+ pr_debug("perf_evsel__read_on_cpu: expected to intercept %d calls, got %" PRIu64 "\n",
nr_open_calls, evsel->counts->cpu[0].val);
goto out_close_fd;
}
@@ -332,8 +332,7 @@ static int test__open_syscall_event_on_all_cpus(void)
struct perf_evsel *evsel;
struct perf_event_attr attr;
unsigned int nr_open_calls = 111, i;
- cpu_set_t *cpu_set;
- size_t cpu_set_size;
+ cpu_set_t cpu_set;
int id = trace_event__id("sys_enter_open");
if (id < 0) {
@@ -353,13 +352,8 @@ static int test__open_syscall_event_on_all_cpus(void)
return -1;
}
- cpu_set = CPU_ALLOC(cpus->nr);
- if (cpu_set == NULL)
- goto out_thread_map_delete;
-
- cpu_set_size = CPU_ALLOC_SIZE(cpus->nr);
- CPU_ZERO_S(cpu_set_size, cpu_set);
+ CPU_ZERO(&cpu_set);
memset(&attr, 0, sizeof(attr));
attr.type = PERF_TYPE_TRACEPOINT;
@@ -367,7 +361,7 @@ static int test__open_syscall_event_on_all_cpus(void)
evsel = perf_evsel__new(&attr, 0);
if (evsel == NULL) {
pr_debug("perf_evsel__new\n");
- goto out_cpu_free;
+ goto out_thread_map_delete;
}
if (perf_evsel__open(evsel, cpus, threads) < 0) {
@@ -379,14 +373,29 @@ static int test__open_syscall_event_on_all_cpus(void)
for (cpu = 0; cpu < cpus->nr; ++cpu) {
unsigned int ncalls = nr_open_calls + cpu;
+ /*
+ * XXX eventually lift this restriction in a way that
+ * keeps perf building on older glibc installations
+ * without CPU_ALLOC. 1024 cpus in 2010 still seems
+ * a reasonable upper limit tho :-)
+ */
+ if (cpus->map[cpu] >= CPU_SETSIZE) {
+ pr_debug("Ignoring CPU %d\n", cpus->map[cpu]);
+ continue;
+ }
- CPU_SET(cpu, cpu_set);
- sched_setaffinity(0, cpu_set_size, cpu_set);
+ CPU_SET(cpus->map[cpu], &cpu_set);
+ if (sched_setaffinity(0, sizeof(cpu_set), &cpu_set) < 0) {
+ pr_debug("sched_setaffinity() failed on CPU %d: %s ",
+ cpus->map[cpu],
+ strerror(errno));
+ goto out_close_fd;
+ }
for (i = 0; i < ncalls; ++i) {
fd = open("/etc/passwd", O_RDONLY);
close(fd);
}
- CPU_CLR(cpu, cpu_set);
+ CPU_CLR(cpus->map[cpu], &cpu_set);
}
/*
@@ -402,6 +411,9 @@ static int test__open_syscall_event_on_all_cpus(void)
for (cpu = 0; cpu < cpus->nr; ++cpu) {
unsigned int expected;
+ if (cpus->map[cpu] >= CPU_SETSIZE)
+ continue;
+
if (perf_evsel__read_on_cpu(evsel, cpu, 0) < 0) {
pr_debug("perf_evsel__open_read_on_cpu\n");
goto out_close_fd;
@@ -409,8 +421,8 @@ static int test__open_syscall_event_on_all_cpus(void)
expected = nr_open_calls + cpu;
if (evsel->counts->cpu[cpu].val != expected) {
- pr_debug("perf_evsel__read_on_cpu: expected to intercept %d calls on cpu %d, got %Ld\n",
- expected, cpu, evsel->counts->cpu[cpu].val);
+ pr_debug("perf_evsel__read_on_cpu: expected to intercept %d calls on cpu %d, got %" PRIu64 "\n",
+ expected, cpus->map[cpu], evsel->counts->cpu[cpu].val);
goto out_close_fd;
}
}
@@ -420,8 +432,6 @@ out_close_fd:
perf_evsel__close_fd(evsel, 1, threads->nr);
out_evsel_delete:
perf_evsel__delete(evsel);
-out_cpu_free:
- CPU_FREE(cpu_set);
out_thread_map_delete:
thread_map__delete(threads);
return err;
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index 6ce4042..b6998e0 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -40,6 +40,7 @@
#include <stdio.h>
#include <termios.h>
#include <unistd.h>
+#include <inttypes.h>
#include <errno.h>
#include <time.h>
@@ -214,7 +215,7 @@ static int parse_source(struct sym_entry *syme)
len = sym->end - sym->start;
sprintf(command,
- "objdump --start-address=%#0*Lx --stop-address=%#0*Lx -dS %s",
+ "objdump --start-address=%#0*" PRIx64 " --stop-address=%#0*" PRIx64 " -dS %s",
BITS_PER_LONG / 4, map__rip_2objdump(map, sym->start),
BITS_PER_LONG / 4, map__rip_2objdump(map, sym->end), path);
@@ -308,7 +309,7 @@ static void lookup_sym_source(struct sym_entry *syme)
struct source_line *line;
char pattern[PATTERN_LEN + 1];
- sprintf(pattern, "%0*Lx <", BITS_PER_LONG / 4,
+ sprintf(pattern, "%0*" PRIx64 " <", BITS_PER_LONG / 4,
map__rip_2objdump(syme->map, symbol->start));
pthread_mutex_lock(&syme->src->lock);
@@ -537,7 +538,7 @@ static void print_sym_table(void)
if (nr_counters == 1 || !display_weighted) {
struct perf_evsel *first;
first = list_entry(evsel_list.next, struct perf_evsel, node);
- printf("%Ld", first->attr.sample_period);
+ printf("%" PRIu64, (uint64_t)first->attr.sample_period);
if (freq)
printf("Hz ");
else
@@ -640,7 +641,7 @@ static void print_sym_table(void)
percent_color_fprintf(stdout, "%4.1f%%", pcnt);
if (verbose)
- printf(" %016llx", sym->start);
+ printf(" %016" PRIx64, sym->start);
printf(" %-*.*s", sym_width, sym_width, sym->name);
printf(" %-*.*s\n", dso_width, dso_width,
dso_width >= syme->map->dso->long_name_len ?
@@ -1247,8 +1248,6 @@ try_again:
die("Permission error - are you root?\n"
"\t Consider tweaking"
" /proc/sys/kernel/perf_event_paranoid.\n");
- if (err == ENOENT)
- die("%s event is not supported. ", event_name(evsel));
/*
* If it's cycles then fall back to hrtimer
* based cpu-clock-tick sw counter, which
@@ -1473,6 +1472,8 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
pos->attr.sample_period = default_interval;
}
+ sym_evsel = list_entry(evsel_list.next, struct perf_evsel, node);
+
symbol_conf.priv_size = (sizeof(struct sym_entry) +
(nr_counters + 1) * sizeof(unsigned long));
@@ -1490,6 +1491,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
out_free_fd:
list_for_each_entry(pos, &evsel_list, node)
perf_evsel__free_mmap(pos);
+ perf_evsel_list__delete();
return status;
}
diff --git a/tools/perf/perf.c b/tools/perf/perf.c
index 5b1ecd6..595d0f4 100644
--- a/tools/perf/perf.c
+++ b/tools/perf/perf.c
@@ -286,8 +286,6 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv)
status = p->fn(argc, argv, prefix);
exit_browser(status);
- perf_evsel_list__delete();
-
if (status)
return status & 0xff;
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index 2302ec0..1478ab4 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -459,7 +459,8 @@ int event__process_comm(event_t *self, struct sample_data *sample __used,
int event__process_lost(event_t *self, struct sample_data *sample __used,
struct perf_session *session)
{
- dump_printf(": id:%Ld: lost:%Ld\n", self->lost.id, self->lost.lost);
+ dump_printf(": id:%" PRIu64 ": lost:%" PRIu64 "\n",
+ self->lost.id, self->lost.lost);
session->hists.stats.total_lost += self->lost.lost;
return 0;
}
@@ -575,7 +576,7 @@ int event__process_mmap(event_t *self, struct sample_data *sample __used,
u8 cpumode = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
int ret = 0;
- dump_printf(" %d/%d: [%#Lx(%#Lx) @ %#Lx]: %s\n",
+ dump_printf(" %d/%d: [%#" PRIx64 "(%#" PRIx64 ") @ %#" PRIx64 "]: %s\n",
self->mmap.pid, self->mmap.tid, self->mmap.start,
self->mmap.len, self->mmap.pgoff, self->mmap.filename);
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index 989fa2d..f6a929e 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -798,8 +798,8 @@ static int perf_file_section__process(struct perf_file_section *self,
int feat, int fd)
{
if (lseek(fd, self->offset, SEEK_SET) == (off_t)-1) {
- pr_debug("Failed to lseek to %Ld offset for feature %d, "
- "continuing...\n", self->offset, feat);
+ pr_debug("Failed to lseek to %" PRIu64 " offset for feature "
+ "%d, continuing...\n", self->offset, feat);
return 0;
}
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index c749ba6..32f4f1f 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -636,13 +636,13 @@ int hist_entry__snprintf(struct hist_entry *self, char *s, size_t size,
}
}
} else
- ret = snprintf(s, size, sep ? "%lld" : "%12lld ", period);
+ ret = snprintf(s, size, sep ? "%" PRIu64 : "%12" PRIu64 " ", period);
if (symbol_conf.show_nr_samples) {
if (sep)
- ret += snprintf(s + ret, size - ret, "%c%lld", *sep, period);
+ ret += snprintf(s + ret, size - ret, "%c%" PRIu64, *sep, period);
else
- ret += snprintf(s + ret, size - ret, "%11lld", period);
+ ret += snprintf(s + ret, size - ret, "%11" PRIu64, period);
}
if (pair_hists) {
@@ -971,7 +971,7 @@ int hist_entry__inc_addr_samples(struct hist_entry *self, u64 ip)
sym_size = sym->end - sym->start;
offset = ip - sym->start;
- pr_debug3("%s: ip=%#Lx\n", __func__, self->ms.map->unmap_ip(self->ms.map, ip));
+ pr_debug3("%s: ip=%#" PRIx64 "\n", __func__, self->ms.map->unmap_ip(self->ms.map, ip));
if (offset >= sym_size)
return 0;
@@ -980,8 +980,9 @@ int hist_entry__inc_addr_samples(struct hist_entry *self, u64 ip)
h->sum++;
h->ip[offset]++;
- pr_debug3("%#Lx %s: period++ [ip: %#Lx, %#Lx] => %Ld\n", self->ms.sym->start,
- self->ms.sym->name, ip, ip - self->ms.sym->start, h->ip[offset]);
+ pr_debug3("%#" PRIx64 " %s: period++ [ip: %#" PRIx64 ", %#" PRIx64
+ "] => %" PRIu64 "\n", self->ms.sym->start, self->ms.sym->name,
+ ip, ip - self->ms.sym->start, h->ip[offset]);
return 0;
}
@@ -1132,7 +1133,7 @@ fallback:
goto out_free_filename;
}
- pr_debug("%s: filename=%s, sym=%s, start=%#Lx, end=%#Lx\n", __func__,
+ pr_debug("%s: filename=%s, sym=%s, start=%#" PRIx64 ", end=%#" PRIx64 "\n", __func__,
filename, sym->name, map->unmap_ip(map, sym->start),
map->unmap_ip(map, sym->end));
@@ -1142,7 +1143,7 @@ fallback:
dso, dso->long_name, sym, sym->name);
snprintf(command, sizeof(command),
- "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS -C %s|grep -v %s|expand",
+ "objdump --start-address=0x%016" PRIx64 " --stop-address=0x%016" PRIx64 " -dS -C %s|grep -v %s|expand",
map__rip_2objdump(map, sym->start),
map__rip_2objdump(map, sym->end),
symfs_filename, filename);
diff --git a/tools/perf/util/include/linux/bitops.h b/tools/perf/util/include/linux/bitops.h
index 8be0b96..305c848 100644
--- a/tools/perf/util/include/linux/bitops.h
+++ b/tools/perf/util/include/linux/bitops.h
@@ -2,6 +2,7 @@
#define _PERF_LINUX_BITOPS_H_
#include <linux/kernel.h>
+#include <linux/compiler.h>
#include <asm/hweight.h>
#define BITS_PER_LONG __WORDSIZE
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c
index 3a7eb6e..a16ecab 100644
--- a/tools/perf/util/map.c
+++ b/tools/perf/util/map.c
@@ -1,5 +1,6 @@
#include "symbol.h"
#include <errno.h>
+#include <inttypes.h>
#include <limits.h>
#include <stdlib.h>
#include <string.h>
@@ -195,7 +196,7 @@ int map__overlap(struct map *l, struct map *r)
size_t map__fprintf(struct map *self, FILE *fp)
{
- return fprintf(fp, " %Lx-%Lx %Lx %s\n",
+ return fprintf(fp, " %" PRIx64 "-%" PRIx64 " %" PRIx64 " %s\n",
self->start, self->end, self->pgoff, self->dso->name);
}
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 5cb6f4b..135f69b 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -279,7 +279,7 @@ const char *__event_name(int type, u64 config)
static char buf[32];
if (type == PERF_TYPE_RAW) {
- sprintf(buf, "raw 0x%llx", config);
+ sprintf(buf, "raw 0x%" PRIx64, config);
return buf;
}
@@ -490,32 +490,6 @@ parse_multiple_tracepoint_event(char *sys_name, const char *evt_exp,
return EVT_HANDLED_ALL;
}
-static int store_event_type(const char *orgname)
-{
- char filename[PATH_MAX], *c;
- FILE *file;
- int id, n;
-
- sprintf(filename, "%s/", debugfs_path);
- strncat(filename, orgname, strlen(orgname));
- strcat(filename, "/id");
-
- c = strchr(filename, ':');
- if (c)
- *c = '/';
-
- file = fopen(filename, "r");
- if (!file)
- return 0;
- n = fscanf(file, "%i", &id);
- fclose(file);
- if (n < 1) {
- pr_err("cannot store event ID\n");
- return -EINVAL;
- }
- return perf_header__push_event(id, orgname);
-}
-
static enum event_result parse_tracepoint_event(const char **strp,
struct perf_event_attr *attr)
{
@@ -555,13 +529,10 @@ static enum event_result parse_tracepoint_event(const char **strp,
if (evt_length >= MAX_EVENT_LENGTH)
return EVT_FAILED;
if (strpbrk(evt_name, "*?")) {
- *strp += strlen(sys_name) + evt_length;
+ *strp += strlen(sys_name) + evt_length + 1; /* 1 == the ':' */
return parse_multiple_tracepoint_event(sys_name, evt_name,
flags);
} else {
- if (store_event_type(evt_name) < 0)
- return EVT_FAILED;
-
return parse_single_tracepoint_event(sys_name, evt_name,
evt_length, attr, strp);
}
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index b82cafb..458e3ec 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -23,7 +23,7 @@ struct tracepoint_path {
};
extern struct tracepoint_path *tracepoint_id_to_path(u64 config);
-extern bool have_tracepoints(struct list_head *evsel_list);
+extern bool have_tracepoints(struct list_head *evlist);
extern int nr_counters;
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 128aaab..6e29d9c 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -172,7 +172,7 @@ static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp,
sym = __find_kernel_function_by_name(tp->symbol, &map);
if (sym) {
addr = map->unmap_ip(map, sym->start + tp->offset);
- pr_debug("try to find %s+%ld@%llx\n", tp->symbol,
+ pr_debug("try to find %s+%ld@%" PRIx64 "\n", tp->symbol,
tp->offset, addr);
ret = find_perf_probe_point((unsigned long)addr, pp);
}
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index 313dac2..105f00b 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -652,10 +652,11 @@ static void callchain__printf(struct sample_data *sample)
{
unsigned int i;
- printf("... chain: nr:%Lu\n", sample->callchain->nr);
+ printf("... chain: nr:%" PRIu64 "\n", sample->callchain->nr);
for (i = 0; i < sample->callchain->nr; i++)
- printf("..... %2d: %016Lx\n", i, sample->callchain->ips[i]);
+ printf("..... %2d: %016" PRIx64 "\n",
+ i, sample->callchain->ips[i]);
}
static void perf_session__print_tstamp(struct perf_session *session,
@@ -672,7 +673,7 @@ static void perf_session__print_tstamp(struct perf_session *session,
printf("%u ", sample->cpu);
if (session->sample_type & PERF_SAMPLE_TIME)
- printf("%Lu ", sample->time);
+ printf("%" PRIu64 " ", sample->time);
}
static void dump_event(struct perf_session *session, event_t *event,
@@ -681,16 +682,16 @@ static void dump_event(struct perf_session *session, event_t *event,
if (!dump_trace)
return;
- printf("\n%#Lx [%#x]: event: %d\n", file_offset, event->header.size,
- event->header.type);
+ printf("\n%#" PRIx64 " [%#x]: event: %d\n",
+ file_offset, event->header.size, event->header.type);
trace_event(event);
if (sample)
perf_session__print_tstamp(session, event, sample);
- printf("%#Lx [%#x]: PERF_RECORD_%s", file_offset, event->header.size,
- event__get_event_name(event->header.type));
+ printf("%#" PRIx64 " [%#x]: PERF_RECORD_%s", file_offset,
+ event->header.size, event__get_event_name(event->header.type));
}
static void dump_sample(struct perf_session *session, event_t *event,
@@ -699,8 +700,9 @@ static void dump_sample(struct perf_session *session, event_t *event,
if (!dump_trace)
return;
- printf("(IP, %d): %d/%d: %#Lx period: %Ld\n", event->header.misc,
- sample->pid, sample->tid, sample->ip, sample->period);
+ printf("(IP, %d): %d/%d: %#" PRIx64 " period: %" PRIu64 "\n",
+ event->header.misc, sample->pid, sample->tid, sample->ip,
+ sample->period);
if (session->sample_type & PERF_SAMPLE_CALLCHAIN)
callchain__printf(sample);
@@ -843,8 +845,8 @@ static void perf_session__warn_about_errors(const struct perf_session *session,
{
if (ops->lost == event__process_lost &&
session->hists.stats.total_lost != 0) {
- ui__warning("Processed %Lu events and LOST %Lu!\n\n"
- "Check IO/CPU overload!\n\n",
+ ui__warning("Processed %" PRIu64 " events and LOST %" PRIu64
+ "!\n\nCheck IO/CPU overload!\n\n",
session->hists.stats.total_period,
session->hists.stats.total_lost);
}
@@ -918,7 +920,7 @@ more:
if (size == 0 ||
(skip = perf_session__process_event(self, &event, ops, head)) < 0) {
- dump_printf("%#Lx [%#x]: skipping unknown header type: %d\n",
+ dump_printf("%#" PRIx64 " [%#x]: skipping unknown header type: %d\n",
head, event.header.size, event.header.type);
/*
* assume we lost track of the stream, check alignment, and
@@ -1023,7 +1025,7 @@ more:
if (size == 0 ||
perf_session__process_event(session, event, ops, file_pos) < 0) {
- dump_printf("%#Lx [%#x]: skipping unknown header type: %d\n",
+ dump_printf("%#" PRIx64 " [%#x]: skipping unknown header type: %d\n",
file_offset + head, event->header.size,
event->header.type);
/*
diff --git a/tools/perf/util/svghelper.c b/tools/perf/util/svghelper.c
index b3637db..fb737fe 100644
--- a/tools/perf/util/svghelper.c
+++ b/tools/perf/util/svghelper.c
@@ -12,6 +12,7 @@
* of the License.
*/
+#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
@@ -43,11 +44,11 @@ static double cpu2y(int cpu)
return cpu2slot(cpu) * SLOT_MULT;
}
-static double time2pixels(u64 time)
+static double time2pixels(u64 __time)
{
double X;
- X = 1.0 * svg_page_width * (time - first_time) / (last_time - first_time);
+ X = 1.0 * svg_page_width * (__time - first_time) / (last_time - first_time);
return X;
}
@@ -94,7 +95,7 @@ void open_svg(const char *filename, int cpus, int rows, u64 start, u64 end)
total_height = (1 + rows + cpu2slot(cpus)) * SLOT_MULT;
fprintf(svgfile, "<?xml version=\"1.0\" standalone=\"no\"?> \n");
- fprintf(svgfile, "<svg width=\"%i\" height=\"%llu\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\">\n", svg_page_width, total_height);
+ fprintf(svgfile, "<svg width=\"%i\" height=\"%" PRIu64 "\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\">\n", svg_page_width, total_height);
fprintf(svgfile, "<defs>\n <style type=\"text/css\">\n <![CDATA[\n");
@@ -483,7 +484,7 @@ void svg_time_grid(void)
color = 128;
}
- fprintf(svgfile, "<line x1=\"%4.8f\" y1=\"%4.2f\" x2=\"%4.8f\" y2=\"%llu\" style=\"stroke:rgb(%i,%i,%i);stroke-width:%1.3f\"/>\n",
+ fprintf(svgfile, "<line x1=\"%4.8f\" y1=\"%4.2f\" x2=\"%4.8f\" y2=\"%" PRIu64 "\" style=\"stroke:rgb(%i,%i,%i);stroke-width:%1.3f\"/>\n",
time2pixels(i), SLOT_MULT/2, time2pixels(i), total_height, color, color, color, thickness);
i += 10000000;
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index 15ccfba..7821d0e 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -11,6 +11,7 @@
#include <sys/param.h>
#include <fcntl.h>
#include <unistd.h>
+#include <inttypes.h>
#include "build-id.h"
#include "debug.h"
#include "symbol.h"
@@ -153,7 +154,7 @@ static struct symbol *symbol__new(u64 start, u64 len, u8 binding,
self->binding = binding;
self->namelen = namelen - 1;
- pr_debug4("%s: %s %#Lx-%#Lx\n", __func__, name, start, self->end);
+ pr_debug4("%s: %s %#" PRIx64 "-%#" PRIx64 "\n", __func__, name, start, self->end);
memcpy(self->name, name, namelen);
@@ -167,7 +168,7 @@ void symbol__delete(struct symbol *self)
static size_t symbol__fprintf(struct symbol *self, FILE *fp)
{
- return fprintf(fp, " %llx-%llx %c %s\n",
+ return fprintf(fp, " %" PRIx64 "-%" PRIx64 " %c %s\n",
self->start, self->end,
self->binding == STB_GLOBAL ? 'g' :
self->binding == STB_LOCAL ? 'l' : 'w',
@@ -1161,6 +1162,13 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name,
section_name = elf_sec__name(&shdr, secstrs);
+ /* On ARM, symbols for thumb functions have 1 added to
+ * the symbol address as a flag - remove it */
+ if ((ehdr.e_machine == EM_ARM) &&
+ (map->type == MAP__FUNCTION) &&
+ (sym.st_value & 1))
+ --sym.st_value;
+
if (self->kernel != DSO_TYPE_USER || kmodule) {
char dso_name[PATH_MAX];
@@ -1208,8 +1216,8 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name,
}
if (curr_dso->adjust_symbols) {
- pr_debug4("%s: adjusting symbol: st_value: %#Lx "
- "sh_addr: %#Lx sh_offset: %#Lx\n", __func__,
+ pr_debug4("%s: adjusting symbol: st_value: %#" PRIx64 " "
+ "sh_addr: %#" PRIx64 " sh_offset: %#" PRIx64 "\n", __func__,
(u64)sym.st_value, (u64)shdr.sh_addr,
(u64)shdr.sh_offset);
sym.st_value -= shdr.sh_addr - shdr.sh_offset;
diff --git a/tools/perf/util/types.h b/tools/perf/util/types.h
index 7d6b833..5f3689a 100644
--- a/tools/perf/util/types.h
+++ b/tools/perf/util/types.h
@@ -1,12 +1,14 @@
#ifndef __PERF_TYPES_H
#define __PERF_TYPES_H
+#include <stdint.h>
+
/*
- * We define u64 as unsigned long long for every architecture
- * so that we can print it with %Lx without getting warnings.
+ * We define u64 as uint64_t for every architecture
+ * so that we can print it with "%"PRIx64 without getting warnings.
*/
-typedef unsigned long long u64;
-typedef signed long long s64;
+typedef uint64_t u64;
+typedef int64_t s64;
typedef unsigned int u32;
typedef signed int s32;
typedef unsigned short u16;
diff --git a/tools/perf/util/ui/browsers/hists.c b/tools/perf/util/ui/browsers/hists.c
index ebda8c3..60c463c 100644
--- a/tools/perf/util/ui/browsers/hists.c
+++ b/tools/perf/util/ui/browsers/hists.c
@@ -350,7 +350,7 @@ static char *callchain_list__sym_name(struct callchain_list *self,
if (self->ms.sym)
return self->ms.sym->name;
- snprintf(bf, bfsize, "%#Lx", self->ip);
+ snprintf(bf, bfsize, "%#" PRIx64, self->ip);
return bf;
}
diff --git a/tools/perf/util/ui/browsers/map.c b/tools/perf/util/ui/browsers/map.c
index e35437d..e515836 100644
--- a/tools/perf/util/ui/browsers/map.c
+++ b/tools/perf/util/ui/browsers/map.c
@@ -1,5 +1,6 @@
#include "../libslang.h"
#include <elf.h>
+#include <inttypes.h>
#include <sys/ttydefaults.h>
#include <ctype.h>
#include <string.h>
@@ -57,7 +58,7 @@ static void map_browser__write(struct ui_browser *self, void *nd, int row)
int width;
ui_browser__set_percent_color(self, 0, current_entry);
- slsmg_printf("%*llx %*llx %c ",
+ slsmg_printf("%*" PRIx64 " %*" PRIx64 " %c ",
mb->addrlen, sym->start, mb->addrlen, sym->end,
sym->binding == STB_GLOBAL ? 'g' :
sym->binding == STB_LOCAL ? 'l' : 'w');
@@ -150,6 +151,6 @@ int map__browse(struct map *self)
++mb.b.nr_entries;
}
- mb.addrlen = snprintf(tmp, sizeof(tmp), "%llx", maxaddr);
+ mb.addrlen = snprintf(tmp, sizeof(tmp), "%" PRIx64, maxaddr);
return map_browser__run(&mb);
}
diff --git a/tools/perf/util/values.c b/tools/perf/util/values.c
index cfa55d6..bdd3347 100644
--- a/tools/perf/util/values.c
+++ b/tools/perf/util/values.c
@@ -150,7 +150,7 @@ static void perf_read_values__display_pretty(FILE *fp,
if (width > tidwidth)
tidwidth = width;
for (j = 0; j < values->counters; j++) {
- width = snprintf(NULL, 0, "%Lu", values->value[i][j]);
+ width = snprintf(NULL, 0, "%" PRIu64, values->value[i][j]);
if (width > counterwidth[j])
counterwidth[j] = width;
}
@@ -165,7 +165,7 @@ static void perf_read_values__display_pretty(FILE *fp,
fprintf(fp, " %*d %*d", pidwidth, values->pid[i],
tidwidth, values->tid[i]);
for (j = 0; j < values->counters; j++)
- fprintf(fp, " %*Lu",
+ fprintf(fp, " %*" PRIu64,
counterwidth[j], values->value[i][j]);
fprintf(fp, "\n");
}
@@ -196,13 +196,13 @@ static void perf_read_values__display_raw(FILE *fp,
width = strlen(values->countername[j]);
if (width > namewidth)
namewidth = width;
- width = snprintf(NULL, 0, "%llx", values->counterrawid[j]);
+ width = snprintf(NULL, 0, "%" PRIx64, values->counterrawid[j]);
if (width > rawwidth)
rawwidth = width;
}
for (i = 0; i < values->threads; i++) {
for (j = 0; j < values->counters; j++) {
- width = snprintf(NULL, 0, "%Lu", values->value[i][j]);
+ width = snprintf(NULL, 0, "%" PRIu64, values->value[i][j]);
if (width > countwidth)
countwidth = width;
}
@@ -214,7 +214,7 @@ static void perf_read_values__display_raw(FILE *fp,
countwidth, "Count");
for (i = 0; i < values->threads; i++)
for (j = 0; j < values->counters; j++)
- fprintf(fp, " %*d %*d %*s %*llx %*Lu\n",
+ fprintf(fp, " %*d %*d %*s %*" PRIx64 " %*" PRIu64,
pidwidth, values->pid[i],
tidwidth, values->tid[i],
namewidth, values->countername[j],
diff --git a/usr/Kconfig b/usr/Kconfig
index 4780dea..65b845bd 100644
--- a/usr/Kconfig
+++ b/usr/Kconfig
@@ -46,7 +46,7 @@ config INITRAMFS_ROOT_GID
If you are not sure, leave it set to "0".
config RD_GZIP
- bool "Support initial ramdisks compressed using gzip" if EMBEDDED
+ bool "Support initial ramdisks compressed using gzip" if EXPERT
default y
depends on BLK_DEV_INITRD
select DECOMPRESS_GZIP
@@ -55,8 +55,8 @@ config RD_GZIP
If unsure, say Y.
config RD_BZIP2
- bool "Support initial ramdisks compressed using bzip2" if EMBEDDED
- default !EMBEDDED
+ bool "Support initial ramdisks compressed using bzip2" if EXPERT
+ default !EXPERT
depends on BLK_DEV_INITRD
select DECOMPRESS_BZIP2
help
@@ -64,8 +64,8 @@ config RD_BZIP2
If unsure, say N.
config RD_LZMA
- bool "Support initial ramdisks compressed using LZMA" if EMBEDDED
- default !EMBEDDED
+ bool "Support initial ramdisks compressed using LZMA" if EXPERT
+ default !EXPERT
depends on BLK_DEV_INITRD
select DECOMPRESS_LZMA
help
@@ -73,8 +73,8 @@ config RD_LZMA
If unsure, say N.
config RD_XZ
- bool "Support initial ramdisks compressed using XZ" if EMBEDDED
- default !EMBEDDED
+ bool "Support initial ramdisks compressed using XZ" if EXPERT
+ default !EXPERT
depends on BLK_DEV_INITRD
select DECOMPRESS_XZ
help
@@ -82,8 +82,8 @@ config RD_XZ
If unsure, say N.
config RD_LZO
- bool "Support initial ramdisks compressed using LZO" if EMBEDDED
- default !EMBEDDED
+ bool "Support initial ramdisks compressed using LZO" if EXPERT
+ default !EXPERT
depends on BLK_DEV_INITRD
select DECOMPRESS_LZO
help